OSDN Git Service

Fix a couple problem exposed through some valgrind testing. use of freed
[handbrake-jp/handbrake-jp-git.git] / libhb / deinterlace.c
index 754ed28..7283634 100644 (file)
@@ -1,23 +1,23 @@
 /*
  Copyright (C) 2006 Michael Niedermayer <michaelni@gmx.at>
+
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */
 
 #include "hb.h"
-#include "ffmpeg/avcodec.h"
+#include "libavcodec/avcodec.h"
 #include "mpeg2dec/mpeg2.h"
 
 #define SUPPRESS_AV_LOG
 #define MIN3(a,b,c) MIN(MIN(a,b),c)
 #define MAX3(a,b,c) MAX(MAX(a,b),c)
 
-struct hb_filter_private_s 
+typedef struct yadif_arguments_s {
+    uint8_t **dst;
+    int parity;
+    int tff;
+    int stop;
+} yadif_arguments_t;
+
+struct hb_filter_private_s
 {
     int              pix_fmt;
     int              width[3];
@@ -41,70 +48,77 @@ struct hb_filter_private_s
     int              yadif_mode;
     int              yadif_parity;
     int              yadif_ready;
-    
-    uint8_t        * yadif_ref[4][3];        
+
+    uint8_t        * yadif_ref[4][3];
     int              yadif_ref_stride[3];
-    
+
+    int              cpu_count;
+
+    hb_thread_t    ** yadif_threads;        // Threads for Yadif - one per CPU
+    hb_lock_t      ** yadif_begin_lock;     // Thread has work
+    hb_lock_t      ** yadif_complete_lock;  // Thread has completed work
+    yadif_arguments_t *yadif_arguments;     // Arguments to thread for work
+
     int              mcdeint_mode;
     int              mcdeint_qp;
-    
+
     int              mcdeint_outbuf_size;
     uint8_t        * mcdeint_outbuf;
     AVCodecContext * mcdeint_avctx_enc;
     AVFrame        * mcdeint_frame;
     AVFrame        * mcdeint_frame_dec;
-    
+
     AVPicture        pic_in;
-    AVPicture        pic_out;            
+    AVPicture        pic_out;
     hb_buffer_t *    buf_out[2];
     hb_buffer_t *    buf_settings;
 };
 
