This adds some bug fixes and improves the analysis portion of the YAIT filter (Yet Another Inverse Telecine) filter. I haven't looked at this code for about two years, but I guess I never submitted the last version of it. The code that was present in v1.1.0 is really old and buggy.
The analysis tool is still an external command line tool. Eventually it will be moved into the filter itself. Eventually. And code style fixes. Also eventually. Heh. Allan
diff -ru old/filter/filter_yait.c new/filter/filter_yait.c --- old/filter/filter_yait.c 2007-05-26 11:52:10.000000000 -0400 +++ new/filter/filter_yait.c 2009-01-27 01:07:21.000000000 -0500 @@ -694,8 +694,12 @@ while( *str ) { c = *str++; - if( c>='1' && c<='5' ) + if( c>='0' && c<='5' ) { + if( c == '0' ) + /* no operation */ + continue; + op |= Y_OP_DEINT; if( mode ) *mode = c - '0'; diff -ru old/tools/tcyait.c new/tools/tcyait.c --- old/tools/tcyait.c 2007-07-04 04:55:47.000000000 -0400 +++ new/tools/tcyait.c 2009-01-27 01:15:33.000000000 -0500 @@ -31,11 +31,19 @@ * Yet Another Inverse Telecine filter. * * Usage: - * tcyait [-d] [-l log] [-o ops] [-m mode] - * -d print debug info to stdout - * -l log specify input yait log file name - * -o ops specify output yait frame operations file name - * -m mode specify transcode de-interlace method to use + * tcyait [-dnlotbwmEO] [arg...] + * -d Print debug information to stdout + * -n Do not drop frames, always de-interlace + * -k No forced keep frames + * -l log Input yait log file name + * -o ops Output yait frame ops file name + * -t thresh Interlace detection threshold (>1) + * -b blend forced blend threshold (>thresh) + * -w size Drop frame look ahead window (0-20) + * -m mode Transcode blend method (0-5) + * -E thresh Even pattern threhold [thresh] + * -O thresh Odd pattern threhold [thresh] + * -N noise minimum normalized delta, else considered noise * * By default, reads "yait.log" and produces "yait.ops". * @@ -49,7 +57,7 @@ */ -#define YAIT_VERSION "v0.1" +#define YAIT_VERSION "v0.2" #define TRUE 1 #define FALSE 0 @@ -57,15 +65,25 @@ /* program defaults */ #define Y_LOG_FN "yait.log" /* log file read */ #define Y_OPS_FN "yait.ops" /* frame operation file written */ +#define Y_THRESH 1.2 /* even/odd ratio to detect interlace */ +#define Y_DROPWIN_SIZE 15 /* drop frame look ahead window */ #define Y_DEINT_MODE 3 /* default transcode de-interlace mode */ -#define Y_THRESH 1.1 /* even/odd ratio to detect interlace */ +/* limits */ +#define Y_DEINT_MIN 0 +#define Y_DEINT_MAX 5 +#define Y_DROPWIN_MIN 0 +#define Y_DROPWIN_MAX 60 + #define Y_MTHRESH 1.02 /* minimum ratio allowing de-interlace */ -#define Y_WEIGHT 0.001 /* normalized delta to filter ratio noise */ +#define Y_NOISE 0.003 /* normalized delta too weak, noise */ +#define Y_SCENE_CHANGE 0.15 /* normalized delta > 15% of max delta */ -#define Y_FTHRESH 1.4 /* force de-interlace if over this ratio */ -#define Y_FWEIGHT 0.01 /* force de-interlace if over this weight */ +/* force de-interlace */ +#define Y_FBLEND 1.6 /* if ratio is > this */ +#define Y_FWEIGHT 0.01 /* if over this weight */ +/* frame operation flags */ #define Y_OP_ODD 0x10 #define Y_OP_EVEN 0x20 #define Y_OP_PAT 0x30 @@ -93,6 +111,7 @@ double r; /* even/odd delta ratio, filtered */ double ro; /* ratio, original value */ double w; /* statistical strength */ + double nd; /* normalized delta */ int fn; /* frame number */ int ed; /* even row delta */ int od; /* odd row delta */ @@ -112,8 +131,16 @@ char *Prog; /* argv[0] */ char *LogFn; /* log file name, default "yait.log" */ char *OpsFn; /* ops file name, default "yait.ops" */ +double Thresh; /* row delta ratio interlace detection threshold */ +double EThresh; /* even interlace detection threshold */ +double OThresh; /* odd interlace detection threshold */ +double Blend; /* force frame blending over this threshold */ +double Noise; /* minimum normalized delta */ +int DropWin; /* drop frame look ahead window */ int DeintMode; /* transcode de-interlace mode, (1-5) */ int DebugFi; /* dump debug frame info */ +int NoDrops; /* force de-interlace everywhere (non vfr) */ +int NoKeeps; /* Don't force keep frames (allows a/v sync drift) */ FILE *LogFp; /* log file */ FILE *OpsFp; /* ops file */ @@ -121,11 +148,19 @@ Fi *Fl; /* frame list */ Fi **Fa; /* frame array */ Fi **Ga; /* group array */ +int *Da; /* drop count array */ int Nf; /* number of frames */ -int Ng; /* number of frames in group */ -int Nd; /* number of frames dropped */ +int Ng; /* number of elements in Ga */ +int Nd; /* number of elements in Da */ int Md; /* max delta */ +int Stat_nd; /* total number of dropped frames */ +int Stat_nb; /* total number of blended frames */ +int Stat_no; /* total number of odd interlaced pairs */ +int Stat_ne; /* total number of even interlaced pairs */ +int Stat_fd; /* total number of forced drops */ +int Stat_fk; /* total number of forced keeps */ + /* * protos: @@ -140,10 +175,10 @@ static void yait_chk_ip( int ); static void yait_chk_pairs( int ); static void yait_chk_tuplets( int ); -static int yait_find_odd( double, int, double* ); -static int yait_find_even( double, int, double* ); -static int yait_ffmin( int ); -static int yait_ffmax( int ); +static int yait_find_odd( double, int, double*, int ); +static int yait_find_even( double, int, double*, int ); +static int yait_ffmin( int, int ); +static int yait_ffmax( int, int ); static int yait_m5( int ); static void yait_mark_grp( int, int, double ); static void yait_find_drops( void ); @@ -162,6 +197,7 @@ static void yait_deint( void ); static void yait_write_ops( void ); static char *yait_write_op( Fi* ); +static void yait_fini( void ); static void yait_debug_fi( void ); static char *yait_op( int op ); @@ -210,11 +246,14 @@ /* let transcode de-interlace frames we missed */ yait_deint(); + /* print frame ops file */ + yait_write_ops(); + if( DebugFi ) yait_debug_fi(); - /* print frame ops file */ - yait_write_ops(); + /* graceful exit */ + yait_fini(); return( 0 ); } @@ -232,7 +271,13 @@ LogFn = Y_LOG_FN; OpsFn = Y_OPS_FN; + Thresh = Y_THRESH; + EThresh = 0; + OThresh = 0; + Blend = Y_FBLEND; + Noise = Y_NOISE; DeintMode = Y_DEINT_MODE; + DropWin = Y_DROPWIN_SIZE; --argc; Prog = *argv++; @@ -247,6 +292,14 @@ DebugFi = TRUE; break; + case 'n': + NoDrops = TRUE; + break; + + case 'k': + NoKeeps = TRUE; + break; + case 'l': yait_chkac( &argc ); LogFn = *++argv; @@ -257,6 +310,36 @@ OpsFn = *++argv; break; + case 't': + yait_chkac( &argc ); + Thresh = atof( *++argv ); + break; + + case 'E': + yait_chkac( &argc ); + EThresh = atof( *++argv ); + break; + + case 'O': + yait_chkac( &argc ); + OThresh = atof( *++argv ); + break; + + case 'b': + yait_chkac( &argc ); + Blend = atof( *++argv ); + break; + + case 'N': + yait_chkac( &argc ); + Noise = atof( *++argv ); + break; + + case 'w': + yait_chkac( &argc ); + DropWin = atoi( *++argv ); + break; + case 'm': yait_chkac( &argc ); DeintMode = atoi( *++argv ); @@ -270,6 +353,35 @@ argv++; } + if( Thresh <= 1 ) + { + printf( "Invalid threshold specified (%g).\n\n", Thresh ); + yait_usage(); + } + + if( Blend <= Thresh ) + { + printf( "Invalid blend threshold specified (%g).\n\n", Blend ); + yait_usage(); + } + + if( DropWin<Y_DROPWIN_MIN || DropWin>Y_DROPWIN_MAX ) + { + printf( "Invalid drop window size specified (%d).\n\n", DropWin ); + yait_usage(); + } + + if( DeintMode<Y_DEINT_MIN || DeintMode>Y_DEINT_MAX ) + { + printf( "Invalid de-interlace method specified (%d).\n\n", DeintMode ); + yait_usage(); + } + + if( !EThresh ) + EThresh = Thresh; + if( !OThresh ) + OThresh = Thresh; + if( argc ) yait_usage(); } @@ -295,11 +407,20 @@ static void yait_usage( void ) { - printf( "Usage: %s [-d] [-l log] [-o ops] [-m mode]\n", Prog ); + printf( "Usage: %s [-dnklotbwmEON] [arg...] \n", Prog ); printf( "\t-d\t\tPrint debug information to stdout.\n" ); - printf( "\t-l log\t\tSpecify input yait log file name [yait.log].\n" ); - printf( "\t-o ops\t\tSpecify output yait frame ops file name [yait.ops].\n" ); - printf( "\t-m mode\t\tSpecify transcode de-interlace method [3].\n\n" ); + printf( "\t-n\t\tDo not drop frames, always de-interlace.\n" ); + printf( "\t-k\t\tNo forced keep frames.\n" ); + printf( "\t-l log\t\tInput yait log file name [%s].\n", Y_LOG_FN ); + printf( "\t-o ops\t\tOutput yait frame ops file name [%s].\n", Y_OPS_FN ); + printf( "\t-t thresh\tInterlace detection threshold (>1) [%g].\n", Y_THRESH ); + printf( "\t-b blend\tforced blend threshold (>thresh) [%g].\n", Y_FBLEND ); + printf( "\t-w size\t\tDrop frame look ahead window (0-20) [%d].\n", Y_DROPWIN_SIZE ); + printf( "\t-m mode\t\tTranscode blend method (0-5) [%d].\n", Y_DEINT_MODE ); + printf( "\t-E thresh\tEven pattern threshold [%g].\n", Y_THRESH ); + printf( "\t-O thresh\tOdd pattern threshold [%g].\n", Y_THRESH ); + printf( "\t-N noise\tMinimum normalized delta, else noise [%g].\n", Y_NOISE ); + printf( "\n" ); exit( 1 ); } @@ -362,9 +483,13 @@ exit( 1 ); } + /* number of 5 frame groups */ + Nd = Nf / 5; + Fa = (Fi**) malloc( (Nf+1) * sizeof(Fi*) ); Ga = (Fi**) malloc( (Nf+1) * sizeof(Fi*) ); - if( !Fa || !Ga ) + Da = (int*) malloc( Nd * sizeof(int) ); + if( !Fa || !Ga || !Da ) { perror( "malloc" ); exit( 1 ); @@ -437,7 +562,9 @@ static double yait_calc_ratio( int ed, int od ) { - double r = 0.0; + double r; + + r = 1; /* compute ratio, >1 odd, <-1 even */ if( !ed && !od ) @@ -486,17 +613,18 @@ int m, p, i; /* mark obvious drop frames */ - for( i=1; i<Nf-1; i++ ) - { - f = Fa[i]; - if( f->r ) - continue; + if( !NoDrops ) + for( i=1; i<Nf-1; i++ ) + { + f = Fa[i]; + if( f->r ) + continue; - if( !Fa[i-1]->r && !Fa[i+1]->r ) - continue; + if( !Fa[i-1]->r && !Fa[i+1]->r ) + continue; - f->drop = TRUE; - } + f->drop = TRUE; + } /* create group array, ommiting drops */ Ng = 0; @@ -529,12 +657,14 @@ exit( 1 ); } + /* compute normalized row deltas and */ /* filter out weak r values (noise) */ for( i=0; i<Ng; i++ ) { f = Ga[i]; - if( (f->ed + f->od) / (double) Md < Y_WEIGHT ) - f->r = 0; + f->nd = (f->ed + f->od) / (double) Md; + if( f->nd < Noise ) + f->r = 1; } /* adjust for incomplete interleave patterns */ @@ -553,14 +683,14 @@ continue; } - p = yait_find_odd( Y_THRESH, i, &w ); + p = yait_find_odd( OThresh, i, &w, 4 ); if( p != -1 ) { yait_mark_grp( p, i, w ); continue; } - p = yait_find_even( Y_THRESH, i, &w ); + p = yait_find_even( EThresh, i, &w, 4 ); if( p != -1 ) yait_mark_grp( p+10, i, w ); } @@ -577,7 +707,9 @@ static void yait_chk_ip( int n ) { - yait_chk_pairs( n ); + if( !NoDrops ) + yait_chk_pairs( n ); + yait_chk_tuplets( n ); } @@ -607,15 +739,15 @@ } for( i=2; i<4; i++ ) - if( ra[i] < Y_THRESH ) + if( ra[i] < Thresh ) return; /* adjacent frames to the tuplet must be <thresh */ - if( ra[1]>Y_THRESH || ra[4]>Y_THRESH ) + if( ra[1]>Thresh || ra[4]>Thresh ) return; /* we only need one edge frame to be <thresh */ - if( ra[0]>Y_THRESH && ra[5]>Y_THRESH ) + if( ra[0]>Thresh && ra[5]>Thresh ) return; if( fa[2]->r>0 && fa[3]->r>0 ) @@ -626,8 +758,8 @@ /* two isolated high r values of opposite sign */ /* drop the interlaced frame, erase the pattern */ - fa[2]->r = 0; - fa[3]->r = 0; + fa[2]->r = 1; + fa[3]->r = 1; fa[2]->drop = TRUE; } @@ -660,15 +792,15 @@ } for( i=2; i<5; i++ ) - if( ra[i] < Y_THRESH ) + if( ra[i] < Thresh ) return; /* adjacent frames to the tuplet must be <thresh */ - if( ra[1]>Y_THRESH || ra[5]>Y_THRESH ) + if( ra[1]>Thresh || ra[5]>Thresh ) return; /* we only need one edge frame to be <thresh */ - if( ra[0]>Y_THRESH && ra[6]>Y_THRESH ) + if( ra[0]>Thresh && ra[6]>Thresh ) return; if( fa[2]->r>0 && fa[4]->r>0 ) @@ -679,7 +811,7 @@ /* isolated tuplet of high r values of opposite sign */ if( ra[3]>ra[2] || ra[3]>ra[4] ) - fa[3]->r = 0; + fa[3]->r = 1; } @@ -688,7 +820,7 @@ */ static int -yait_find_odd( double thresh, int n, double *w ) +yait_find_odd( double thresh, int n, double *w, int win ) { double re, ro; int me, mo; @@ -696,8 +828,8 @@ /* find max even/odd correlations */ /* (r<0 - even, r>0 - odd) */ - me = yait_ffmin( n ); - mo = yait_ffmax( n ); + me = yait_ffmin( n, win ); + mo = yait_ffmax( n, win ); p = -1; if( yait_m5(mo-2) == yait_m5(me) ) @@ -707,7 +839,8 @@ if( re>thresh && ro>thresh ) { p = yait_m5( mo - 4 ); - *w = re + ro; + if( w ) + *w = re + ro; } } @@ -720,14 +853,14 @@ */ static int -yait_find_even( double thresh, int n, double *w ) +yait_find_even( double thresh, int n, double *w, int win ) { double re, ro; int me, mo; int p; - me = yait_ffmin( n ); - mo = yait_ffmax( n ); + me = yait_ffmin( n, win ); + mo = yait_ffmax( n, win ); p = -1; if( yait_m5(me-2) == yait_m5(mo) ) @@ -737,7 +870,8 @@ if( re>thresh && ro>thresh ) { p = yait_m5( me - 4 ); - *w = re + ro; + if( w ) + *w = re + ro; } } @@ -750,7 +884,7 @@ */ static int -yait_ffmin( int n ) +yait_ffmin( int n, int w ) { Fi *f; int m, i; @@ -758,7 +892,7 @@ r = 0; m = 0; - for( i=n; i<n+4; i++ ) + for( i=n; i<n+w; i++ ) { if( i < 0 ) break; @@ -783,7 +917,7 @@ */ static int -yait_ffmax( int n ) +yait_ffmax( int n, int w ) { Fi *f; int m, i; @@ -791,7 +925,7 @@ r = 0; m = 0; - for( i=n; i<n+4; i++ ) + for( i=n; i<n+w; i++ ) { if( i < 0 ) break; @@ -826,13 +960,29 @@ /* * yait_mark_grp: + * Try to catch the situation where a progressive frame is missing + * between interlace groups. This will cause an erroneous (opposite) ip + * pattern to be detected. The first sequence shown below is a normal (odd) + * telecine pattern. The second shows what happens when a progressive frame + * is missing. We want to reject the even pattern detected. Therefore, if + * we find an identical pattern at n+4 we keep it. If not, we reject if an + * opposite pattern follows at n+2 of greater weight. + * + * n: 0 1 2 3 4 0 1 2 3 4 + * r: 0 -1 0 1 0 0 -1 0 1 0 + * odd odd + * + * n: 0 1 2 3 4 1 2 3 4 + * r: 0 -1 0 1 0 -1 0 1 0 + * odd even odd */ static void yait_mark_grp( int p, int n, double w ) { Fi *f; - int t, i; + double nw; + int np, t, i; if( n%5 != (p+2)%5 ) return; @@ -842,6 +992,30 @@ if( w <= f->w ) return; + /* check for same pattern at n+4 */ + if( p < 10 ) + np = yait_find_odd( OThresh, n+4, NULL, 5 ); + else + np = yait_find_even( EThresh, n+4, NULL, 5 ); + if( np < 0 ) + { + /* no pattern at n+4, reject if opposite ip at n+2 */ + if( p < 10 ) + np = yait_find_even( EThresh, n+2, &nw, 5 ); + else + np = yait_find_odd( OThresh, n+2, &nw, 5 ); + + if( np>=0 && nw>w ) + return; + } + + /* erase previous pattern */ + if( n > 1 ) + { + Ga[n-1]->op = 0; + Ga[n-2]->op = 0; + } + /* this frame and next are interlaced */ t = (p < 10) ? Y_OP_ODD : Y_OP_EVEN; f->op = t | Y_OP_SAVE | Y_OP_DROP; @@ -851,7 +1025,7 @@ /* assume 1 progressive on either side of the tuplet */ for( i=n-1; i<n+4; i++ ) { - if( i<0 || i>Ng-1 ) + if( i<0 || i>=Ng ) continue; f = Ga[i]; @@ -864,9 +1038,9 @@ /* * yait_find_drops: * For every group of 5 frames, make sure we drop a frame. Allow up to a - * 4 group lookahead to make up for extra or missing drops. (The duplicated frames - * generated by --hard_fps can be quite early or late in the sequence). If a group - * requires a drop, but none exists, mark the group as requiring de-interlacing. + * DropWin (default 15) group lookahead to make up for extra or missing drops. (The + * duplicated frames generated by --hard_fps can be quite early or late in the sequence). + * If a group requires a drop, but none exists, mark the group as requiring de-interlacing. * Finally, consequetive marked groups inherit surrounding interleave patterns. * * Each group will receive one of the following flags: @@ -893,85 +1067,72 @@ yait_find_drops( void ) { Fi *f; - int ed; - int d, n; + int d, l; - /* running count of extra drops */ - ed = 0; + /* populate drop counts */ + for( d=0; d<Nd; d++ ) + Da[d] = yait_cnt_drops( d*5 ); - /* process by groups of 5 */ - for( n=0; n<Nf; n+=5 ) + /* balance drop counts restricted by window size */ + for( d=0; d<Nd; d++ ) { - f = Fa[n]; + f = Fa[d*5]; - /* get number of drops */ - d = yait_cnt_drops( n ); - - /* we can't really handle this well, so force the keep of frames */ - /* until we have only two extra drops */ - while( d > 2 ) + /* this is what we want to see */ + if( Da[d] == 1 ) { - yait_keep_frame( n ); - d = yait_cnt_drops( n ); + if( !f->gf ) + f->gf = Y_HAS_DROP; + continue; } - /* no drops in group */ - if( !d ) + /* group is missing a drop? */ + if( !Da[d] ) { - if( ed > 0 ) - { - /* an extra drop was available */ - f->gf = Y_WITHDRAW_DROP; - --ed; - continue; - } - /* look ahead for an extra drop */ - d = yait_extra_drop( n ); - if( d ) + l = yait_extra_drop( d ); + if( l ) { - /* consume the next extra drop */ + /* found one */ + Da[d]++; f->gf = Y_BORROW_DROP; - --ed; + + --Da[l]; + Fa[l*5]->gf = Y_RETURN_DROP; continue; } - /* mark group to be de-interlaced */ + /* no extra drops exist, mark for de-interlacing */ f->gf = Y_FORCE_DEINT; - continue; } - /* extra drop exists */ - if( d > 1 ) + /* we have too many drops */ + while( Da[d] > 1 ) { - if( ed < 0 ) - { - /* we needed it */ - f->gf = Y_RETURN_DROP; - ed++; - continue; - } + --Da[d]; /* look ahead for a missing drop */ - d = yait_missing_drop( n ); - if( d ) + l = yait_missing_drop( d ); + if( l ) { - /* we can use it later */ + /* found one */ f->gf = Y_BANK_DROP; - ed++; + + Da[l]++; + Fa[l*5]->gf = Y_WITHDRAW_DROP; continue; } - /* we can't use an extra drop, keep one */ - f->gf = Y_FORCE_KEEP; - yait_keep_frame( n ); + /* we have to keep a drop */ + if( !NoKeeps ) + { + f->gf = Y_FORCE_KEEP; + yait_keep_frame( d*5 ); - continue; + Stat_fk++; + } } - - /* group has a single drop frame */ - f->gf = Y_HAS_DROP; } } @@ -1000,66 +1161,49 @@ /* * yait_extra_drop: - * Scan four groups ahead for an extra drop. + * Scan DropWin groups ahead for an extra drop. */ static int -yait_extra_drop( int n ) +yait_extra_drop( int d ) { - int da[4], d, e, g, i; + int l, w; - d = 0; - for( g=0; g<4; g++ ) + for( w=0; w<DropWin; w++ ) { - i = n + (g+1) * 5; - da[g] = yait_cnt_drops( i ); - d += da[g]; - } - - if( d < 5 ) - return( FALSE ); + l = d + w + 1; + if( l >= Nd ) + return( 0 ); - /* find group with the extra drop */ - for( e=0; e<4; e++ ) - if( da[e] > 1 ) - break; - - /* make sure extra drop wouldn't be accounted for */ - d = 0; - for( g=0; g<3; g++ ) - { - i = n + ((e+1)+(g+1)) * 5; - d += yait_cnt_drops( i ); + if( Da[l] > 1 ) + return( l ); } - if( d < 3 ) - return( FALSE ); - - return( TRUE ); + return( 0 ); } /* * yait_missing_drop: - * Scan four groups ahead for a missing drop. + * Scan DropWin groups ahead for a missing drop. */ static int -yait_missing_drop( int n ) +yait_missing_drop( int d ) { - int d, g, i; + int l, w; - d = 0; - for( g=0; g<4; g++ ) + for( w=0; w<DropWin; w++ ) { - i = n + (g+1) * 5; - d += yait_cnt_drops( i ); - } + l = d + w + 1; + if( l >= Nd ) + return( 0 ); - if( d > 3 ) - return( FALSE ); + if( !Da[l] ) + return( l ); + } - return( TRUE ); + return( 0 ); } @@ -1116,7 +1260,7 @@ f = Fa[d-1]; if( f->drop ) - /* sheesh, two dups in a row */ + /* two dups in a row */ f = Fa[d-2]; if( !f->op ) @@ -1231,6 +1375,8 @@ fd = Fa[d]; fp = Fa[d-1]; + if( fp->drop ) + fp = Fa[d-2]; if( fp->op & Y_OP_COPY ) { @@ -1442,7 +1588,8 @@ } } - Fa[ (mr>Y_THRESH)?fr:fd ]->drop = TRUE; + Fa[ (mr>Thresh)?fr:fd ]->drop = TRUE; + Stat_fd++; } @@ -1467,7 +1614,7 @@ /* yait_tst_ip() returns the sum of two ratios */ /* we want both ratios > Y_MTHRESH */ thresh = Y_MTHRESH * 2; - if( m1<thresh && m2<thresh ) + if( !NoDrops && m1<thresh && m2<thresh ) /* neither pattern matches, force a drop instead */ return( -1 ); @@ -1573,86 +1720,57 @@ * pattern interlace frames solely on row delta information. Perhaps we should * have built 32detect into the log generation, and added an extra flag field if * we thought the frame was interlaced. This also would help when trying to - * assign ambiguous ip patterns. Unfortunately, the affect I see when I tell - * transcode to de-interlace are horribly encoded frames, as though the bit - * rate drops down to nothing. So, more investigation is required. - * - * Also, sequences of requested frame blending usually indicate a - * problem. The ip pattern was not detected correctly. This is especially - * true when a progressive frame is missing. For example: - * - * Normal (odd) case: - * 0 -1 0 1 0 0 -1 0 1 0 - * odd odd - * - * Missing frame: - * 0 -1 0 1 0 -1 0 1 0 - * odd even deint - * - * Because a frame was missing, an even interlace pattern was - * erroneously determined, which then causes the last two frames of the - * sequence to be blended. I'm currently stumped here. I usually examine - * the original video and edit the .ops file directly to correct the problem. + * assign ambiguous ip patterns. */ static void yait_deint( void ) { - Fi *f1, *f2, *f; - int os, i; + Fi *fp, *fn, *f; + int i; - for( i=1; i<Ng-2; i++ ) + for( i=1; i<Ng-1; i++ ) { + fp = Ga[i-1]; f = Ga[i]; + fn = Ga[i+1]; if( f->op&Y_OP_PAT || f->drop ) /* already being de-interlaced or dropped */ continue; - if( fabs(f->r) < Y_FTHRESH ) + if( fp->op & Y_OP_PAT ) + /* trailing element of a tuplet */ + continue; + + if( fabs(f->r) < Blend ) /* it isn't interlaced (we think) */ continue; - if( (f->ed + f->od) / (double) Md < Y_FWEIGHT ) + if( f->nd < Y_FWEIGHT ) /* delta is too weak, interlace is likely not visible */ continue; - f1 = Ga[i+1]; - f2 = Ga[i+2]; - - /* kludge: if this is the trailing frame of an ip tuplet, then */ - /* only de-interlace if a high ratio exists within the next two */ - /* frames and are not accounted for */ - if( Ga[i-1]->op & Y_OP_PAT ) - { - if( fabs(f1->r)<Y_THRESH && fabs(f2->r)<Y_THRESH ) - continue; - - if( f1->op&Y_OP_PAT || f2->op&Y_OP_PAT ) - continue; - - /* looks like we made a bad choice for the ip pattern */ - /* too late now, so just blend frames */ - } - - /* set os true if next frame has opposite sign ratio */ - os = (f->r*f1->r < 0) ? TRUE : FALSE; - - /* only reject now if next frame has same sign > thresh */ - if( !os && fabs(f1->r)>Y_THRESH ) + if( fp->nd>Y_SCENE_CHANGE || f->nd>Y_SCENE_CHANGE ) + /* can't make a decision over scene changes */ continue; /* this frame is interlaced with no operation assigned */ f->op = Y_OP_DEINT; - /* if the next frame ratio < thresh, it is similar and */ - /* therefore interlaced as well (probably) */ - if( fabs(f1->r) < Y_FTHRESH ) - if( !(f1->op&Y_OP_PAT) && !f1->drop ) - f1->op = Y_OP_DEINT; - - /* skip next */ - i++; + /* if the next frame ratio < thresh, it is similar, unless */ + /* a scene change, therefore interlaced as well */ + if( fabs(fn->r)<Thresh && fn->nd<Y_SCENE_CHANGE ) + if( !(fn->op&Y_OP_PAT) && !fn->drop ) + fn->op = Y_OP_DEINT; + + /* if the next frame(s) are duplicates of this, mark them */ + /* for blending as well, as the may eventually be force kept */ + while( f->next && !f->next->gi ) + { + f = f->next; + f->op = Y_OP_DEINT; + } } } @@ -1687,7 +1805,7 @@ { *p++ = 'd'; *p = 0; - Nd++; + Stat_nd++; return( buf ); } @@ -1703,10 +1821,17 @@ if( op & Y_OP_DROP ) { *p++ = 'd'; - Nd++; + Stat_nd++; + if( op & Y_OP_ODD ) + Stat_no++; + else + Stat_ne++; } if( op & Y_OP_DEINT ) + { *p++ = '0' + DeintMode; + Stat_nb++; + } *p = 0; return( buf ); @@ -1714,6 +1839,25 @@ /* + * yait_fini: + * Free up allocations. + */ + +static void +yait_fini( void ) + { + int i; + + for( i=0; i<Nf; i++ ) + free( Fa[i] ); + + free( Fa ); + free( Ga ); + free( Da ); + } + + +/* * Output debug information to stdout */ @@ -1723,6 +1867,26 @@ Fi *f; int i; + printf( "Options:\n" ); + printf( "\tLog file: %s\n", LogFn ); + printf( "\tOps file: %s\n", OpsFn ); + printf( "\tEven Threshold: %g\n", EThresh ); + printf( "\tOdd Threshold: %g\n", OThresh ); + printf( "\tBlend threshold: %g\n", Blend ); + printf( "\tDrop window size: %d\n", DropWin ); + printf( "\tDe-interlace mode: %d\n\n", DeintMode ); + + printf( "Stats:\n" ); + printf( "\tTotal number of frames: %d\n", Nf ); + printf( "\tNumber of frames divided by 5: %d\n", Nf/5 ); + printf( "\tTotal dropped frames: %d\n", Stat_nd ); + printf( "\tTotal blended frames: %d\n", Stat_nb ); + printf( "\tTotal odd interlaced pairs: %d\n", Stat_no ); + printf( "\tTotal even interlaced pairs: %d\n", Stat_ne ); + printf( "\tNumber of forced frame drops: %d\n", Stat_fd ); + printf( "\tNumber of forced frame keeps: %d\n\n", Stat_fk ); + printf( "\tMax row delta: %d\n\n", Md ); + i = 0; for( f=Fl; f; f=f->next, i++ ) {