rendered paste bodyIndex: libhb/deinterlace.c===================================================================--- libhb/deinterlace.c (revision 1252)+++ libhb/deinterlace.c (working copy)@@ -41,6 +41,7 @@ int yadif_mode;
int yadif_parity;
int yadif_ready;
+ int comb;
uint8_t * yadif_ref[4][3];
int yadif_ref_stride[3];
@@ -84,6 +85,53 @@ hb_deinterlace_close,
};
+int detect_comb( hb_buffer_t * buf, int width, int height);
+
+int detect_comb( hb_buffer_t * buf, int width, int height)
+{
+ /* See if frame shows interlacing */
+ int j, n, off, block, cc_1, cc_2, cc, flag, eq, diff, thres;
+ uint16_t s1, s2, s3, s4;
+ cc_1 = 0; cc_2 = 0;
+ eq = 10; diff = 30; thres = 0;
+
+ block = width;
+ flag = 0;
+
+ for(j=0; j<block; ++j)
+ {
+ off=0;
+
+ for(n=0; n<(height-4); n=n+2)
+ {
+ s1 = (buf->data[off+j ] & 0xff);
+ s2 = (buf->data[off+j+ block] & 0xff);
+ s3 = (buf->data[off+j+2*block] & 0xff);
+ s4 = (buf->data[off+j+3*block] & 0xff);
+
+ if((abs(s1 - s3) < eq) &&
+ (abs(s1 - s2) > diff)) ++cc_1;
+
+ if((abs(s2 - s4) < eq) &&
+ (abs(s2 - s3) > diff)) ++cc_2;
+
+ off +=2*block;
+ }
+ }
+
+ // compare results
+
+ cc = (int)((cc_1 + cc_2)*1000.0/(width*height));
+
+ flag = (cc > thres) ? 1:0;
+
+ if(cc)
+ hb_log("flag: %i | cc: %i | cc1: %i | cc2: %i", flag, cc, cc_1, cc_2);
+
+ return flag;
+}
+
+
static void yadif_store_ref( const uint8_t ** pic,
hb_filter_private_t * pv )
{
@@ -115,6 +163,26 @@ }
}
+static void yadif_get_ref( uint8_t ** pic, hb_filter_private_t * pv, int frm )
+{
+ int i;
+ for( i = 0; i < 3; i++ )
+ {
+ uint8_t * dst = pic[i];
+ const uint8_t * ref = pv->yadif_ref[frm][i];
+ int w = pv->width[i];
+ int ref_stride = pv->yadif_ref_stride[i];
+
+ int y;
+ for( y = 0; y < pv->height[i]; y++ )
+ {
+ memcpy(dst, ref, w);
+ dst += w;
+ ref += ref_stride;
+ }
+ }
+}
+
static void yadif_filter_line( uint8_t *dst,
uint8_t *prev,
uint8_t *cur,
@@ -520,13 +588,25 @@ {
avpicture_fill( &pv->pic_out, pv->buf_out[0]->data,
pix_fmt, width, height );
-
- avpicture_deinterlace( &pv->pic_out, &pv->pic_in,
+
+ if( detect_comb(buf_in, width, height) )
+ {
+ hb_log("found combing!");
+
+ avpicture_deinterlace( &pv->pic_out, &pv->pic_in,
pix_fmt, width, height );
-
- hb_buffer_copy_settings( pv->buf_out[0], buf_in );
+
+ hb_buffer_copy_settings( pv->buf_out[0], buf_in );
+
+ *buf_out = pv->buf_out[0];
- *buf_out = pv->buf_out[0];
+ }
+ else
+ {
+ hb_buffer_copy_settings( pv->buf_out[0], buf_in );
+
+ *buf_out = buf_in;
+ }
return FILTER_OK;
}
@@ -544,6 +624,7 @@
/* Store current frame in yadif cache */
yadif_store_ref( (const uint8_t**)pv->pic_in.data, pv );
+ pv->comb = (pv->comb << 1) | detect_comb(buf_in, width, height);
/* If yadif is not ready, store another ref and return FILTER_DELAY */
if( pv->yadif_ready == 0 )
@@ -551,50 +632,64 @@ 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;
+ /* don't let 'work_loop' send a chapter mark upstream */
+ buf_in->new_chap = 0;
+
pv->yadif_ready = 1;
return FILTER_DELAY;
}
- /* Perform yadif and mcdeint filtering */
- int frame;
- for( frame = 0; frame <= (pv->yadif_mode & 1); frame++ )
+ /* yadif & mcdeint work one frame behind so if the previous frame
+ * had combing, deinterlace it otherwise just output it. */
+ if( (pv->comb & 2 ) == 0 )
{
- int parity = frame ^ tff ^ 1;
-
- avpicture_fill( &pv->pic_out, pv->buf_out[!(frame^1)]->data,
- pix_fmt, width, height );
-
- yadif_filter( pv->pic_out.data, parity, tff, pv );
+ /* previous frame not interlaced - copy cached input frame to buf_out */
+ avpicture_fill( &pv->pic_out, pv->buf_out[0]->data, pix_fmt, width, height );
+ yadif_get_ref( (uint8_t**)pv->pic_out.data, pv, 1 );
+ *buf_out = pv->buf_out[0];
+ }
+ else
+ {
+ /* Perform yadif and mcdeint filtering */
+ hb_log("combing detected, passing to yadif");
- if( pv->mcdeint_mode >= 0 )
+ int frame;
+ for( frame = 0; frame <= (pv->yadif_mode & 1); frame++ )
{
- avpicture_fill( &pv->pic_in, pv->buf_out[(frame^1)]->data,
+ int parity = frame ^ tff ^ 1;
+
+ avpicture_fill( &pv->pic_out, 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)];
+
+ 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,
+ pix_fmt, width, height );
+
+ mcdeint_filter( pv->pic_in.data, pv->pic_out.data, parity, pv );
+
+ *buf_out = pv->buf_out[ (frame^1)];
+ }
+ else
+ {
+ *buf_out = pv->buf_out[!(frame^1)];
+ }
}
- else
- {
- *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 );
-- /* don't let 'work_loop' send a chapter mark upstream */- buf_in->new_chap = 0;
+ /* don't let 'work_loop' send a chapter mark upstream */
+ buf_in->new_chap = 0;
+
return FILTER_OK;
}