Index: test/test.c =================================================================== --- test/test.c (revision 1336) +++ test/test.c (working copy) @@ -300,6 +300,13 @@ fprintf( stderr, " + %d, %s (iso639-2: %s)\n", i + 1, subtitle->lang, subtitle->iso639_2); } + + if(title->detected_interlacing) + { + /* Interlacing was found in 6 or more preview frames */ + fprintf( stderr, " + interlacing artifacts detected\n"); + } + } static int HandleEvents( hb_handle_t * h ) @@ -725,6 +732,13 @@ { job->pixel_ratio = pixelratio; } + + if (vfr) + { + detelecine = 1; + job->vfr = 1; + } + /* Add selected filters */ job->filters = hb_list_init(); if( detelecine ) @@ -926,9 +940,6 @@ if (maxHeight) job->maxHeight = maxHeight; - if (vfr) - job->vfr = 1; - if( subtitle_force ) { job->subtitle_force = subtitle_force; @@ -1626,6 +1637,7 @@ { int i; char * tmp = optarg; +// fprintf(stderr, "cropping string is: %s", tmp); for( i = 0; i < 4; i++ ) { if( !*tmp ) @@ -1634,7 +1646,14 @@ tmp++; } break; - } + +/* sscanf( optarg, "%d:%d:%d:%d", + &crop[0], + &crop[1], + &crop[2], + &crop[3]); + break; +*/ } case 'r': { int i; Index: libhb/detelecine.c =================================================================== --- libhb/detelecine.c (revision 1336) +++ libhb/detelecine.c (working copy) @@ -1027,7 +1027,9 @@ pv->width[1] * pv->height[1] * sizeof(uint8_t) ); memcpy( pv->pic_out.data[2], frame->buffer->planes[2], pv->width[2] * pv->height[2] * sizeof(uint8_t) ); - + + pv->buf_out->length = frame->length; + pullup_release_frame( frame ); output_frame: Index: libhb/hb.c =================================================================== --- libhb/hb.c (revision 1336) +++ libhb/hb.c (working copy) @@ -426,6 +426,115 @@ avpicture_free( &pic_in ); } + /** + * Analyzes a frame to detect interlacing artifacts + * and returns true if interlacing (combing) is found. + * + * Code taken from Thomas Oestreich's 32detect filter + * in the Transcode project, with minor formatting changes. + * + * @param buf An hb_buffer structure holding valid frame data. + * @param width The frame's width in pixels. + * @param height The frame's height in pixels. + */ +int hb_detect_comb( hb_buffer_t * buf, int width, int height, int color_equal, int color_diff, int threshold) +{ + int j, k, n, off, block, cc_1, cc_2, cc[3], flag[3]; + uint16_t s1, s2, s3, s4; + cc_1 = 0; cc_2 = 0; + + /* These values are defined in hb.h */ + int thres = threshold; + int eq = color_equal; + int diff = color_diff; + + int offset = 0; + if( buf->telecined ) + { + return 0; + } + + for(k=0; k < 3; k++) + { + /* One pas for Y, one pass for Cb, one pass for Cr */ + if( k == 1 ) + { + /* Y has already been checked, now offset by Y's dimensions + and divide all the other values by 2, since Cr and Cb + are half-size compared to Y. */ + offset = width * height; + width >>= 1; + height >>= 1; + thres >>= 1; + eq >>= 1; + diff >>= 1; + } + else if (k == 2 ) + { + /* Y and Cb are done, so the offset needs to be bumped + so it's width*height + (width / 2) * (height / 2) */ + offset *= 5/4; + } + + /* Look at one horizontal line at a time */ + block = width; + + for(j=0; jdata+offset)[off+j ] & 0xff); + s2 = ((buf->data+offset)[off+j+ block] & 0xff); + s3 = ((buf->data+offset)[off+j+2*block] & 0xff); + s4 = ((buf->data+offset)[off+j+3*block] & 0xff); + + /* Note if the 1st and 2nd lines are more different in + color than the 1st and 3rd lines are similar in color.*/ + if((abs(s1 - s3) < eq) && + (abs(s1 - s2) > diff)) ++cc_1; + + /* Note if the 2nd and 3rd lines are more different in + color than the 2nd and 4th lines are similar in color.*/ + if((abs(s2 - s4) < eq) && + (abs(s2 - s3) > diff)) ++cc_2; + + /* Now move down 2 horizontal lines before starting over.*/ + off +=2*block; + } + } + + // compare results + /* The final metric seems to be doing some kind of bits per pixel style calculation + to decide whether or not enough lines showed alternating colors for the frame size. */ + cc[k] = (int)((cc_1 + cc_2)*1000.0/(width*height)); + + /* If the plane's cc score meets the threshold, flag it as combed. */ + flag[k] = 0; + if(cc[k] > thres) + { + flag[k] = 1; + } + } + +#if 0 +/* Debugging info */ +// if(flag) + hb_log("flags: %i/%i/%i | cc0: %i | cc1: %i | cc2: %i", flag[0], flag[1], flag[2], cc[0], cc[1], cc[2]); +#endif + + /* When more than one plane shows combing, tell the caller. */ + if (flag[0] || flag[1] || flag[2] ) + { + return 1; + } + + return 0; +} + + /** * Calculates job width and height for anamorphic content, * Index: libhb/hb.h =================================================================== --- libhb/hb.h (revision 1336) +++ libhb/hb.h (working copy) @@ -75,6 +75,14 @@ Returns the list of valid titles detected by the latest scan. */ hb_list_t * hb_get_titles( hb_handle_t * ); +/* hb_detect_comb() + Analyze a frame for interlacing artifacts, returns true if they're found. + Taken from Thomas Oestreich's 32detect filter in the Transcode project. */ +int hb_detect_comb( hb_buffer_t * buf, int width, int height, int color_equal, int color_diff, int threshold); +#define COLOR_EQUAL 10 // Sensitivity for detecting similar colors. +#define COLOR_DIFF 30 // Sensitivity for detecting different colors +#define THRESHOLD 9 // Sensitivity for flagging planes as combed + void hb_get_preview( hb_handle_t *, hb_title_t *, int, uint8_t * ); void hb_set_size( hb_job_t *, int ratio, int pixels ); Index: libhb/render.c =================================================================== --- libhb/render.c (revision 1336) +++ libhb/render.c (working copy) @@ -29,6 +29,7 @@ uint64_t total_gained_time; int64_t chapter_time; int chapter_val; + int last_frame_length; }; int renderInit( hb_work_object_t *, hb_job_t * ); @@ -282,6 +283,14 @@ if( result == FILTER_OK ) { buf_tmp_in = buf_tmp_out; + if (buf_tmp_in->length == 3 || pv->last_frame_length == 3) + { + buf_tmp_in->telecined = 1; + } + else + { + buf_tmp_in->telecined = 0; + } } else if( result == FILTER_DELAY ) { @@ -420,7 +429,10 @@ /* The current frame exists. That means it hasn't been dropped by a filter. Make it accessible as ivtc_buffer so we can edit its duration if needed. */ ivtc_buffer = *buf_out; + + pv->last_frame_length = ivtc_buffer->length; + //hb_log("frame length: %i", ivtc_buffer->length); if( pv->lost_time[3] > 0 ) { /* @@ -562,6 +574,8 @@ pv->lost_time[0] = 0; pv->lost_time[1] = 0; pv->lost_time[2] = 0; pv->lost_time[3] = 0; pv->chapter_time = 0; pv->chapter_val = 0; + + pv->last_frame_length = 0; /* Setup filters */ /* TODO: Move to work.c? */ Index: libhb/deinterlace.c =================================================================== --- libhb/deinterlace.c (revision 1336) +++ libhb/deinterlace.c (working copy) @@ -42,6 +42,14 @@ int yadif_parity; int yadif_ready; + int comb; + int comb_detect; + int color_equal; + int color_diff; + int threshold; + int deinterlaced_frames; + int passed_frames; + uint8_t * yadif_ref[4][3]; int yadif_ref_stride[3]; @@ -115,6 +123,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, @@ -356,6 +384,13 @@ pv->buf_out[1] = hb_buffer_init( buf_size ); pv->buf_settings = hb_buffer_init( 0 ); + pv->deinterlaced_frames = 0; + pv->passed_frames = 0; + pv->comb_detect = 0; + pv->color_equal = 10; + pv->color_diff = 30; + pv->threshold = 9; + pv->yadif_ready = 0; pv->yadif_mode = YADIF_MODE_DEFAULT; pv->yadif_parity = YADIF_PARITY_DEFAULT; @@ -365,11 +400,15 @@ if( settings ) { - sscanf( settings, "%d:%d:%d:%d", + sscanf( settings, "%d:%d:%d:%d:%d:%d:%d:%d", &pv->yadif_mode, &pv->yadif_parity, &pv->mcdeint_mode, - &pv->mcdeint_qp ); + &pv->mcdeint_qp, + &pv->comb_detect, + &pv->color_equal, + &pv->color_diff, + &pv->threshold ); } /* Allocate yadif specific buffers */ @@ -451,6 +490,8 @@ return; } + hb_log("deinterlacer: filtered %i | unfiltered %i | total %i", pv->deinterlaced_frames, pv->passed_frames, pv->deinterlaced_frames + pv->passed_frames); + /* Cleanup frame buffers */ if( pv->buf_out[0] ) { @@ -521,12 +562,29 @@ avpicture_fill( &pv->pic_out, pv->buf_out[0]->data, pix_fmt, width, height ); - avpicture_deinterlace( &pv->pic_out, &pv->pic_in, - pix_fmt, width, height ); + /* Check for combing on the input frame */ + int interlaced = pv->comb_detect ? ( hb_detect_comb(buf_in, width, height, pv->color_equal, pv->color_diff, pv->threshold)) : 1; + + if(interlaced) + { + avpicture_deinterlace( &pv->pic_out, &pv->pic_in, + pix_fmt, width, height ); - hb_buffer_copy_settings( pv->buf_out[0], buf_in ); + pv->deinterlaced_frames++; - *buf_out = pv->buf_out[0]; + hb_buffer_copy_settings( pv->buf_out[0], buf_in ); + *buf_out = pv->buf_out[0]; + } + else + { + /* No combing detected, pass input frame through unmolested.*/ + + pv->passed_frames++; + + hb_buffer_copy_settings( pv->buf_out[0], buf_in ); + *buf_out = buf_in; + + } return FILTER_OK; } @@ -545,6 +603,9 @@ /* Store current frame in yadif cache */ yadif_store_ref( (const uint8_t**)pv->pic_in.data, pv ); + /* Note down if the input frame is combed */ + pv->comb = (pv->comb << 1) | ( pv->comb_detect? hb_detect_comb(buf_in, width, height, pv->color_equal, pv->color_diff, pv->threshold) : 1); + /* If yadif is not ready, store another ref and return FILTER_DELAY */ if( pv->yadif_ready == 0 ) { @@ -560,30 +621,48 @@ 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; + /* previous frame not interlaced - copy cached input frame to buf_out */ + + pv->passed_frames++; + + 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 */ + + pv->deinterlaced_frames++; + + int frame; + 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, - 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_out, pv->buf_out[!(frame^1)]->data, pix_fmt, width, height ); - mcdeint_filter( pv->pic_in.data, pv->pic_out.data, parity, pv ); + yadif_filter( pv->pic_out.data, parity, tff, pv ); - *buf_out = pv->buf_out[ (frame^1)]; + 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 */ Index: libhb/internal.h =================================================================== --- libhb/internal.h (revision 1336) +++ libhb/internal.h (working copy) @@ -54,7 +54,9 @@ #define HB_FRAME_REF 0xF0 uint8_t frametype; uint16_t flags; - + int length; + int telecined; + /* Holds the output PTS from x264, for use by b-frame offsets in muxmp4.c */ int64_t renderOffset; Index: libhb/fifo.c =================================================================== --- libhb/fifo.c (revision 1336) +++ libhb/fifo.c (working copy) @@ -321,6 +321,8 @@ dst->new_chap = src->new_chap; dst->frametype = src->frametype; dst->flags = src->flags; + dst->length = src->length; + dst->telecined = src->telecined; } hb_fifo_t * hb_fifo_init( int capacity ) Index: libhb/scan.c =================================================================== --- libhb/scan.c (revision 1336) +++ libhb/scan.c (working copy) @@ -286,6 +286,8 @@ hb_list_t * list_es, * list_raw; hb_libmpeg2_t * mpeg2; int progressive_count = 0; + int interlacing[10]; + int ar16_count = 0, ar4_count = 0; buf_ps = hb_buffer_init( HB_DVD_READ_BUFFER_SIZE ); @@ -419,7 +421,7 @@ */ if( progressive_count == 6 ) { - hb_log("Title's mostly progressive NTSC, setting fps to 23.976"); + hb_log("Title's mostly NTSC Film, setting fps to 23.976"); } title->rate_base = 1126125; } @@ -449,7 +451,19 @@ } buf_raw = hb_list_item( list_raw, 0 ); - + + /* Check preview for interlacing artifacts */ + if( hb_detect_comb(buf_raw, title->width, title->height, 10, 30, 9) ) + { + hb_log("Interlacing detected in preview frame %i", i); + interlacing[i] = 1; + } + else + { + interlacing[i] = 0; + } + + hb_get_tempory_filename( data->h, filename, "%x%d", (intptr_t)title, i ); @@ -522,7 +536,28 @@ (float) title->rate_base, title->crop[0], title->crop[1], title->crop[2], title->crop[3], title->aspect == HB_ASPECT_BASE * 16 / 9 ? "16:9" : - title->aspect == HB_ASPECT_BASE * 4 / 3 ? "4:3" : "none" ); + title->aspect == HB_ASPECT_BASE * 4 / 3 ? "4:3" : "none" ); + + /* Add up how many previews were interlaced.*/ + int interlacing_sum, t; + for(t = 0; t < 10; t++ ) + { + if( interlacing[t] == 1 ) + { + interlacing_sum++; + } + } + + if( interlacing_sum >= 6) + { + hb_log("Title is mostly interlaced or telecined (%i out of 10 previews). You should do something about that.", interlacing_sum); + title->detected_interlacing = 1; + } + else + { + title->detected_interlacing = 0; + } + goto cleanup; error: Index: libhb/common.h =================================================================== --- libhb/common.h (revision 1336) +++ libhb/common.h (working copy) @@ -426,6 +426,7 @@ int rate; int rate_base; int crop[4]; + int detected_interlacing; uint32_t palette[16];