-hb_filter_private_t * hb_deinterlace_init( int pix_fmt, 
-                                           int width, 
+hb_filter_private_t * hb_deinterlace_init( int pix_fmt,
+                                           int width,
                                            int height,
                                            char * settings );
 
-int hb_deinterlace_work( const hb_buffer_t * buf_in,
+int hb_deinterlace_work( hb_buffer_t * buf_in,
                          hb_buffer_t ** buf_out,
                          int pix_fmt,
-                         int width, 
+                         int width,
                          int height,
                          hb_filter_private_t * pv );
 
 void hb_deinterlace_close( hb_filter_private_t * pv );
 
 hb_filter_object_t hb_filter_deinterlace =
-{   
+{
     FILTER_DEINTERLACE,
-    "Deinterlace (yadif/mcdeint)",
+    "Deinterlace (ffmpeg or yadif/mcdeint)",
     NULL,
     hb_deinterlace_init,
     hb_deinterlace_work,
     hb_deinterlace_close,
 };
 
-static void yadif_store_ref( const uint8_t ** pic, 
+
+static void yadif_store_ref( const uint8_t ** pic,
                              hb_filter_private_t * pv )
 {
-    memcpy( pv->yadif_ref[3], 
-            pv->yadif_ref[0], 
+    memcpy( pv->yadif_ref[3],
+            pv->yadif_ref[0],
             sizeof(uint8_t *)*3 );
-    
-    memmove( pv->yadif_ref[0], 
-             pv->yadif_ref[1], 
-             sizeof(uint8_t *)*3*3 );    
-    
+
+    memmove( pv->yadif_ref[0],
+             pv->yadif_ref[1],
+             sizeof(uint8_t *)*3*3 );
+
     int i;
     for( i = 0; i < 3; i++ )
     {
         const uint8_t * src = pic[i];
         uint8_t * ref = pv->yadif_ref[2][i];
-        
+
         int w = pv->width[i];
-        int h = pv->height[i];
         int ref_stride = pv->yadif_ref_stride[i];
-        
+
         int y;
         for( y = 0; y < pv->height[i]; y++ )
         {
@@ -117,7 +131,7 @@ static void yadif_store_ref( const uint8_t ** pic,
 
 static void yadif_filter_line( uint8_t *dst,
                                uint8_t *prev,
-                               uint8_t *cur, 
+                               uint8_t *cur,
                                uint8_t *next,
                                int plane,
                                int parity,
@@ -125,10 +139,10 @@ static void yadif_filter_line( uint8_t *dst,
 {
     uint8_t *prev2 = parity ? prev : cur ;
     uint8_t *next2 = parity ? cur  : next;
-    
+
     int w = pv->width[plane];
     int refs = pv->yadif_ref_stride[plane];
-    
+
     int x;
     for( x = 0; x < w; x++)
     {
@@ -150,7 +164,7 @@ static void yadif_filter_line( uint8_t *dst,
             if( score < spatial_score ){\
                 spatial_score = score;\
                 spatial_pred  = (cur[-refs  +j] + cur[+refs  -j])>>1;\
-                            
+
         YADIF_CHECK(-1) YADIF_CHECK(-2) }} }}
         YADIF_CHECK( 1) YADIF_CHECK( 2) }} }}
 
@@ -158,7 +172,7 @@ static void yadif_filter_line( uint8_t *dst,
         {
             int b = (prev2[-2*refs] + next2[-2*refs])>>1;
             int f = (prev2[+2*refs] + next2[+2*refs])>>1;
-            
+
             int max = MAX3(d-e, d-c, MIN(b-c, f-e));
             int min = MIN3(d-e, d-c, MAX(b-c, f-e));
 
@@ -185,77 +199,203 @@ static void yadif_filter_line( uint8_t *dst,
     }
 }
 
-static void yadif_filter( uint8_t ** dst,
-                          int parity,
-                          int tff,
-                          hb_filter_private_t * pv )
+typedef struct yadif_thread_arg_s {
+    hb_filter_private_t *pv;
+    int segment;
+} yadif_thread_arg_t;
+
+/*
+ * deinterlace this segment of all three planes in a single thread.
+ */
+void yadif_filter_thread( void *thread_args_v )
 {
-    int i;
-    for( i = 0; i < 3; i++ )
-    {   
-        int w = pv->width[i];
-        int h = pv->height[i];
-        int ref_stride = pv->yadif_ref_stride[i];
+    yadif_arguments_t *yadif_work = NULL;
+    hb_filter_private_t * pv;
+    int run = 1;
+    int plane;
+    int segment, segment_start, segment_stop;
+    yadif_thread_arg_t *thread_args = thread_args_v;
+    uint8_t **dst;
+    int parity, tff, y, w, h, ref_stride;
+
+
+    pv = thread_args->pv;
+    segment = thread_args->segment;
+
+    hb_log("Yadif Deinterlace thread started for segment %d", segment);
+
+    while( run )
+    {
+        /*
+         * Wait here until there is work to do. hb_lock() blocks until
+         * render releases it to say that there is more work to do.
+         */
+        hb_lock( pv->yadif_begin_lock[segment] );
+
+        yadif_work = &pv->yadif_arguments[segment];
+
+        if( yadif_work->stop )
+        {
+            /*
+             * No more work to do, exit this thread.
+             */
+            run = 0;
+            continue;
+        } 
+
+        if( yadif_work->dst == NULL )
+        {
+            hb_error( "Thread started when no work available" );
+            hb_snooze(500);
+            continue;
+        }
         
-        int y;
-        for( y = 0; y < h; y++ )
+        /*
+         * Process all three planes, but only this segment of it.
+         */
+        for( plane = 0; plane < 3; plane++)
         {
-            if( (y ^ parity) &  1 )
+
+            dst = yadif_work->dst;
+            parity = yadif_work->parity;
+            tff = yadif_work->tff;
+            w = pv->width[plane];
+            h = pv->height[plane];
+            ref_stride = pv->yadif_ref_stride[plane];
+            segment_start = ( h / pv->cpu_count ) * segment;
+            if( segment == pv->cpu_count - 1 )
             {
-                uint8_t *prev = &pv->yadif_ref[0][i][y*ref_stride];
-                uint8_t *cur  = &pv->yadif_ref[1][i][y*ref_stride];
-                uint8_t *next = &pv->yadif_ref[2][i][y*ref_stride];
-                uint8_t *dst2 = &dst[i][y*w];
-                
-                yadif_filter_line( dst2, prev, cur, next, i, parity ^ tff, pv );
+                /*
+                 * Final segment
+                 */
+                segment_stop = h;
+            } else {
+                segment_stop = ( h / pv->cpu_count ) * ( segment + 1 );
             }
-            else
+
+            for( y = segment_start; y < segment_stop; y++ )
             {
-                memcpy( &dst[i][y*w], 
-                        &pv->yadif_ref[1][i][y*ref_stride], 
-                        w * sizeof(uint8_t) );
+                if( (y ^ parity) &  1 )
+                {
+                    uint8_t *prev = &pv->yadif_ref[0][plane][y*ref_stride];
+                    uint8_t *cur  = &pv->yadif_ref[1][plane][y*ref_stride];
+                    uint8_t *next = &pv->yadif_ref[2][plane][y*ref_stride];
+                    uint8_t *dst2 = &dst[plane][y*w];
+                    
+                    yadif_filter_line( dst2, 
+                                       prev, 
+                                       cur, 
+                                       next, 
+                                       plane, 
+                                       parity ^ tff, 
+                                       pv );
+                    
+                }
+                else
+                {
+                    memcpy( &dst[plane][y*w],
+                            &pv->yadif_ref[1][plane][y*ref_stride],
+                            w * sizeof(uint8_t) );
+                }
             }
         }
+        /*
+         * Finished this segment, let everyone know.
+         */
+        hb_unlock( pv->yadif_complete_lock[segment] );
     }
+    free( thread_args_v );
 }
 
-static void mcdeint_filter( uint8_t ** dst, 
+
+/*
+ * threaded yadif - each thread deinterlaces 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 deinterlaced.
+ */
+static void yadif_filter( uint8_t ** dst,
+                          int parity,
+                          int tff,
+                          hb_filter_private_t * pv )
+{
+
+    int segment;
+
+    for( segment = 0; segment < pv->cpu_count; segment++ )
+    {  
+        /*
+         * Setup the work for this plane.
+         */
+        pv->yadif_arguments[segment].parity = parity;
+        pv->yadif_arguments[segment].tff = tff;
+        pv->yadif_arguments[segment].dst = dst;
+
+        /*
+         * Let the thread for this plane know that we've setup work 
+         * for it by releasing the begin lock (ensuring that the
+         * complete lock is already locked so that we block when
+         * we try to lock it again below).
+         */
+        hb_lock( pv->yadif_complete_lock[segment] );
+        hb_unlock( pv->yadif_begin_lock[segment] );
+    }
+
+    /*
+     * Wait until all three threads have completed by trying to get
+     * the complete lock that we locked earlier for each thread, which
+     * will block until that thread has completed the work on that
+     * plane.
+     */
+    for( segment = 0; segment < pv->cpu_count; segment++ )
+    {
+        hb_lock( pv->yadif_complete_lock[segment] );
+        hb_unlock( pv->yadif_complete_lock[segment] );
+    }
+
+    /*
+     * Entire frame is now deinterlaced.
+     */
+}
+
+static void mcdeint_filter( uint8_t ** dst,
                             uint8_t ** src,
                             int parity,
                             hb_filter_private_t * pv )
 {
     int x, y, i;
-    int out_size;    
-   
+    int out_size;
+
 #ifdef SUPPRESS_AV_LOG
     /* TODO: temporarily change log level to suppress obnoxious debug output */
     int loglevel = av_log_get_level();
     av_log_set_level( AV_LOG_QUIET );
 #endif
-    
+
     for( i=0; i<3; i++ )
     {
         pv->mcdeint_frame->data[i] = src[i];
         pv->mcdeint_frame->linesize[i] = pv->width[i];
-    }    
+    }
     pv->mcdeint_avctx_enc->me_cmp     = FF_CMP_SAD;
     pv->mcdeint_avctx_enc->me_sub_cmp = FF_CMP_SAD;
     pv->mcdeint_frame->quality        = pv->mcdeint_qp * FF_QP2LAMBDA;
-    
-    out_size = avcodec_encode_video( pv->mcdeint_avctx_enc, 
-                                     pv->mcdeint_outbuf, 
-                                     pv->mcdeint_outbuf_size, 
+
+    out_size = avcodec_encode_video( pv->mcdeint_avctx_enc,
+                                     pv->mcdeint_outbuf,
+                                     pv->mcdeint_outbuf_size,
                                      pv->mcdeint_frame );
-    
+
     pv->mcdeint_frame_dec = pv->mcdeint_avctx_enc->coded_frame;
-    
+
     for( i = 0; i < 3; i++ )
     {
         int w    = pv->width[i];
         int h    = pv->height[i];
         int fils = pv->mcdeint_frame_dec->linesize[i];
         int srcs = pv->width[i];
-        
+
         for( y = 0; y < h; y++ )
         {
             if( (y ^ parity) & 1 )
@@ -263,21 +403,21 @@ static void mcdeint_filter( uint8_t ** dst,
                 for( x = 0; x < w; x++ )
                 {
                     if( (x-2)+(y-1)*w >= 0 && (x+2)+(y+1)*w < w*h )
-                    { 
-                        uint8_t * filp = 
+                    {
+                        uint8_t * filp =
                             &pv->mcdeint_frame_dec->data[i][x + y*fils];
                         uint8_t * srcp = &src[i][x + y*srcs];
 
                         int diff0 = filp[-fils] - srcp[-srcs];
                         int diff1 = filp[+fils] - srcp[+srcs];
-                        
-                        int spatial_score = 
+
+                        int spatial_score =
                               ABS(srcp[-srcs-1] - srcp[+srcs-1])
                             + ABS(srcp[-srcs  ] - srcp[+srcs  ])
                             + ABS(srcp[-srcs+1] - srcp[+srcs+1]) - 1;
-                        
+
                         int temp = filp[0];
-                        
+
 #define MCDEINT_CHECK(j)\
                         {   int score = ABS(srcp[-srcs-1+j] - srcp[+srcs-1-j])\
                                       + ABS(srcp[-srcs  +j] - srcp[+srcs  -j])\
@@ -286,27 +426,27 @@ static void mcdeint_filter( uint8_t ** dst,
                                 spatial_score = score;\
                                 diff0 = filp[-fils+j] - srcp[-srcs+j];\
                                 diff1 = filp[+fils-j] - srcp[+srcs-j];
-                                        
+
                         MCDEINT_CHECK(-1) MCDEINT_CHECK(-2) }} }}
                         MCDEINT_CHECK( 1) MCDEINT_CHECK( 2) }} }}
 
                         if(diff0 + diff1 > 0)
                         {
-                            temp -= (diff0 + diff1 - 
+                            temp -= (diff0 + diff1 -
                                      ABS( ABS(diff0) - ABS(diff1) ) / 2) / 2;
                         }
                         else
                         {
-                            temp -= (diff0 + diff1 + 
+                            temp -= (diff0 + diff1 +
                                      ABS( ABS(diff0) - ABS(diff1) ) / 2) / 2;
                         }
 
-                        filp[0] = dst[i][x + y*w] = 
+                        filp[0] = dst[i][x + y*w] =
                             temp > 255U ? ~(temp>>31) : temp;
                     }
                     else
                     {
-                        dst[i][x + y*w] = 
+                        dst[i][x + y*w] =
                             pv->mcdeint_frame_dec->data[i][x + y*fils];
                     }
                 }
@@ -332,8 +472,8 @@ static void mcdeint_filter( uint8_t ** dst,
 #endif
 }
 
-hb_filter_private_t * hb_deinterlace_init( int pix_fmt, 
-                                           int width, 
+hb_filter_private_t * hb_deinterlace_init( int pix_fmt,
+                                           int width,
                                            int height,
                                            char * settings )
 {
@@ -341,71 +481,112 @@ hb_filter_private_t * hb_deinterlace_init( int pix_fmt,
     {
         return 0;
     }
-    
+
     hb_filter_private_t * pv = calloc( 1, sizeof(struct hb_filter_private_s) );
-    
+
     pv->pix_fmt = pix_fmt;
 
     pv->width[0]  = width;
-    pv->height[0] = height;    
+    pv->height[0] = height;
     pv->width[1]  = pv->width[2]  = width >> 1;
-    pv->height[1] = pv->height[2] = height >> 1;    
-    
-    int buf_size = 3 * width * height / 2;    
+    pv->height[1] = pv->height[2] = height >> 1;
+
+    int buf_size = 3 * width * height / 2;
     pv->buf_out[0] = hb_buffer_init( buf_size );
     pv->buf_out[1] = hb_buffer_init( buf_size );
     pv->buf_settings = hb_buffer_init( 0 );
-    
+
     pv->yadif_ready    = 0;
     pv->yadif_mode     = YADIF_MODE_DEFAULT;
-    pv->yadif_parity   = YADIF_PARITY_DEFAULT;    
-    
+    pv->yadif_parity   = YADIF_PARITY_DEFAULT;
+
     pv->mcdeint_mode   = MCDEINT_MODE_DEFAULT;
     pv->mcdeint_qp     = MCDEINT_QP_DEFAULT;
-    
+
     if( settings )
     {
-        sscanf( settings, "%d:%d:%d:%d", 
-                &pv->yadif_mode, 
+        sscanf( settings, "%d:%d:%d:%d",
+                &pv->yadif_mode,
                 &pv->yadif_parity,
                 &pv->mcdeint_mode,
                 &pv->mcdeint_qp );
     }
-    
+
+    pv->cpu_count = hb_get_cpu_count();
+
     /* Allocate yadif specific buffers */
     if( pv->yadif_mode >= 0 )
     {
         int i, j;
         for( i = 0; i < 3; i++ )
-        {   
+        {
             int is_chroma = !!i;
             int w = ((width   + 31) & (~31))>>is_chroma;
             int h = ((height+6+ 31) & (~31))>>is_chroma;
-            
+
             pv->yadif_ref_stride[i] = w;
-            
+
             for( j = 0; j < 3; j++ )
             {
                 pv->yadif_ref[j][i] = malloc( w*h*sizeof(uint8_t) ) + 3*w;
-            }        
+            }
+        }
+
+        /*
+         * Create yadif threads and locks.
+         */
+        pv->yadif_threads = malloc( sizeof( hb_thread_t* ) * pv->cpu_count );
+        pv->yadif_begin_lock = malloc( sizeof( hb_lock_t * ) * pv->cpu_count );
+        pv->yadif_complete_lock = malloc( sizeof( hb_lock_t * ) * pv->cpu_count );
+        pv->yadif_arguments = malloc( sizeof( yadif_arguments_t ) * pv->cpu_count );
+
+        for( i = 0; i < pv->cpu_count; i++ )
+        {
+            yadif_thread_arg_t *thread_args;
+
+            thread_args = malloc( sizeof( yadif_thread_arg_t ) );
+
+            if( thread_args ) {
+                thread_args->pv = pv;
+                thread_args->segment = i;
+
+                pv->yadif_begin_lock[i] = hb_lock_init();
+                pv->yadif_complete_lock[i] = hb_lock_init();
+
+                /*
+                 * Important to start off with the threads locked waiting
+                 * on input.
+                 */
+                hb_lock( pv->yadif_begin_lock[i] );
+
+                pv->yadif_arguments[i].stop = 0;
+                pv->yadif_arguments[i].dst = NULL;
+                
+                pv->yadif_threads[i] = hb_thread_init( "yadif_filter_segment",
+                                                       yadif_filter_thread,
+                                                       thread_args,
+                                                       HB_NORMAL_PRIORITY );
+            } else {
+                hb_error( "Yadif could not create threads" );
+            }
         }
     }
-    
+
     /* Allocate mcdeint specific buffers */
     if( pv->mcdeint_mode >= 0 )
     {
         avcodec_init();
         avcodec_register_all();
-        
+
         AVCodec * enc = avcodec_find_encoder( CODEC_ID_SNOW );
-        
+
         int i;
         for (i = 0; i < 3; i++ )
         {
             AVCodecContext * avctx_enc;
-            
+
             avctx_enc = pv->mcdeint_avctx_enc = avcodec_alloc_context();
-            
+
             avctx_enc->width                    = width;
             avctx_enc->height                   = height;
             avctx_enc->time_base                = (AVRational){1,25};  // meaningless
@@ -419,23 +600,23 @@ hb_filter_private_t * hb_deinterlace_init( int pix_fmt,
             avctx_enc->me_cmp                   = FF_CMP_SAD; //SSE;
             avctx_enc->me_sub_cmp               = FF_CMP_SAD; //SSE;
             avctx_enc->mb_cmp                   = FF_CMP_SSE;
-            
+
             switch( pv->mcdeint_mode )
             {
                 case 3:
                     avctx_enc->refs = 3;
                 case 2:
-                    avctx_enc->me_method = ME_ITER;
+                    avctx_enc->me_method = ME_UMH;
                 case 1:
                     avctx_enc->flags |= CODEC_FLAG_4MV;
                     avctx_enc->dia_size =2;
                 case 0:
                     avctx_enc->flags |= CODEC_FLAG_QPEL;
             }
-            
-            avcodec_open(avctx_enc, enc);        
+
+            avcodec_open(avctx_enc, enc);
         }
-        
+
         pv->mcdeint_frame       = avcodec_alloc_frame();
         pv->mcdeint_outbuf_size = width * height * 10;
         pv->mcdeint_outbuf      = malloc( pv->mcdeint_outbuf_size );
@@ -446,16 +627,16 @@ hb_filter_private_t * hb_deinterlace_init( int pix_fmt,
 
 void hb_deinterlace_close( hb_filter_private_t * pv )
 {
-    if( !pv ) 
+    if( !pv )
     {
         return;
     }
-    
+
     /* Cleanup frame buffers */
     if( pv->buf_out[0] )
     {
         hb_buffer_close( &pv->buf_out[0] );
-    }    
+    }
     if( pv->buf_out[1] )
     {
         hb_buffer_close( &pv->buf_out[1] );
@@ -472,14 +653,35 @@ void hb_deinterlace_close( hb_filter_private_t * pv )
         for( i = 0; i<3*3; i++ )
         {
             uint8_t **p = &pv->yadif_ref[i%3][i/3];
-            if (*p) 
+            if (*p)
             {
                 free( *p - 3*pv->yadif_ref_stride[i/3] );
                 *p = NULL;
             }
         }
+
+        for( i = 0; i < pv->cpu_count; i++)
+        {
+            /*
+             * Tell each yadif thread to stop, and then cleanup.
+             */
+            pv->yadif_arguments[i].stop = 1;
+            hb_unlock(  pv->yadif_begin_lock[i] );
+
+            hb_thread_close( &pv->yadif_threads[i] );
+            hb_lock_close( &pv->yadif_begin_lock[i] );
+            hb_lock_close( &pv->yadif_complete_lock[i] );
+        }
+        
+        /*
+         * free memory for yadif structs
+         */
+        free( pv->yadif_threads );
+        free( pv->yadif_begin_lock );
+        free( pv->yadif_complete_lock );
+        free( pv->yadif_arguments );
     }
-    
+
     /* Cleanup mcdeint specific buffers */
     if( pv->mcdeint_mode >= 0 )
     {
@@ -487,50 +689,50 @@ void hb_deinterlace_close( hb_filter_private_t * pv )
         {
             avcodec_close( pv->mcdeint_avctx_enc );
             av_freep( &pv->mcdeint_avctx_enc );
-        }        
+        }
         if( pv->mcdeint_outbuf )
         {
             free( pv->mcdeint_outbuf );
-        }        
-    }    
-    
+        }
+    }
+
     free( pv );
 }
 
-int hb_deinterlace_work( const hb_buffer_t * buf_in,
+int hb_deinterlace_work( hb_buffer_t * buf_in,
                          hb_buffer_t ** buf_out,
                          int pix_fmt,
-                         int width, 
+                         int width,
                          int height,
                          hb_filter_private_t * pv )
 {
-    if( !pv || 
+    if( !pv ||
         pix_fmt != pv->pix_fmt ||
         width   != pv->width[0] ||
         height  != pv->height[0] )
     {
         return FILTER_FAILED;
     }
-    
-    avpicture_fill( &pv->pic_in, buf_in->data, 
+
+    avpicture_fill( &pv->pic_in, buf_in->data,
                     pix_fmt, width, height );
 
     /* Use libavcodec deinterlace if yadif_mode < 0 */
     if( pv->yadif_mode < 0 )
-    {        
-        avpicture_fill( &pv->pic_out, pv->buf_out[0]->data, 
+    {
+        avpicture_fill( &pv->pic_out, pv->buf_out[0]->data,
                         pix_fmt, width, height );
-        
-        avpicture_deinterlace( &pv->pic_out, &pv->pic_in, 
+
+        avpicture_deinterlace( &pv->pic_out, &pv->pic_in,
                                pix_fmt, width, height );
-        
+
         hb_buffer_copy_settings( pv->buf_out[0], buf_in );
 
         *buf_out = pv->buf_out[0];
-        
+
         return FILTER_OK;
     }
-    
+
     /* Determine if top-field first layout */
     int tff;
     if( pv->yadif_parity < 0 )
@@ -541,19 +743,22 @@ int hb_deinterlace_work( const hb_buffer_t * buf_in,
     {
         tff = (pv->yadif_parity & 1) ^ 1;
     }
-    
+
     /* Store current frame in yadif cache */
     yadif_store_ref( (const uint8_t**)pv->pic_in.data, pv );
-    
+
     /* If yadif is not ready, store another ref and return FILTER_DELAY */
     if( pv->yadif_ready == 0 )
     {
         yadif_store_ref( (const uint8_t**)pv->pic_in.data, pv );
-        
+
         hb_buffer_copy_settings( pv->buf_settings, buf_in );
 
+        /* don't let 'work_loop' send a chapter mark upstream */
+        buf_in->new_chap  = 0;
+
         pv->yadif_ready = 1;
-        
+
         return FILTER_DELAY;
     }
 
@@ -562,19 +767,19 @@ int hb_deinterlace_work( const hb_buffer_t * buf_in,
     for( frame = 0; frame <= (pv->yadif_mode & 1); frame++ )
     {
         int parity = frame ^ tff ^ 1;
-        
-        avpicture_fill( &pv->pic_out, pv->buf_out[!(frame^1)]->data, 
+
+        avpicture_fill( &pv->pic_out, pv->buf_out[!(frame^1)]->data,
                         pix_fmt, width, height );
-        
+
         yadif_filter( pv->pic_out.data, parity, tff, pv );
 
         if( pv->mcdeint_mode >= 0 )
         {
-            avpicture_fill( &pv->pic_in,  pv->buf_out[(frame^1)]->data, 
+            avpicture_fill( &pv->pic_in,  pv->buf_out[(frame^1)]->data,
                             pix_fmt, width, height );
-            
+
             mcdeint_filter( pv->pic_in.data, pv->pic_out.data, parity, pv );
-            
+
             *buf_out = pv->buf_out[ (frame^1)];
         }
         else
@@ -582,12 +787,15 @@ int hb_deinterlace_work( const hb_buffer_t * buf_in,
             *buf_out = pv->buf_out[!(frame^1)];
         }
     }
-    
+
     /* Copy buffered settings to output buffer settings */
     hb_buffer_copy_settings( *buf_out, pv->buf_settings );
-    
+
     /* Replace buffered settings with input buffer settings */
-    hb_buffer_copy_settings( pv->buf_settings, buf_in );    
+    hb_buffer_copy_settings( pv->buf_settings, buf_in );
+
+    /* don't let 'work_loop' send a chapter mark upstream */
+    buf_in->new_chap  = 0;
 
     return FILTER_OK;
 }