1 /*
2 * tcyait.c
3 *
4 * Copyright (C) Allan Snider - February 2007
5 *
6 * This file is part of transcode, a video stream processing tool
7 *
8 * transcode is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * transcode is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with GNU Make; see the file COPYING. If not, write to
20 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <math.h>
28
29 /*
30 * tcyait:
31 * Yet Another Inverse Telecine filter.
32 *
33 * Usage:
34 * tcyait [-dnlotbwmEO] [arg...]
35 * -d Print debug information to stdout
36 * -n Do not drop frames, always de-interlace
37 * -k No forced keep frames
38 * -l log Input yait log file name
39 * -o ops Output yait frame ops file name
40 * -t thresh Interlace detection threshold (>1)
41 * -b blend forced blend threshold (>thresh)
42 * -w size Drop frame look ahead window (0-20)
43 * -m mode Transcode blend method (0-5)
44 * -E thresh Even pattern threhold [thresh]
45 * -O thresh Odd pattern threhold [thresh]
46 * -N noise minimum normalized delta, else considered noise
47 *
48 * By default, reads "yait.log" and produces "yait.ops".
49 *
50 * Description:
51 *
52 * Read a yait log file (generated via -J yait=log), and analyze it to
53 * produce a yait frame operations file. The frame operations file contains
54 * commands to the yait filter to drop, copy or save rows (to de-interlace),
55 * or blend frames. This will convert from NTSC 29.97 to 23.976 fps. The file
56 * generated is used as input for another transcode pass (-J yait=ops).
57 */
58
59
60 #define YAIT_VERSION "v0.2"
61
62 #define TRUE 1
63 #define FALSE 0
64
65 /* program defaults */
66 #define Y_LOG_FN "yait.log" /* log file read */
67 #define Y_OPS_FN "yait.ops" /* frame operation file written */
68 #define Y_THRESH 1.2 /* even/odd ratio to detect interlace */
69 #define Y_DROPWIN_SIZE 15 /* drop frame look ahead window */
70 #define Y_DEINT_MODE 3 /* default transcode de-interlace mode */
71
72 /* limits */
73 #define Y_DEINT_MIN 0
74 #define Y_DEINT_MAX 5
75 #define Y_DROPWIN_MIN 0
76 #define Y_DROPWIN_MAX 60
77
78 #define Y_MTHRESH 1.02 /* minimum ratio allowing de-interlace */
79 #define Y_NOISE 0.003 /* normalized delta too weak, noise */
80 #define Y_SCENE_CHANGE 0.15 /* normalized delta > 15% of max delta */
81
82 /* force de-interlace */
83 #define Y_FBLEND 1.6 /* if ratio is > this */
84 #define Y_FWEIGHT 0.01 /* if over this weight */
85
86 /* frame operation flags */
87 #define Y_OP_ODD 0x10
88 #define Y_OP_EVEN 0x20
89 #define Y_OP_PAT 0x30
90
91 #define Y_OP_NOP 0x0
92 #define Y_OP_SAVE 0x1
93 #define Y_OP_COPY 0x2
94 #define Y_OP_DROP 0x4
95 #define Y_OP_DEINT 0x8
96
97 /* group flags */
98 #define Y_HAS_DROP 1
99 #define Y_BANK_DROP 2
100 #define Y_WITHDRAW_DROP 3
101 #define Y_BORROW_DROP 4
102 #define Y_RETURN_DROP 5
103 #define Y_FORCE_DEINT 6
104 #define Y_FORCE_DROP 7
105 #define Y_FORCE_KEEP 8
106
107 /* frame information */
108 typedef struct fi_t Fi;
109 struct fi_t
110 {
111 double r; /* even/odd delta ratio, filtered */
112 double ro; /* ratio, original value */
113 double w; /* statistical strength */
114 double nd; /* normalized delta */
115 int fn; /* frame number */
116 int ed; /* even row delta */
117 int od; /* odd row delta */
118 int gi; /* group array index */
119 int ip; /* telecine pattern */
120 int op; /* frame operation, nop, save/copy row */
121 int drop; /* frame is to be dropped */
122 int gf; /* group flag */
123 Fi *next;
124 };
125
126
127 /*
128 * globals:
129 */
130
131 char *Prog; /* argv[0] */
132 char *LogFn; /* log file name, default "yait.log" */
133 char *OpsFn; /* ops file name, default "yait.ops" */
134 double Thresh; /* row delta ratio interlace detection threshold */
135 double EThresh; /* even interlace detection threshold */
136 double OThresh; /* odd interlace detection threshold */
137 double Blend; /* force frame blending over this threshold */
138 double Noise; /* minimum normalized delta */
139 int DropWin; /* drop frame look ahead window */
140 int DeintMode; /* transcode de-interlace mode, (1-5) */
141 int DebugFi; /* dump debug frame info */
142 int NoDrops; /* force de-interlace everywhere (non vfr) */
143 int NoKeeps; /* Don't force keep frames (allows a/v sync drift) */
144
145 FILE *LogFp; /* log file */
146 FILE *OpsFp; /* ops file */
147
148 Fi *Fl; /* frame list */
149 Fi **Fa; /* frame array */
150 Fi **Ga; /* group array */
151 int *Da; /* drop count array */
152 int Nf; /* number of frames */
153 int Ng; /* number of elements in Ga */
154 int Nd; /* number of elements in Da */
155 int Md; /* max delta */
156
157 int Stat_nd; /* total number of dropped frames */
158 int Stat_nb; /* total number of blended frames */
159 int Stat_no; /* total number of odd interlaced pairs */
160 int Stat_ne; /* total number of even interlaced pairs */
161 int Stat_fd; /* total number of forced drops */
162 int Stat_fk; /* total number of forced keeps */
163
164
165 /*
166 * protos:
167 */
168
169 static void yait_parse_args( int, char** );
170 static void yait_chkac( int* );
171 static void yait_usage( void );
172 static void yait_read_log( void );
173 static double yait_calc_ratio( int, int );
174 static void yait_find_ip( void );
175 static void yait_chk_ip( int );
176 static void yait_chk_pairs( int );
177 static void yait_chk_tuplets( int );
178 static int yait_find_odd( double, int, double*, int );
179 static int yait_find_even( double, int, double*, int );
180 static int yait_ffmin( int, int );
181 static int yait_ffmax( int, int );
182 static int yait_m5( int );
183 static void yait_mark_grp( int, int, double );
184 static void yait_find_drops( void );
185 static int yait_cnt_drops( int );
186 static int yait_extra_drop( int );
187 static int yait_missing_drop( int );
188 static void yait_keep_frame( int );
189 static int yait_get_hdrop( int, int* );
190 static void yait_ivtc_keep( int );
191 static void yait_ivtc_grps( void );
192 static int yait_scan_bk( int );
193 static int yait_scan_fw( int );
194 static void yait_drop_frame( int );
195 static int yait_ivtc_grp( int, int, int );
196 static double yait_tst_ip( int, int );
197 static void yait_deint( void );
198 static void yait_write_ops( void );
199 static char *yait_write_op( Fi* );
200 static void yait_fini( void );
201
202 static void yait_debug_fi( void );
203 static char *yait_op( int op );
204 static char *yait_drop( Fi *f );
205 static char *yait_grp( int flg );
206
207
208 /*
209 * main:
210 */
211
212 int
main(int argc,char ** argv)213 main( int argc, char **argv )
214 {
215 /* parse args */
216 yait_parse_args( argc, argv );
217
218 LogFp = fopen( LogFn, "r" );
219 if( !LogFp )
220 {
221 perror( "fopen" );
222 fprintf( stderr, "Cannot open YAIT delta log file (%s)\n", LogFn );
223 exit( 1 );
224 }
225
226 OpsFp = fopen( OpsFn, "w" );
227 if( !OpsFp )
228 {
229 perror( "fopen" );
230 fprintf( stderr, "Cannot create YAIT frame ops file (%s)\n", OpsFn );
231 exit( 1 );
232 }
233
234 /* read the log */
235 yait_read_log();
236
237 /* find interleave patterns */
238 yait_find_ip();
239
240 /* find drop frames */
241 yait_find_drops();
242
243 /* complete groups missing an interleave pattern */
244 yait_ivtc_grps();
245
246 /* let transcode de-interlace frames we missed */
247 yait_deint();
248
249 /* print frame ops file */
250 yait_write_ops();
251
252 if( DebugFi )
253 yait_debug_fi();
254
255 /* graceful exit */
256 yait_fini();
257
258 return( 0 );
259 }
260
261
262 /*
263 * yait_parse_args:
264 */
265
266 static void
yait_parse_args(int argc,char ** argv)267 yait_parse_args( int argc, char **argv )
268 {
269 int opt;
270 char *p;
271
272 LogFn = Y_LOG_FN;
273 OpsFn = Y_OPS_FN;
274 Thresh = Y_THRESH;
275 EThresh = 0;
276 OThresh = 0;
277 Blend = Y_FBLEND;
278 Noise = Y_NOISE;
279 DeintMode = Y_DEINT_MODE;
280 DropWin = Y_DROPWIN_SIZE;
281
282 --argc;
283 Prog = *argv++;
284 while( (p = *argv) )
285 {
286 if( *p++ != '-' )
287 break;
288 while( (opt = *p++) )
289 switch( opt )
290 {
291 case 'd':
292 DebugFi = TRUE;
293 break;
294
295 case 'n':
296 NoDrops = TRUE;
297 break;
298
299 case 'k':
300 NoKeeps = TRUE;
301 break;
302
303 case 'l':
304 yait_chkac( &argc );
305 LogFn = *++argv;
306 break;
307
308 case 'o':
309 yait_chkac( &argc );
310 OpsFn = *++argv;
311 break;
312
313 case 't':
314 yait_chkac( &argc );
315 Thresh = atof( *++argv );
316 break;
317
318 case 'E':
319 yait_chkac( &argc );
320 EThresh = atof( *++argv );
321 break;
322
323 case 'O':
324 yait_chkac( &argc );
325 OThresh = atof( *++argv );
326 break;
327
328 case 'b':
329 yait_chkac( &argc );
330 Blend = atof( *++argv );
331 break;
332
333 case 'N':
334 yait_chkac( &argc );
335 Noise = atof( *++argv );
336 break;
337
338 case 'w':
339 yait_chkac( &argc );
340 DropWin = atoi( *++argv );
341 break;
342
343 case 'm':
344 yait_chkac( &argc );
345 DeintMode = atoi( *++argv );
346 break;
347
348 default:
349 yait_usage();
350 break;
351 }
352 --argc;
353 argv++;
354 }
355
356 if( Thresh <= 1 )
357 {
358 printf( "Invalid threshold specified (%g).\n\n", Thresh );
359 yait_usage();
360 }
361
362 if( Blend <= Thresh )
363 {
364 printf( "Invalid blend threshold specified (%g).\n\n", Blend );
365 yait_usage();
366 }
367
368 if( DropWin<Y_DROPWIN_MIN || DropWin>Y_DROPWIN_MAX )
369 {
370 printf( "Invalid drop window size specified (%d).\n\n", DropWin );
371 yait_usage();
372 }
373
374 if( DeintMode<Y_DEINT_MIN || DeintMode>Y_DEINT_MAX )
375 {
376 printf( "Invalid de-interlace method specified (%d).\n\n", DeintMode );
377 yait_usage();
378 }
379
380 if( !EThresh )
381 EThresh = Thresh;
382 if( !OThresh )
383 OThresh = Thresh;
384
385 if( argc )
386 yait_usage();
387 }
388
389
390 /*
391 * yait_chkac:
392 */
393
394 static void
yait_chkac(int * ac)395 yait_chkac( int *ac )
396 {
397 if( *ac < 1 )
398 yait_usage();
399 --*ac;
400 }
401
402
403 /*
404 * yait_usage:
405 */
406
407 static void
yait_usage(void)408 yait_usage( void )
409 {
410 printf( "Usage: %s [-dnklotbwmEON] [arg...] \n", Prog );
411 printf( "\t-d\t\tPrint debug information to stdout.\n" );
412 printf( "\t-n\t\tDo not drop frames, always de-interlace.\n" );
413 printf( "\t-k\t\tNo forced keep frames.\n" );
414 printf( "\t-l log\t\tInput yait log file name [%s].\n", Y_LOG_FN );
415 printf( "\t-o ops\t\tOutput yait frame ops file name [%s].\n", Y_OPS_FN );
416 printf( "\t-t thresh\tInterlace detection threshold (>1) [%g].\n", Y_THRESH );
417 printf( "\t-b blend\tforced blend threshold (>thresh) [%g].\n", Y_FBLEND );
418 printf( "\t-w size\t\tDrop frame look ahead window (0-20) [%d].\n", Y_DROPWIN_SIZE );
419 printf( "\t-m mode\t\tTranscode blend method (0-5) [%d].\n", Y_DEINT_MODE );
420 printf( "\t-E thresh\tEven pattern threshold [%g].\n", Y_THRESH );
421 printf( "\t-O thresh\tOdd pattern threshold [%g].\n", Y_THRESH );
422 printf( "\t-N noise\tMinimum normalized delta, else noise [%g].\n", Y_NOISE );
423 printf( "\n" );
424
425 exit( 1 );
426 }
427
428
429 /*
430 * yait_read_log:
431 */
432
433 static void
yait_read_log(void)434 yait_read_log( void )
435 {
436 Fi **fa, *pf, *f;
437 int fn, ed, od;
438 int s, n;
439
440 s = 0;
441 pf = NULL;
442 for( Nf=0; ; Nf++ )
443 {
444 n = fscanf( LogFp, "%d: e: %d, o: %d\n", &fn, &ed, &od );
445 if( n != 3 )
446 break;
447
448 /* starting frame number */
449 if( !Nf )
450 s = fn;
451
452 if( (fn-s) != Nf )
453 {
454 printf( "Broken log file, line %d\n", Nf );
455 exit( 1 );
456 }
457
458 f = (Fi*) malloc( sizeof(Fi) );
459 if( !f )
460 {
461 perror( "malloc" );
462 exit( 1 );
463 }
464
465 memset( (void*) f, 0, sizeof(Fi) );
466 if( !Fl )
467 Fl = f;
468 if( pf )
469 pf->next = f;
470 pf = f;
471
472 f->r = yait_calc_ratio( ed, od );
473 f->ro = f->r;
474 f->fn = fn;
475 f->ed = ed;
476 f->od = od;
477 f->ip = -1;
478 }
479
480 if( !Fl )
481 {
482 fprintf( stderr, "Invalid log file.\n" );
483 exit( 1 );
484 }
485
486 /* number of 5 frame groups */
487 Nd = Nf / 5;
488
489 Fa = (Fi**) malloc( (Nf+1) * sizeof(Fi*) );
490 Ga = (Fi**) malloc( (Nf+1) * sizeof(Fi*) );
491 Da = (int*) malloc( Nd * sizeof(int) );
492 if( !Fa || !Ga || !Da )
493 {
494 perror( "malloc" );
495 exit( 1 );
496 }
497
498 fa = Fa;
499 for( f=Fl; f; f=f->next )
500 *fa++ = f;
501 *fa = NULL;
502 }
503
504
505 /*
506 * yait_calc_ratio:
507 * Compute a ratio between even/odd row deltas. A high ratio indicates an
508 * interlace present. Use the sign of the ratio to indicate even row (<0), or odd
509 * row (>0) correlation.
510 *
511 * If the magnitude of the ratio is > 1.1, this is usually enough to
512 * indicate interlacing. A value around 1.0 indicates no row correlation at
513 * all.
514 *
515 * Assigning the ratios in this manner result in the following patterns
516 * present for interlaced material. Assume 0 for fabs(r)<thresh, else +/- 1:
517 *
518 * An odd interlace pattern (for a five frame group) would appear as:
519 *
520 * frame: 1 2 3 4 5
521 * even: a a b c d
522 * odd: a b c c d
523 *
524 * ratio: 0 -1 0 1 0
525 *
526 * If we detect this pattern, we assign the following frame operations:
527 *
528 * frame: 1 2 3 4 5
529 * even: a a b c d
530 * odd: a b c c d
531 *
532 * ratio: 0 -1 0 1 0
533 * op: osd oc
534 *
535 * osd = save odd rows and drop the frame
536 * oc = copy in saved odd rows
537 *
538 * This results with:
539 *
540 * frame: 1 |2| 3 4 5
541 * even: a |a| b c d
542 * odd: a |b|--> b c d
543 * drop
544 *
545 * For even interlace patterns, the signs are reversed, or simply:
546 *
547 * ratio: 0 1 0 -1 0
548 * esd ec
549 *
550 * The entire approach of this tool depends on these specific ratio patterns
551 * to be present, and should be for 2:3 pulldown. Lots of complications arise
552 * around still and abrupt scene changes. Again, it might be useful for the
553 * filter to produce a combing co-efficient as well as the delta information.
554 *
555 * Side note:
556 * For yuv, deltas based only on luminance yeilded much stronger
557 * interlace patterns, however, I suppose there are (rare) cases where
558 * chroma could be the only indicator, so chroma is included in the
559 * delta calculation, even though it results in weaker ratios.
560 */
561
562 static double
yait_calc_ratio(int ed,int od)563 yait_calc_ratio( int ed, int od )
564 {
565 double r;
566
567 r = 1;
568
569 /* compute ratio, >1 odd, <-1 even */
570 if( !ed && !od )
571 /* duplicate frame */
572 r = 0;
573
574 if( ed && !od )
575 r = 100;
576
577 if( !ed && od )
578 r = -100;
579
580 if( ed && od )
581 {
582 r = (double) ed / (double) od;
583
584 if( r < 1 )
585 r = -1.0 / r;
586
587 if( r > 100 )
588 r = 100;
589 if( r < -100 )
590 r = -100;
591 }
592
593 return( r );
594 }
595
596
597 /*
598 * yait_find_ip:
599 * - Mark isolated duplicate frames to be hard dropped.
600 * - Create the group array which is used to processes interleave
601 * patterns without duplicate frames present.
602 * - Find the maximum frame delta value. This is used to normalize
603 * frame deltas to filter out weak frames (noise which may cause
604 * erroneous interleave patterns to be detected).
605 * - Detect local interleave patterns.
606 */
607
608 static void
yait_find_ip(void)609 yait_find_ip( void )
610 {
611 Fi *f;
612 double w;
613 int m, p, i;
614
615 /* mark obvious drop frames */
616 if( !NoDrops )
617 for( i=1; i<Nf-1; i++ )
618 {
619 f = Fa[i];
620 if( f->r )
621 continue;
622
623 if( !Fa[i-1]->r && !Fa[i+1]->r )
624 continue;
625
626 f->drop = TRUE;
627 }
628
629 /* create group array, ommiting drops */
630 Ng = 0;
631 for( i=0; i<Nf; i++ )
632 {
633 f = Fa[i];
634 if( f->drop )
635 continue;
636
637 f->gi = Ng;
638 Ga[Ng++] = f;
639 }
640 Ga[Ng] = NULL;
641
642 /* find max row delta */
643 m = 0;
644 for( i=0; i<Nf; i++ )
645 {
646 f = Fa[i];
647 if( f->ed > m )
648 m = f->ed;
649 if( f->od > m )
650 m = f->od;
651 }
652
653 Md = m;
654 if( !Md )
655 {
656 fprintf( stderr, "All empty frames?\n" );
657 exit( 1 );
658 }
659
660 /* compute normalized row deltas and */
661 /* filter out weak r values (noise) */
662 for( i=0; i<Ng; i++ )
663 {
664 f = Ga[i];
665 f->nd = (f->ed + f->od) / (double) Md;
666 if( f->nd < Noise )
667 f->r = 1;
668 }
669
670 /* adjust for incomplete interleave patterns */
671 /* (indexing Fa[0,..,i+6]) */
672 for( i=0; i<Ng-6; i++ )
673 yait_chk_ip( i );
674
675 /* find interleave patterns */
676 for( i=0; i<Ng; i++ )
677 {
678 f = Ga[i];
679 if( f->op & Y_OP_COPY )
680 {
681 /* finish this group before looking for another pattern */
682 i++;
683 continue;
684 }
685
686 p = yait_find_odd( OThresh, i, &w, 4 );
687 if( p != -1 )
688 {
689 yait_mark_grp( p, i, w );
690 continue;
691 }
692
693 p = yait_find_even( EThresh, i, &w, 4 );
694 if( p != -1 )
695 yait_mark_grp( p+10, i, w );
696 }
697 }
698
699
700 /*
701 * yait_chk_ip:
702 * Two cases to look for. An isolated pair of high r's, and an
703 * isolated tuplet of high r's. These can be caused by interlacing over
704 * still and abrupt scene changes.
705 */
706
707 static void
yait_chk_ip(int n)708 yait_chk_ip( int n )
709 {
710 if( !NoDrops )
711 yait_chk_pairs( n );
712
713 yait_chk_tuplets( n );
714 }
715
716
717 /*
718 * yait_chk_pairs:
719 * Look for patterns of the type:
720 * i: 0 1 2 3 4 5
721 * odd: 0 0 -1 1 0 0
722 * even: 0 0 1 -1 0 0
723 *
724 * If detected, force the drop of the (single) interlaced frame.
725 * De-interlacing would just incur a redundant copy operation.
726 */
727
728 static void
yait_chk_pairs(int n)729 yait_chk_pairs( int n )
730 {
731 Fi *fa[6];
732 double ra[6];
733 int i;
734
735 for( i=0; i<6; i++ )
736 {
737 fa[i] = Ga[n+i];
738 ra[i] = fabs( fa[i]->r );
739 }
740
741 for( i=2; i<4; i++ )
742 if( ra[i] < Thresh )
743 return;
744
745 /* adjacent frames to the tuplet must be <thresh */
746 if( ra[1]>Thresh || ra[4]>Thresh )
747 return;
748
749 /* we only need one edge frame to be <thresh */
750 if( ra[0]>Thresh && ra[5]>Thresh )
751 return;
752
753 if( fa[2]->r>0 && fa[3]->r>0 )
754 return;
755
756 if( fa[2]->r<0 && fa[3]->r<0 )
757 return;
758
759 /* two isolated high r values of opposite sign */
760 /* drop the interlaced frame, erase the pattern */
761 fa[2]->r = 1;
762 fa[3]->r = 1;
763
764 fa[2]->drop = TRUE;
765 }
766
767
768 /*
769 * yait_chk_tuplets:
770 * Look for patterns of the type:
771 * i: 0 1 2 3 4 5 6
772 * odd: 0 0 -1 +/-2 1 0 0
773 * even: 0 0 1 +/-2 -1 0 0
774 *
775 * and complete to:
776 *
777 * odd: 0 0 -1 0 1 0 0
778 * even: 0 0 1 0 -1 0 0
779 */
780
781 static void
yait_chk_tuplets(int n)782 yait_chk_tuplets( int n )
783 {
784 Fi *fa[7];
785 double ra[7];
786 int i;
787
788 for( i=0; i<7; i++ )
789 {
790 fa[i] = Ga[n+i];
791 ra[i] = fabs( fa[i]->r );
792 }
793
794 for( i=2; i<5; i++ )
795 if( ra[i] < Thresh )
796 return;
797
798 /* adjacent frames to the tuplet must be <thresh */
799 if( ra[1]>Thresh || ra[5]>Thresh )
800 return;
801
802 /* we only need one edge frame to be <thresh */
803 if( ra[0]>Thresh && ra[6]>Thresh )
804 return;
805
806 if( fa[2]->r>0 && fa[4]->r>0 )
807 return;
808
809 if( fa[2]->r<0 && fa[4]->r<0 )
810 return;
811
812 /* isolated tuplet of high r values of opposite sign */
813 if( ra[3]>ra[2] || ra[3]>ra[4] )
814 fa[3]->r = 1;
815 }
816
817
818 /*
819 * yait_find_odd:
820 */
821
822 static int
yait_find_odd(double thresh,int n,double * w,int win)823 yait_find_odd( double thresh, int n, double *w, int win )
824 {
825 double re, ro;
826 int me, mo;
827 int p;
828
829 /* find max even/odd correlations */
830 /* (r<0 - even, r>0 - odd) */
831 me = yait_ffmin( n, win );
832 mo = yait_ffmax( n, win );
833
834 p = -1;
835 if( yait_m5(mo-2) == yait_m5(me) )
836 {
837 re = fabs( Ga[me]->r );
838 ro = fabs( Ga[mo]->r );
839 if( re>thresh && ro>thresh )
840 {
841 p = yait_m5( mo - 4 );
842 if( w )
843 *w = re + ro;
844 }
845 }
846
847 return( p );
848 }
849
850
851 /*
852 * yait_find_even:
853 */
854
855 static int
yait_find_even(double thresh,int n,double * w,int win)856 yait_find_even( double thresh, int n, double *w, int win )
857 {
858 double re, ro;
859 int me, mo;
860 int p;
861
862 me = yait_ffmin( n, win );
863 mo = yait_ffmax( n, win );
864
865 p = -1;
866 if( yait_m5(me-2) == yait_m5(mo) )
867 {
868 re = fabs( Ga[me]->r );
869 ro = fabs( Ga[mo]->r );
870 if( re>thresh && ro>thresh )
871 {
872 p = yait_m5( me - 4 );
873 if( w )
874 *w = re + ro;
875 }
876 }
877
878 return( p );
879 }
880
881
882 /*
883 * yait_ffmin:
884 */
885
886 static int
yait_ffmin(int n,int w)887 yait_ffmin( int n, int w )
888 {
889 Fi *f;
890 int m, i;
891 double r;
892
893 r = 0;
894 m = 0;
895 for( i=n; i<n+w; i++ )
896 {
897 if( i < 0 )
898 break;
899
900 f = Ga[i];
901 if( !f )
902 break;
903
904 if( f->r < r )
905 {
906 r = f->r;
907 m = i;
908 }
909 }
910
911 return( m );
912 }
913
914
915 /*
916 * yait_ffmax:
917 */
918
919 static int
yait_ffmax(int n,int w)920 yait_ffmax( int n, int w )
921 {
922 Fi *f;
923 int m, i;
924 double r;
925
926 r = 0;
927 m = 0;
928 for( i=n; i<n+w; i++ )
929 {
930 if( i < 0 )
931 break;
932
933 f = Ga[i];
934 if( !f )
935 break;
936
937 if( f->r > r )
938 {
939 r = f->r;
940 m = i;
941 }
942 }
943
944 return( m );
945 }
946
947
948 /*
949 * yait_m5:
950 */
951
952 static int
yait_m5(int n)953 yait_m5( int n )
954 {
955 while( n < 0 )
956 n += 5;
957 return( n % 5 );
958 }
959
960
961 /*
962 * yait_mark_grp:
963 * Try to catch the situation where a progressive frame is missing
964 * between interlace groups. This will cause an erroneous (opposite) ip
965 * pattern to be detected. The first sequence shown below is a normal (odd)
966 * telecine pattern. The second shows what happens when a progressive frame
967 * is missing. We want to reject the even pattern detected. Therefore, if
968 * we find an identical pattern at n+4 we keep it. If not, we reject if an
969 * opposite pattern follows at n+2 of greater weight.
970 *
971 * n: 0 1 2 3 4 0 1 2 3 4
972 * r: 0 -1 0 1 0 0 -1 0 1 0
973 * odd odd
974 *
975 * n: 0 1 2 3 4 1 2 3 4
976 * r: 0 -1 0 1 0 -1 0 1 0
977 * odd even odd
978 */
979
980 static void
yait_mark_grp(int p,int n,double w)981 yait_mark_grp( int p, int n, double w )
982 {
983 Fi *f;
984 double nw;
985 int np, t, i;
986
987 if( n%5 != (p+2)%5 )
988 return;
989
990 /* only overwrite an existing pattern if weight is greater */
991 f = Ga[n];
992 if( w <= f->w )
993 return;
994
995 /* check for same pattern at n+4 */
996 if( p < 10 )
997 np = yait_find_odd( OThresh, n+4, NULL, 5 );
998 else
999 np = yait_find_even( EThresh, n+4, NULL, 5 );
1000 if( np < 0 )
1001 {
1002 /* no pattern at n+4, reject if opposite ip at n+2 */
1003 if( p < 10 )
1004 np = yait_find_even( EThresh, n+2, &nw, 5 );
1005 else
1006 np = yait_find_odd( OThresh, n+2, &nw, 5 );
1007
1008 if( np>=0 && nw>w )
1009 return;
1010 }
1011
1012 /* erase previous pattern */
1013 if( n > 1 )
1014 {
1015 Ga[n-1]->op = 0;
1016 Ga[n-2]->op = 0;
1017 }
1018
1019 /* this frame and next are interlaced */
1020 t = (p < 10) ? Y_OP_ODD : Y_OP_EVEN;
1021 f->op = t | Y_OP_SAVE | Y_OP_DROP;
1022 f = Ga[n+1];
1023 f->op = t | Y_OP_COPY;
1024
1025 /* assume 1 progressive on either side of the tuplet */
1026 for( i=n-1; i<n+4; i++ )
1027 {
1028 if( i<0 || i>=Ng )
1029 continue;
1030
1031 f = Ga[i];
1032 f->ip = p;
1033 f->w = w;
1034 }
1035 }
1036
1037
1038 /*
1039 * yait_find_drops:
1040 * For every group of 5 frames, make sure we drop a frame. Allow up to a
1041 * DropWin (default 15) group lookahead to make up for extra or missing drops. (The
1042 * duplicated frames generated by --hard_fps can be quite early or late in the sequence).
1043 * If a group requires a drop, but none exists, mark the group as requiring de-interlacing.
1044 * Finally, consequetive marked groups inherit surrounding interleave patterns.
1045 *
1046 * Each group will receive one of the following flags:
1047 *
1048 * Y_HAS_DROP - group has a single drop frame
1049 * Y_BANK_DROP - extra drop, can be used forward
1050 * Y_WITHDRAW_DROP - missing drop, use banked drop from behind
1051 * Y_RETURN_DROP - extra drop, can be used behind
1052 * Y_BORROW_DROP - missing drop, use future extra drop
1053 * Y_FORCE_DEINT - force de-interlacing, (produces a drop)
1054 * Y_FORCE_DROP - missing drop, no extras and no interleave found
1055 * Y_FORCE_KEEP - extra drop, no consumer so have to keep it
1056 *
1057 * For any flags other than FORCE, no action is required. Eeach group already has
1058 * an available frame to drop, whether a marked duplicate, or a locally detected
1059 * interleave pattern (which produces a drop).
1060 *
1061 * For Y_FORCE_DEINT, assemble consecutive groups of this type and try to inherit
1062 * adjacent interleave patterns. If no pattern is available, mark them as
1063 * Y_FORCE_DROP.
1064 */
1065
1066 static void
yait_find_drops(void)1067 yait_find_drops( void )
1068 {
1069 Fi *f;
1070 int d, l;
1071
1072 /* populate drop counts */
1073 for( d=0; d<Nd; d++ )
1074 Da[d] = yait_cnt_drops( d*5 );
1075
1076 /* balance drop counts restricted by window size */
1077 for( d=0; d<Nd; d++ )
1078 {
1079 f = Fa[d*5];
1080
1081 /* this is what we want to see */
1082 if( Da[d] == 1 )
1083 {
1084 if( !f->gf )
1085 f->gf = Y_HAS_DROP;
1086 continue;
1087 }
1088
1089 /* group is missing a drop? */
1090 if( !Da[d] )
1091 {
1092 /* look ahead for an extra drop */
1093 l = yait_extra_drop( d );
1094 if( l )
1095 {
1096 /* found one */
1097 Da[d]++;
1098 f->gf = Y_BORROW_DROP;
1099
1100 --Da[l];
1101 Fa[l*5]->gf = Y_RETURN_DROP;
1102 continue;
1103 }
1104
1105 /* no extra drops exist, mark for de-interlacing */
1106 f->gf = Y_FORCE_DEINT;
1107 continue;
1108 }
1109
1110 /* we have too many drops */
1111 while( Da[d] > 1 )
1112 {
1113 --Da[d];
1114
1115 /* look ahead for a missing drop */
1116 l = yait_missing_drop( d );
1117 if( l )
1118 {
1119 /* found one */
1120 f->gf = Y_BANK_DROP;
1121
1122 Da[l]++;
1123 Fa[l*5]->gf = Y_WITHDRAW_DROP;
1124 continue;
1125 }
1126
1127 /* we have to keep a drop */
1128 if( !NoKeeps )
1129 {
1130 f->gf = Y_FORCE_KEEP;
1131 yait_keep_frame( d*5 );
1132
1133 Stat_fk++;
1134 }
1135 }
1136 }
1137 }
1138
1139
1140 /*
1141 * yait_cnt_drops:
1142 */
1143
1144 static int
yait_cnt_drops(int n)1145 yait_cnt_drops( int n )
1146 {
1147 Fi *f;
1148 int d, i;
1149
1150 d = 0;
1151 for( i=n; i<n+5 && i<Nf; i++ )
1152 {
1153 f = Fa[i];
1154 if( f->drop || f->op&Y_OP_DROP )
1155 d++;
1156 }
1157
1158 return( d );
1159 }
1160
1161
1162 /*
1163 * yait_extra_drop:
1164 * Scan DropWin groups ahead for an extra drop.
1165 */
1166
1167 static int
yait_extra_drop(int d)1168 yait_extra_drop( int d )
1169 {
1170 int l, w;
1171
1172 for( w=0; w<DropWin; w++ )
1173 {
1174 l = d + w + 1;
1175 if( l >= Nd )
1176 return( 0 );
1177
1178 if( Da[l] > 1 )
1179 return( l );
1180 }
1181
1182 return( 0 );
1183 }
1184
1185
1186 /*
1187 * yait_missing_drop:
1188 * Scan DropWin groups ahead for a missing drop.
1189 */
1190
1191 static int
yait_missing_drop(int d)1192 yait_missing_drop( int d )
1193 {
1194 int l, w;
1195
1196 for( w=0; w<DropWin; w++ )
1197 {
1198 l = d + w + 1;
1199 if( l >= Nd )
1200 return( 0 );
1201
1202 if( !Da[l] )
1203 return( l );
1204 }
1205
1206 return( 0 );
1207 }
1208
1209
1210 /*
1211 * yait_keep_frame:
1212 * Multiple drops exist. Pick the best frame to keep. This can be difficult,
1213 * as we do not want to keep a duplicate of an interlaced frame. First, try to find
1214 * a hard dropped frame which does not follow an interlace. If one can be found, then
1215 * simply negate the drop flag. If we are duplicating an interlace, alter the frame
1216 * operations for the group to produce a non-interlaced duplicate.
1217 */
1218
1219 static void
yait_keep_frame(int n)1220 yait_keep_frame( int n )
1221 {
1222 Fi *f;
1223 int da[6], bd, d, i;
1224
1225 d = yait_get_hdrop( n, da );
1226
1227 if( !d )
1228 {
1229 /* no hard drop frames were found, so ... */
1230 /* two interlace drops exist, keep one, but blend it */
1231 for( i=n; i<n+5 && i<Nf; i++ )
1232 {
1233 f = Fa[i];
1234 if( f->op & Y_OP_DROP )
1235 {
1236 f->op &= ~Y_OP_DROP;
1237 f->op |= Y_OP_DEINT;
1238 return;
1239 }
1240 }
1241
1242 /* sanity check */
1243 f = Fa[n];
1244 fprintf( stderr, "No drop frame can be found, frame: %d\n", f->fn );
1245 exit( 1 );
1246 }
1247
1248 /* try to use a drop frame that isn't an interlace duplicate */
1249 bd = -1;
1250 for( i=0; i<5; i++ )
1251 {
1252 d = da[i];
1253 if( !d )
1254 /* can't access before Fa[0] */
1255 continue;
1256
1257 if( d < 0 )
1258 /* end of drop list */
1259 break;
1260
1261 f = Fa[d-1];
1262 if( f->drop )
1263 /* two dups in a row */
1264 f = Fa[d-2];
1265
1266 if( !f->op )
1267 {
1268 /* good */
1269 f = Fa[d];
1270 f->drop = FALSE;
1271 return;
1272 }
1273
1274 if( f->op & Y_OP_COPY )
1275 bd = d;
1276 }
1277
1278 /* keeping a duplicate of an interlace, try to use one which duplicates the */
1279 /* second of an interlace pair, as that is cleaner to deal with */
1280 /* bd (best drop) was set earlier in the loop if such a frame was found */
1281 if( bd < 0 )
1282 bd = da[0];
1283
1284 yait_ivtc_keep( bd );
1285 }
1286
1287
1288 /*
1289 * yait_get_hdrop:
1290 * Populate an index array of the hard dropped frames, and return
1291 * the count of how many were found.
1292 */
1293
1294 static int
yait_get_hdrop(int n,int * da)1295 yait_get_hdrop( int n, int *da )
1296 {
1297 Fi *f;
1298 int d, i;
1299
1300 d = 0;
1301 for( i=n; i<n+5 && i<Nf; i++ )
1302 {
1303 f = Fa[i];
1304 if( f->drop )
1305 {
1306 *da++ = i;
1307 d++;
1308 }
1309 }
1310 *da = -1;
1311
1312 return( d );
1313 }
1314
1315
1316 /*
1317 * yait_ivtc_keep
1318 * Depending upon the position of the DROP in the pattern, alter the
1319 * frame ops to generate a non-interlaced frame, and keep it.
1320 *
1321 * Case 1:
1322 * If the duplicated frame is the second of the interlaced pair, then
1323 * simply repeat the row copy operation and keep the frame.
1324 *
1325 * Original (odd pattern):
1326 * sd c
1327 * even: 2 2 3 3 4
1328 * odd: 2 3 4 4 4
1329 * drop DROP
1330 *
1331 * yeilds (bad keep frame):
1332 * even: 2 3 3 4
1333 * odd: 2 3 4 4
1334 * KEEP
1335 * Revised:
1336 * sd c c
1337 * even: 2 2 3 3 4
1338 * odd: 2 3 4 4 4
1339 * drop DROP
1340 * yeilds:
1341 * even: 2 3 3 4
1342 * odd: 2 3 3 4
1343 * KEEP
1344 *
1345 * Case 2:
1346 * If the duplicated frame copies the first of the interlaced pair, more
1347 * work must be done:
1348 *
1349 * Original (odd pattern):
1350 * sd c
1351 * even: 2 2 2 3 4
1352 * odd: 2 3 3 4 4
1353 * drop DROP
1354 *
1355 * yeilds (bad keep frame):
1356 * even: 2 2 3 4
1357 * odd: 2 3 3 4
1358 * KEEP
1359 * Revised:
1360 * s c sd c
1361 * even: 2 2 2 3 4
1362 * odd: 2 3 3 4 4
1363 * drop
1364 * yeilds:
1365 * even: 2 2 3 4
1366 * odd: 2 2 3 4
1367 * (keep)
1368 */
1369
1370 static void
yait_ivtc_keep(int d)1371 yait_ivtc_keep( int d )
1372 {
1373 Fi *fd, *fp;
1374 int t;
1375
1376 fd = Fa[d];
1377 fp = Fa[d-1];
1378 if( fp->drop )
1379 fp = Fa[d-2];
1380
1381 if( fp->op & Y_OP_COPY )
1382 {
1383 /* case 1 */
1384 fd->op = fp->op;
1385 fd->drop = FALSE;
1386 return;
1387 }
1388
1389 /* case 2 */
1390 if( d < 2 )
1391 {
1392 /* can't access before Fa[0] */
1393 /* (unlikely we would see this the first two frames of a film) */
1394 fd->drop = FALSE;
1395 return;
1396 }
1397
1398 fd->op = fp->op;
1399 fd->drop = FALSE;
1400
1401 t = fp->op & Y_OP_PAT;
1402 fp->op = t | Y_OP_COPY;
1403 fp = Fa[d-2];
1404 fp->op = t | Y_OP_SAVE;
1405 }
1406
1407
1408 /*
1409 * yait_ivtc_grps:
1410 * For each group missing an interleave pattern, scan backward and forward
1411 * for an adjacent pattern. Consider hard dropped frames as barriers. If two
1412 * different patterns exist, test the pattern against the original r values to find
1413 * the best match. For consecutive (forced) interleave groups, use the previously
1414 * found pattern values, until the forward scan value is used, which is then
1415 * propagated to the rest of the sequence. (This avoids an O(n^2) search).
1416 *
1417 * If no pattern can be found, force a drop of a frame in the group.
1418 *
1419 * TODO:
1420 * I should really be detecting scene changes as well, and consider them
1421 * barriers.
1422 */
1423
1424 static void
yait_ivtc_grps(void)1425 yait_ivtc_grps( void )
1426 {
1427 Fi *f;
1428 int pb, pf, fg;
1429 int p, n;
1430
1431 /* process by groups of 5 */
1432 fg = TRUE;
1433 pb = -1;
1434 pf = -1;
1435 for( n=0; n<Nf; n+=5 )
1436 {
1437 f = Fa[n];
1438 if( f->gf != Y_FORCE_DEINT )
1439 {
1440 fg = TRUE;
1441 continue;
1442 }
1443
1444 if( fg )
1445 {
1446 /* this is the first group of a sequence, scan */
1447 fg = FALSE;
1448 pb = yait_scan_bk( n );
1449 pf = yait_scan_fw( n );
1450 }
1451
1452 if( pb<0 && pf<0 )
1453 {
1454 /* no pattern exists */
1455 f->gf = Y_FORCE_DROP;
1456 yait_drop_frame( n );
1457 continue;
1458 }
1459
1460 /* deinterlace the group with one of the given patterns */
1461 /* if the pattern used is forward, keep it from now on */
1462 p = yait_ivtc_grp( n, pb, pf );
1463 if( p < 0 )
1464 {
1465 /* no pattern will match */
1466 f->gf = Y_FORCE_DROP;
1467 yait_drop_frame( n );
1468 continue;
1469 }
1470
1471 if( p == pf )
1472 pb = -1;
1473 }
1474 }
1475
1476
1477 /*
1478 * yait_scan_bk:
1479 */
1480
1481 static int
yait_scan_bk(int n)1482 yait_scan_bk( int n )
1483 {
1484 Fi *f;
1485 int i;
1486
1487 for( i=n-1; i>=0; --i )
1488 {
1489 f = Fa[i];
1490 if( !f )
1491 return( -1 );
1492
1493 if( f->drop )
1494 return( -1 );
1495
1496 if( f->ip != -1 )
1497 return( f->ip );
1498 }
1499
1500 return( -1 );
1501 }
1502
1503
1504 /*
1505 * yait_scan_fw:
1506 */
1507
1508 static int
yait_scan_fw(int n)1509 yait_scan_fw( int n )
1510 {
1511 Fi *f;
1512 int i;
1513
1514 for( i=n+5; i<Nf; i++ )
1515 {
1516 f = Fa[i];
1517
1518 if( f->drop )
1519 return( -1 );
1520
1521 if( f->ip != -1 )
1522 return( f->ip );
1523 }
1524
1525 return( -1 );
1526 }
1527
1528
1529 /*
1530 * yait_drop_frame:
1531 * Choose a frame to drop. We want the frame with the highest fabs(r) value,
1532 * as it is likely an interlaced frame. Do not use a frame which follows an assigned
1533 * ip pattern, (it is the trailing element of a tuplet). If no r values exceed the
1534 * threshold, choose the frame with the minimum delta.
1535 *
1536 * Frame: 0 1 2 3 4 | 5 6 7 8 9
1537 * Ratio: 0 0 0 -1 0 | 1 0 0 0 0
1538 * Op: sd c |
1539 * group boundary
1540 *
1541 * In the above example, the first frame of the second group (5) may have the highest
1542 * ratio value, but is the worst choice because it is part of the detected pattern and
1543 * is a unique progressive frame.
1544 */
1545
1546 static void
yait_drop_frame(int n)1547 yait_drop_frame( int n )
1548 {
1549 Fi *f;
1550 double mr, r;
1551 int md, d;
1552 int fr, fd;
1553 int i;
1554
1555 mr = 0;
1556 md = 0;
1557 fr = n;
1558 fd = n;
1559
1560 for( i=n; i<n+5 && i<Nf-1; i++ )
1561 {
1562 if( !i )
1563 /* can't access before Fa[0] */
1564 continue;
1565
1566 if( Fa[i-1]->drop || Fa[i+1]->drop )
1567 /* avoid two consequetive drops */
1568 continue;
1569
1570 if( Fa[i-1]->op & Y_OP_PAT )
1571 /* trailing tuplet element */
1572 continue;
1573
1574 f = Fa[i];
1575
1576 r = fabs( f->ro );
1577 if( r > mr )
1578 {
1579 mr = r;
1580 fr = i;
1581 }
1582
1583 d = f->ed + f->od;
1584 if( !md || d<md )
1585 {
1586 md = d;
1587 fd = i;
1588 }
1589 }
1590
1591 Fa[ (mr>Thresh)?fr:fd ]->drop = TRUE;
1592 Stat_fd++;
1593 }
1594
1595
1596 /*
1597 * yait_ivtc_grp:
1598 * We need to de-interlace this group. Given are two potential patterns.
1599 * If both are valid, test both and keep the one with the best r value matches.
1600 * For the pattern used, mark the group, set the frame ops accordingly, and return
1601 * it as the function value.
1602 */
1603
1604 static int
yait_ivtc_grp(int n,int p1,int p2)1605 yait_ivtc_grp( int n, int p1, int p2 )
1606 {
1607 Fi *f;
1608 double thresh, m1, m2;
1609 int p, t, i;
1610
1611 m1 = (p1 < 0) ? -1 : yait_tst_ip(n,p1);
1612 m2 = (p2 < 0) ? -1 : yait_tst_ip(n,p2);
1613
1614 /* yait_tst_ip() returns the sum of two ratios */
1615 /* we want both ratios > Y_MTHRESH */
1616 thresh = Y_MTHRESH * 2;
1617 if( !NoDrops && m1<thresh && m2<thresh )
1618 /* neither pattern matches, force a drop instead */
1619 return( -1 );
1620
1621 p = (m1 > m2) ? p1 : p2;
1622
1623 /* sanity check */
1624 if( p < 0 )
1625 {
1626 f = Fa[n];
1627 fprintf( stderr, "Impossible interlace pattern computed (%d), frame: %d\n",
1628 p, f->fn );
1629 exit( 1 );
1630 }
1631
1632 /* we have a pattern, mark group */
1633 for( i=n; i<n+5 && i<Nf; i++ )
1634 {
1635 f = Fa[i];
1636 if( f->drop )
1637 {
1638 fprintf( stderr,
1639 "De-interlace, horribly confused now, frame: %d.\n", f->fn );
1640 exit( 1 );
1641 }
1642 f->ip = p;
1643 }
1644
1645 f = Fa[n];
1646 n = f->gi;
1647
1648 /* sanity check */
1649 if( Ga[n] != f )
1650 {
1651 fprintf( stderr, "Lost our frame in the group array, frame: %d\n", f->fn );
1652 exit( 1 );
1653 }
1654
1655 t = (p < 10) ? Y_OP_ODD : Y_OP_EVEN;
1656 for( i=n; i<n+5 && i<Ng-1; i++ )
1657 {
1658 if( i%5 == (p+2)%5 )
1659 {
1660 f = Ga[i];
1661 f->op = t | Y_OP_SAVE | Y_OP_DROP;
1662
1663 /* don't overwrite an existing frame drop */
1664 f = Ga[i+1];
1665 if( !(f->op&Y_OP_DROP) )
1666 f->op = t | Y_OP_COPY;
1667
1668 break;
1669 }
1670 }
1671
1672 return( p );
1673 }
1674
1675
1676 /*
1677 * yait_tst_ip:
1678 */
1679
1680 static double
yait_tst_ip(int n,int p)1681 yait_tst_ip( int n, int p )
1682 {
1683 double rs, r;
1684 int s, i;
1685
1686 s = (p < 10) ? 1 : -1;
1687 rs = 0;
1688
1689 n = Fa[n]->gi;
1690 for( i=n; i<n+5 && i<Ng-2; i++ )
1691 {
1692 if( i%5 != (p+2)%5 )
1693 continue;
1694
1695 /* strong pattern would have r[i]<-thresh and r[i+2]>thresh */
1696 r = s * Ga[i]->ro;
1697 if( r < 0 )
1698 rs += fabs( r );
1699
1700 r = s * Ga[i+2]->ro;
1701 if( r > 0 )
1702 rs += r;
1703
1704 break;
1705 }
1706
1707 return( rs );
1708 }
1709
1710
1711 /*
1712 * yait_deint:
1713 * For non 3/2 telecine patterns, we may have let interlaced frames
1714 * through. Tell transcode to de-interlace (blend) these. This is the case for
1715 * any frame having a high ratio with no interlace pattern detected.
1716 *
1717 * TODO:
1718 * This was an afterthought. Perhaps we can avoid a 32detect pass on
1719 * the video by performing this, although it is difficult to detect out of
1720 * pattern interlace frames solely on row delta information. Perhaps we should
1721 * have built 32detect into the log generation, and added an extra flag field if
1722 * we thought the frame was interlaced. This also would help when trying to
1723 * assign ambiguous ip patterns.
1724 */
1725
1726 static void
yait_deint(void)1727 yait_deint( void )
1728 {
1729 Fi *fp, *fn, *f;
1730 int i;
1731
1732 for( i=1; i<Ng-1; i++ )
1733 {
1734 fp = Ga[i-1];
1735 f = Ga[i];
1736 fn = Ga[i+1];
1737
1738 if( f->op&Y_OP_PAT || f->drop )
1739 /* already being de-interlaced or dropped */
1740 continue;
1741
1742 if( fp->op & Y_OP_PAT )
1743 /* trailing element of a tuplet */
1744 continue;
1745
1746 if( fabs(f->r) < Blend )
1747 /* it isn't interlaced (we think) */
1748 continue;
1749
1750 if( f->nd < Y_FWEIGHT )
1751 /* delta is too weak, interlace is likely not visible */
1752 continue;
1753
1754 if( fp->nd>Y_SCENE_CHANGE || f->nd>Y_SCENE_CHANGE )
1755 /* can't make a decision over scene changes */
1756 continue;
1757
1758 /* this frame is interlaced with no operation assigned */
1759 f->op = Y_OP_DEINT;
1760
1761 /* if the next frame ratio < thresh, it is similar, unless */
1762 /* a scene change, therefore interlaced as well */
1763 if( fabs(fn->r)<Thresh && fn->nd<Y_SCENE_CHANGE )
1764 if( !(fn->op&Y_OP_PAT) && !fn->drop )
1765 fn->op = Y_OP_DEINT;
1766
1767 /* if the next frame(s) are duplicates of this, mark them */
1768 /* for blending as well, as the may eventually be force kept */
1769 while( f->next && !f->next->gi )
1770 {
1771 f = f->next;
1772 f->op = Y_OP_DEINT;
1773 }
1774 }
1775 }
1776
1777
1778 /*
1779 * yait_write_ops:
1780 */
1781
1782 static void
yait_write_ops(void)1783 yait_write_ops( void )
1784 {
1785 Fi *f;
1786
1787 for( f=Fl; f; f=f->next )
1788 fprintf( OpsFp, "%d: %s\n", f->fn, yait_write_op(f) );
1789 }
1790
1791
1792 /*
1793 * yait_write_op:
1794 */
1795
1796 static char*
yait_write_op(Fi * f)1797 yait_write_op( Fi *f )
1798 {
1799 static char buf[10];
1800 char *p;
1801 int op;
1802
1803 p = buf;
1804 if( f->drop )
1805 {
1806 *p++ = 'd';
1807 *p = 0;
1808 Stat_nd++;
1809 return( buf );
1810 }
1811
1812 op = f->op;
1813 if( op & Y_OP_ODD )
1814 *p++ = 'o';
1815 if( op & Y_OP_EVEN )
1816 *p++ = 'e';
1817 if( op & Y_OP_SAVE )
1818 *p++ = 's';
1819 if( op & Y_OP_COPY )
1820 *p++ = 'c';
1821 if( op & Y_OP_DROP )
1822 {
1823 *p++ = 'd';
1824 Stat_nd++;
1825 if( op & Y_OP_ODD )
1826 Stat_no++;
1827 else
1828 Stat_ne++;
1829 }
1830 if( op & Y_OP_DEINT )
1831 {
1832 *p++ = '0' + DeintMode;
1833 Stat_nb++;
1834 }
1835 *p = 0;
1836
1837 return( buf );
1838 }
1839
1840
1841 /*
1842 * yait_fini:
1843 * Free up allocations.
1844 */
1845
1846 static void
yait_fini(void)1847 yait_fini( void )
1848 {
1849 int i;
1850
1851 for( i=0; i<Nf; i++ )
1852 free( Fa[i] );
1853
1854 free( Fa );
1855 free( Ga );
1856 free( Da );
1857 }
1858
1859
1860 /*
1861 * Output debug information to stdout
1862 */
1863
1864 static void
yait_debug_fi(void)1865 yait_debug_fi( void )
1866 {
1867 Fi *f;
1868 int i;
1869
1870 printf( "Options:\n" );
1871 printf( "\tLog file: %s\n", LogFn );
1872 printf( "\tOps file: %s\n", OpsFn );
1873 printf( "\tEven Threshold: %g\n", EThresh );
1874 printf( "\tOdd Threshold: %g\n", OThresh );
1875 printf( "\tBlend threshold: %g\n", Blend );
1876 printf( "\tDrop window size: %d\n", DropWin );
1877 printf( "\tDe-interlace mode: %d\n\n", DeintMode );
1878
1879 printf( "Stats:\n" );
1880 printf( "\tTotal number of frames: %d\n", Nf );
1881 printf( "\tNumber of frames divided by 5: %d\n", Nf/5 );
1882 printf( "\tTotal dropped frames: %d\n", Stat_nd );
1883 printf( "\tTotal blended frames: %d\n", Stat_nb );
1884 printf( "\tTotal odd interlaced pairs: %d\n", Stat_no );
1885 printf( "\tTotal even interlaced pairs: %d\n", Stat_ne );
1886 printf( "\tNumber of forced frame drops: %d\n", Stat_fd );
1887 printf( "\tNumber of forced frame keeps: %d\n\n", Stat_fk );
1888 printf( "\tMax row delta: %d\n\n", Md );
1889
1890 i = 0;
1891 for( f=Fl; f; f=f->next, i++ )
1892 {
1893 if( i && !(i%5) )
1894 printf( "\n" );
1895
1896 printf( "Frame %6d: e: %8d, o: %8d, r: %7.3f, ro: %7.3f, w: %8.4f, "
1897 "ip: %2d, gi: %6d, op: %-4s d: %s %s\n",
1898 f->fn, f->ed, f->od, f->r, f->ro, f->w, f->ip, f->gi,
1899 yait_op(f->op), yait_drop(f), yait_grp(f->gf) );
1900 }
1901 }
1902
1903 static char*
yait_op(int op)1904 yait_op( int op )
1905 {
1906 static char buf[10];
1907 char *p;
1908
1909 p = buf;
1910 *p = 0;
1911 if( !op )
1912 return( buf );
1913
1914 if( op & Y_OP_ODD )
1915 *p++ = 'o';
1916 if( op & Y_OP_EVEN )
1917 *p++ = 'e';
1918 if( op & Y_OP_SAVE )
1919 *p++ = 's';
1920 if( op & Y_OP_COPY )
1921 *p++ = 'c';
1922 if( op & Y_OP_DROP )
1923 *p++ = 'd';
1924 if( op & Y_OP_DEINT )
1925 *p++ = '0' + DeintMode;
1926 *p = 0;
1927
1928 return( buf );
1929 }
1930
1931 static char*
yait_drop(Fi * f)1932 yait_drop( Fi *f )
1933 {
1934 if( f->drop )
1935 return( "DROP" );
1936
1937 if( f->op&Y_OP_ODD && f->op&Y_OP_DROP )
1938 return( "odd " );
1939
1940 if( f->op&Y_OP_EVEN && f->op&Y_OP_DROP )
1941 return( "even" );
1942
1943 return( " " );
1944 }
1945
1946 static char*
yait_grp(int flg)1947 yait_grp( int flg )
1948 {
1949 switch( flg )
1950 {
1951 case Y_HAS_DROP:
1952 return( "has drop" );
1953 case Y_BANK_DROP:
1954 return( "bank" );
1955 case Y_WITHDRAW_DROP:
1956 return( "withdraw" );
1957 case Y_BORROW_DROP:
1958 return( "borrow" );
1959 case Y_RETURN_DROP:
1960 return( "return" );
1961 case Y_FORCE_DEINT:
1962 return( "force deint" );
1963 case Y_FORCE_DROP:
1964 return( "force drop" );
1965 case Y_FORCE_KEEP:
1966 return( "force keep" );
1967 }
1968 return( "" );
1969 }
1970