diff options
author | John Stebbins <[email protected]> | 2015-10-19 13:14:04 -0700 |
---|---|---|
committer | John Stebbins <[email protected]> | 2015-10-19 13:14:04 -0700 |
commit | ba3d0e46199db21c1e4e899cc1d852ed0738d951 (patch) | |
tree | 51f18e3a0476f3256a27b5839e62c45b210c60cb /libhb/grayscale.c | |
parent | 8a01c54c5cfd7107a00ab8417af07e161ff97b56 (diff) | |
parent | 2e432bdd792739bb498313c36fce824f1debe278 (diff) |
Merge pull request #21 from jstebbins/grayscale
grayscale: make it a real filter
Diffstat (limited to 'libhb/grayscale.c')
-rw-r--r-- | libhb/grayscale.c | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/libhb/grayscale.c b/libhb/grayscale.c new file mode 100644 index 000000000..bdbf3b722 --- /dev/null +++ b/libhb/grayscale.c @@ -0,0 +1,257 @@ +/* grayscale.c + + Copyright (c) 2003-2015 HandBrake Team + This file is part of the HandBrake source code + Homepage: <http://handbrake.fr/>. + It may be used under the terms of the GNU General Public License v2. + For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html + */ + +#include "hb.h" +#include "hbffmpeg.h" +#include "taskset.h" + +// Settings: +// This filter has no settings. +// But at some point it might be interesting to add effects other than +// just gray. + +typedef struct grayscale_arguments_s { + hb_buffer_t *src; +} grayscale_arguments_t; + +struct hb_filter_private_s +{ + int cpu_count; + + taskset_t grayscale_taskset; // Threads - one per CPU + grayscale_arguments_t *grayscale_arguments; // Arguments to thread for work +}; + +static int hb_grayscale_init( hb_filter_object_t * filter, + hb_filter_init_t * init ); + +static int hb_grayscale_work( hb_filter_object_t * filter, + hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ); + +static void hb_grayscale_close( hb_filter_object_t * filter ); + +static int hb_grayscale_info( hb_filter_object_t * filter, + hb_filter_info_t * info ); + +hb_filter_object_t hb_filter_grayscale = +{ + .id = HB_FILTER_GRAYSCALE, + .enforce_order = 0, + .name = "Grayscale", + .settings = NULL, + .init = hb_grayscale_init, + .work = hb_grayscale_work, + .close = hb_grayscale_close, + .info = hb_grayscale_info +}; + + +typedef struct grayscale_thread_arg_s { + hb_filter_private_t *pv; + int segment; +} grayscale_thread_arg_t; + +/* + * gray this segment of all three planes in a single thread. + */ +void grayscale_filter_thread( void *thread_args_v ) +{ + grayscale_arguments_t *grayscale_work = NULL; + hb_filter_private_t * pv; + int run = 1; + int plane; + int segment, segment_start, segment_stop; + grayscale_thread_arg_t *thread_args = thread_args_v; + hb_buffer_t *src_buf; + + pv = thread_args->pv; + segment = thread_args->segment; + + hb_log("Grayscale thread started for segment %d", segment); + + while( run ) + { + /* + * Wait here until there is work to do. + */ + taskset_thread_wait4start( &pv->grayscale_taskset, segment ); + + if( taskset_thread_stop( &pv->grayscale_taskset, segment ) ) + { + /* + * No more work to do, exit this thread. + */ + run = 0; + goto report_completion; + } + + grayscale_work = &pv->grayscale_arguments[segment]; + if (grayscale_work->src == NULL) + { + hb_error( "Thread started when no work available" ); + hb_snooze(500); + goto report_completion; + } + + /* + * Process all three planes, but only this segment of it. + */ + src_buf = grayscale_work->src; + for (plane = 1; plane < 3; plane++) + { + int src_stride = src_buf->plane[plane].stride; + int height = src_buf->plane[plane].height; + segment_start = (height / pv->cpu_count) * segment; + if (segment == pv->cpu_count - 1) + { + /* + * Final segment + */ + segment_stop = height; + } else { + segment_stop = (height / pv->cpu_count) * (segment + 1); + } + + memset(&src_buf->plane[plane].data[segment_start * src_stride], + 0x80, (segment_stop - segment_start) * src_stride); + } + +report_completion: + /* + * Finished this segment, let everyone know. + */ + taskset_thread_complete( &pv->grayscale_taskset, segment ); + } +} + + +/* + * threaded gray - each thread grays a single segment of all + * three planes. Where a segment is defined as the frame divided by + * the number of CPUs. + * + * This function blocks until the frame is grayed. + */ +static void grayscale_filter( hb_filter_private_t * pv, + hb_buffer_t * in ) +{ + + int segment; + + for( segment = 0; segment < pv->cpu_count; segment++ ) + { + /* + * Setup the work for this plane. + */ + pv->grayscale_arguments[segment].src = in; + } + + /* + * Allow the taskset threads to make one pass over the data. + */ + taskset_cycle( &pv->grayscale_taskset ); + + /* + * Entire frame is now grayed. + */ +} + + +static int hb_grayscale_init( hb_filter_object_t * filter, + hb_filter_init_t * init ) +{ + filter->private_data = calloc( 1, sizeof(struct hb_filter_private_s) ); + hb_filter_private_t * pv = filter->private_data; + + pv->cpu_count = hb_get_cpu_count(); + + /* + * Create gray taskset. + */ + pv->grayscale_arguments = malloc(sizeof(grayscale_arguments_t) * + pv->cpu_count); + if (pv->grayscale_arguments == NULL || + taskset_init( &pv->grayscale_taskset, pv->cpu_count, + sizeof( grayscale_thread_arg_t ) ) == 0) + { + hb_error( "grayscale could not initialize taskset" ); + } + + int ii; + for (ii = 0; ii < pv->cpu_count; ii++) + { + grayscale_thread_arg_t *thread_args; + + thread_args = taskset_thread_args(&pv->grayscale_taskset, ii); + + thread_args->pv = pv; + thread_args->segment = ii; + pv->grayscale_arguments[ii].src = NULL; + + if (taskset_thread_spawn(&pv->grayscale_taskset, ii, + "grayscale_filter_segment", + grayscale_filter_thread, + HB_NORMAL_PRIORITY ) == 0) + { + hb_error( "grayscale could not spawn thread" ); + } + } + + return 0; +} + +static int hb_grayscale_info( hb_filter_object_t * filter, + hb_filter_info_t * info ) +{ + info->human_readable_desc[0] = 0; + return 0; +} + +static void hb_grayscale_close( hb_filter_object_t * filter ) +{ + hb_filter_private_t * pv = filter->private_data; + + if( !pv ) + { + return; + } + + taskset_fini( &pv->grayscale_taskset ); + + /* + * free memory for grayscale structs + */ + free( pv->grayscale_arguments ); + + free( pv ); + filter->private_data = NULL; +} + +static int hb_grayscale_work( hb_filter_object_t * filter, + hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ) +{ + hb_filter_private_t * pv = filter->private_data; + hb_buffer_t * in = *buf_in; + + *buf_in = NULL; + if (in->s.flags & HB_BUF_FLAG_EOF) + { + *buf_out = in; + return HB_FILTER_DONE; + } + + // Grayscale! + grayscale_filter(pv, in); + + *buf_out = in; + + return HB_FILTER_OK; +} |