summaryrefslogtreecommitdiffstats
path: root/libhb/deinterlace.c
diff options
context:
space:
mode:
Diffstat (limited to 'libhb/deinterlace.c')
-rw-r--r--libhb/deinterlace.c240
1 files changed, 198 insertions, 42 deletions
diff --git a/libhb/deinterlace.c b/libhb/deinterlace.c
index 09b92c437..69b1c31bc 100644
--- a/libhb/deinterlace.c
+++ b/libhb/deinterlace.c
@@ -40,6 +40,16 @@ typedef struct yadif_arguments_s {
int tff;
} yadif_arguments_t;
+typedef struct deint_arguments_s {
+ hb_buffer_t * src;
+ hb_buffer_t * dst;
+} deint_arguments_t;
+
+typedef struct deint_thread_arg_s {
+ hb_filter_private_t *pv;
+ int segment;
+} deint_thread_arg_t;
+
struct hb_filter_private_s
{
int width;
@@ -52,9 +62,14 @@ struct hb_filter_private_s
hb_buffer_t * yadif_ref[3];
int cpu_count;
+ int segments;
+
+ int deint_nsegs;
- taskset_t yadif_taskset; // Threads for Yadif - one per CPU
+ taskset_t deint_taskset; // Threads for fast deint
+ taskset_t yadif_taskset; // Threads for Yadif
+ deint_arguments_t *deint_arguments; // Arguments to thread for work
yadif_arguments_t *yadif_arguments; // Arguments to thread for work
};
@@ -192,17 +207,16 @@ void yadif_filter_thread( void *thread_args_v )
*/
run = 0;
goto report_completion;
- }
+ }
yadif_work = &pv->yadif_arguments[segment];
if( yadif_work->dst == 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.
*/
@@ -218,9 +232,9 @@ void yadif_filter_thread( void *thread_args_v )
int tff = yadif_work->tff;
int penultimate = h - 2;
- int segment_height = (h / pv->cpu_count) & ~1;
+ int segment_height = (h / pv->segments) & ~1;
segment_start = segment_height * segment;
- if( segment == pv->cpu_count - 1 )
+ if( segment == pv->segments - 1 )
{
/*
* Final segment
@@ -248,7 +262,7 @@ void yadif_filter_thread( void *thread_args_v )
{
/* This isn't the top or bottom,
* proceed as normal to yadif. */
- yadif_filter_line(pv, dst2, prev, cur, next, w, s,
+ yadif_filter_line(pv, dst2, prev, cur, next, w, s,
parity ^ tff);
}
else
@@ -295,8 +309,8 @@ static void yadif_filter( hb_filter_private_t * pv,
int segment;
- for( segment = 0; segment < pv->cpu_count; segment++ )
- {
+ for( segment = 0; segment < pv->segments; segment++ )
+ {
/*
* Setup the work for this plane.
*/
@@ -313,6 +327,128 @@ static void yadif_filter( hb_filter_private_t * pv,
*/
}
+/*
+ * deinterlace a frame in a single thread.
+ */
+void deint_filter_thread( void *thread_args_v )
+{
+ deint_arguments_t *args = NULL;
+ hb_filter_private_t * pv;
+ int run = 1;
+ int segment;
+ deint_thread_arg_t *thread_args = thread_args_v;
+
+ pv = thread_args->pv;
+ segment = thread_args->segment;
+
+ hb_log("Fast Deinterlace thread started for segment %d", segment);
+
+ while( run )
+ {
+ /*
+ * Wait here until there is work to do.
+ */
+ taskset_thread_wait4start( &pv->deint_taskset, segment );
+
+
+ if( taskset_thread_stop( &pv->deint_taskset, segment ) )
+ {
+ /*
+ * No more work to do, exit this thread.
+ */
+ run = 0;
+ goto report_completion;
+ }
+
+ args = &pv->deint_arguments[segment];
+
+ if( args->dst == NULL )
+ {
+ // This can happen when flushing final buffers.
+ goto report_completion;
+ }
+
+ /*
+ * Process all three planes, but only this segment of it.
+ */
+ hb_deinterlace(args->dst, args->src);
+
+report_completion:
+ /*
+ * Finished this segment, let everyone know.
+ */
+ taskset_thread_complete( &pv->deint_taskset, segment );
+ }
+}
+
+/*
+ * threaded fast deint - each thread deinterlaces a single frame.
+ *
+ * This function blocks until all frames are deinterlaced.
+ */
+static hb_buffer_t * deint_fast(hb_filter_private_t * pv, hb_buffer_t * in)
+{
+
+ int ii;
+ hb_buffer_t *dst, *src;
+
+ if (in != NULL)
+ {
+ dst = hb_frame_buffer_init(in->f.fmt, in->f.width, in->f.height);
+ pv->deint_arguments[pv->deint_nsegs].src = in;
+ pv->deint_arguments[pv->deint_nsegs].dst = dst;
+ pv->deint_nsegs++;
+ }
+ if (in != NULL && pv->deint_nsegs < pv->segments)
+ {
+ return NULL;
+ }
+
+ if (pv->deint_nsegs > 0)
+ {
+ /* Allow the taskset threads to make one pass over the data. */
+ taskset_cycle( &pv->deint_taskset );
+ }
+
+ hb_buffer_t *first = NULL, *last = NULL;
+ for (ii = 0; ii < pv->deint_nsegs; ii++)
+ {
+ src = pv->deint_arguments[ii].src;
+ dst = pv->deint_arguments[ii].dst;
+ pv->deint_arguments[ii].src = NULL;
+ pv->deint_arguments[ii].dst = NULL;
+ if (first == NULL)
+ {
+ first = dst;
+ }
+ if (last != NULL)
+ {
+ last->next = dst;
+ }
+ last = dst;
+
+ dst->s = src->s;
+ hb_buffer_move_subs(dst, src);
+ hb_buffer_close(&src);
+ }
+ if (in == NULL)
+ {
+ // Flushing final buffers. Append EOS marker buffer.
+ dst = hb_buffer_init(0);
+ if (first == NULL)
+ {
+ first = dst;
+ }
+ else
+ {
+ last->next = dst;
+ }
+ }
+ pv->deint_nsegs = 0;
+
+ return first;
+}
+
static int hb_deinterlace_init( hb_filter_object_t * filter,
hb_filter_init_t * init )
{
@@ -341,16 +477,17 @@ static int hb_deinterlace_init( hb_filter_object_t * filter,
/*
* Setup yadif taskset.
*/
- pv->yadif_arguments = malloc( sizeof( yadif_arguments_t ) * pv->cpu_count );
+ pv->segments = pv->cpu_count;
+ pv->yadif_arguments = malloc( sizeof( yadif_arguments_t ) * pv->segments );
if( pv->yadif_arguments == NULL ||
- taskset_init( &pv->yadif_taskset, /*thread_count*/pv->cpu_count,
- sizeof( yadif_arguments_t ) ) == 0 )
+ taskset_init( &pv->yadif_taskset, /*thread_count*/pv->segments,
+ sizeof( yadif_thread_arg_t ) ) == 0 )
{
hb_error( "yadif could not initialize taskset" );
}
int ii;
- for( ii = 0; ii < pv->cpu_count; ii++ )
+ for( ii = 0; ii < pv->segments; ii++ )
{
yadif_thread_arg_t *thread_args;
@@ -369,7 +506,41 @@ static int hb_deinterlace_init( hb_filter_object_t * filter,
}
}
}
-
+ else
+ {
+ /*
+ * Setup fast deint taskset.
+ */
+ pv->segments = pv->cpu_count;
+ pv->deint_arguments = malloc( sizeof( deint_arguments_t ) * pv->segments );
+ if( pv->deint_arguments == NULL ||
+ taskset_init( &pv->deint_taskset, pv->segments,
+ sizeof( deint_thread_arg_t ) ) == 0 )
+ {
+ hb_error( "deint could not initialize taskset" );
+ }
+
+ int ii;
+ for( ii = 0; ii < pv->segments; ii++ )
+ {
+ deint_thread_arg_t *thread_args;
+
+ thread_args = taskset_thread_args( &pv->deint_taskset, ii );
+
+ thread_args->pv = pv;
+ thread_args->segment = ii;
+ pv->deint_arguments[ii].dst = NULL;
+
+ if( taskset_thread_spawn( &pv->deint_taskset, ii,
+ "deint_filter_segment",
+ deint_filter_thread,
+ HB_NORMAL_PRIORITY ) == 0 )
+ {
+ hb_error( "deint could not spawn thread" );
+ }
+ }
+ }
+
return 0;
}
@@ -395,37 +566,16 @@ static void hb_deinterlace_close( hb_filter_object_t * filter )
free( pv->yadif_arguments );
}
-
+ else
+ {
+ taskset_fini( &pv->deint_taskset );
+ free( pv->deint_arguments );
+ }
+
free( pv );
filter->private_data = NULL;
}
-static hb_buffer_t * deint_fast(hb_buffer_t * in)
-{
- AVPicture pic_in;
- AVPicture pic_out;
- hb_buffer_t * out;
-
- int w = (in->plane[0].width + 3) & ~0x3;
- int h = (in->plane[0].height + 3) & ~0x3;
-
- out = hb_frame_buffer_init(in->f.fmt, in->f.width, in->f.height);
-
- hb_avpicture_fill( &pic_in, in );
- hb_avpicture_fill( &pic_out, out );
-
- // avpicture_deinterlace requires 4 pixel aligned width and height
- // we have aligned all buffers to 16 byte width and height strides
- // so there is room in the buffers to accomodate a litte
- // overscan.
- avpicture_deinterlace(&pic_out, &pic_in, out->f.fmt, w, h);
-
- out->s = in->s;
- hb_buffer_move_subs(out, in);
-
- return out;
-}
-
static int hb_deinterlace_work( hb_filter_object_t * filter,
hb_buffer_t ** buf_in,
hb_buffer_t ** buf_out )
@@ -438,13 +588,19 @@ static int hb_deinterlace_work( hb_filter_object_t * filter,
{
*buf_out = in;
*buf_in = NULL;
+ if( !( pv->yadif_mode & MODE_YADIF_ENABLE ) )
+ {
+ // Flush final frames
+ *buf_out = deint_fast(pv, NULL);
+ }
return HB_FILTER_DONE;
}
/* Use libavcodec deinterlace if yadif_mode < 0 */
if( !( pv->yadif_mode & MODE_YADIF_ENABLE ) )
{
- *buf_out = deint_fast(in);
+ *buf_in = NULL;
+ *buf_out = deint_fast(pv, in);
return HB_FILTER_OK;
}