comparison libmpcodecs/vf_divtc.c @ 12225:eb79a6192b2b

New filter by Ville Saari (114263 at foo dot bar dot org) for removing duplicate frames from telecined video that was incorrectly deinterlaced. Minor bugfixes added by me.
author rfelker
date Sat, 17 Apr 2004 17:08:31 +0000
parents
children 821f464b4d90
comparison
equal deleted inserted replaced
12224:acb8ed9cfe70 12225:eb79a6192b2b
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <limits.h>
5 #include <math.h>
6
7 #include "../config.h"
8 #include "../mp_msg.h"
9 #include "../cpudetect.h"
10 #include "../bswap.h"
11
12 #include "img_format.h"
13 #include "mp_image.h"
14 #include "vf.h"
15
16 #include "../libvo/fastmemcpy.h"
17
18 vf_info_t vf_info_divtc;
19
20 struct vf_priv_s
21 {
22 int deghost, pass, phase, window, fcount, bcount, frameno, misscount,
23 ocount, sum[5];
24 double threshold;
25 FILE *file;
26 char *bdata;
27 unsigned int *csdata;
28 int *history;
29 };
30
31 /*
32 * diff_MMX and diff_C stolen from vf_decimate.c
33 */
34
35 #ifdef HAVE_MMX
36 static int diff_MMX(unsigned char *old, unsigned char *new, int os, int ns)
37 {
38 volatile short out[4];
39 asm (
40 "movl $8, %%ecx \n\t"
41 "pxor %%mm4, %%mm4 \n\t"
42 "pxor %%mm7, %%mm7 \n\t"
43
44 ".balign 16 \n\t"
45 "1: \n\t"
46
47 "movq (%%esi), %%mm0 \n\t"
48 "movq (%%esi), %%mm2 \n\t"
49 "addl %%eax, %%esi \n\t"
50 "movq (%%edi), %%mm1 \n\t"
51 "addl %%ebx, %%edi \n\t"
52 "psubusb %%mm1, %%mm2 \n\t"
53 "psubusb %%mm0, %%mm1 \n\t"
54 "movq %%mm2, %%mm0 \n\t"
55 "movq %%mm1, %%mm3 \n\t"
56 "punpcklbw %%mm7, %%mm0 \n\t"
57 "punpcklbw %%mm7, %%mm1 \n\t"
58 "punpckhbw %%mm7, %%mm2 \n\t"
59 "punpckhbw %%mm7, %%mm3 \n\t"
60 "paddw %%mm0, %%mm4 \n\t"
61 "paddw %%mm1, %%mm4 \n\t"
62 "paddw %%mm2, %%mm4 \n\t"
63 "paddw %%mm3, %%mm4 \n\t"
64
65 "decl %%ecx \n\t"
66 "jnz 1b \n\t"
67 "movq %%mm4, (%%edx) \n\t"
68 "emms \n\t"
69 :
70 : "S" (old), "D" (new), "a" (os), "b" (ns), "d" (out)
71 : "memory"
72 );
73 return out[0]+out[1]+out[2]+out[3];
74 }
75 #endif
76
77 static int diff_C(unsigned char *old, unsigned char *new, int os, int ns)
78 {
79 int x, y, d=0;
80
81 for(y=8; y; y--, new+=ns, old+=os)
82 for(x=8; x; x--)
83 d+=abs(new[x]-old[x]);
84
85 return d;
86 }
87
88 static int (*diff)(unsigned char *, unsigned char *, int, int);
89
90 static int diff_plane(unsigned char *old, unsigned char *new,
91 int w, int h, int os, int ns, int arg)
92 {
93 int x, y, d, max=0, sum=0, n=0;
94
95 for(y=0; y<h-7; y+=8)
96 {
97 for(x=0; x<w-7; x+=8)
98 {
99 d=diff(old+x+y*os, new+x+y*ns, os, ns);
100 if(d>max) max=d;
101 sum+=d;
102 n++;
103 }
104 }
105
106 return (sum+n*max)/2;
107 }
108
109 /*
110 static unsigned int checksum_plane(unsigned char *p, unsigned char *z,
111 int w, int h, int s, int zs, int arg)
112 {
113 unsigned int shift, sum;
114 unsigned char *e;
115
116 for(sum=0; h; h--, p+=s-w)
117 for(e=p+w, shift=32; p<e;)
118 sum^=(*p++)<<(shift=(shift-8)&31);
119
120 return sum;
121 }
122 */
123
124 static unsigned int checksum_plane(unsigned char *p, unsigned char *z,
125 int w, int h, int s, int zs, int arg)
126 {
127 unsigned int shift;
128 uint32_t sum, t;
129 unsigned char *e, *e2;
130 #if MP_WORDSIZE==64
131 typedef uint64_t wsum_t;
132 #else
133 typedef uint32_t wsum_t;
134 #endif
135 wsum_t wsum;
136
137 for(sum=0; h; h--, p+=s-w)
138 {
139 for(shift=0, e=p+w; (int)p&(sizeof(wsum_t)-1) && p<e;)
140 sum^=*p++<<(shift=(shift-8)&31);
141
142 for(wsum=0, e2=e-sizeof(wsum_t)+1; p<e2; p+=sizeof(wsum_t))
143 wsum^=*(wsum_t *)p;
144
145 #if MP_WORDSIZE==64
146 t=be2me_32((uint32_t)(wsum>>32^wsum));
147 #else
148 t=be2me_32(wsum);
149 #endif
150
151 for(sum^=(t<<shift|t>>(32-shift)); p<e;)
152 sum^=*p++<<(shift=(shift-8)&31);
153 }
154
155 return sum;
156 }
157
158 static int deghost_plane(unsigned char *d, unsigned char *s,
159 int w, int h, int ds, int ss, int threshold)
160 {
161 int t;
162 unsigned char *e;
163
164 for(; h; h--, s+=ss-w, d+=ds-w)
165 for(e=d+w; d<e; d++, s++)
166 if(abs(*d-*s)>=threshold)
167 *d=(t=(*d<<1)-*s)<0?0:t>255?255:t;
168
169 return 0;
170 }
171
172 static int imgop(int(*planeop)(unsigned char *, unsigned char *,
173 int, int, int, int, int),
174 mp_image_t *dst, mp_image_t *src, int arg)
175 {
176 if(dst->flags&MP_IMGFLAG_PLANAR)
177 return planeop(dst->planes[0], src?src->planes[0]:0,
178 dst->w, dst->h,
179 dst->stride[0], src?src->stride[0]:0, arg)+
180 planeop(dst->planes[1], src?src->planes[1]:0,
181 dst->chroma_width, dst->chroma_height,
182 dst->stride[1], src?src->stride[1]:0, arg)+
183 planeop(dst->planes[2], src?src->planes[2]:0,
184 dst->chroma_width, dst->chroma_height,
185 dst->stride[2], src?src->stride[2]:0, arg);
186
187 return planeop(dst->planes[0], src?src->planes[0]:0,
188 dst->w*(dst->bpp/8), dst->h,
189 dst->stride[0], src?src->stride[0]:0, arg);
190 }
191
192 /*
193 * Find the phase in which the telecine pattern fits best to the
194 * given 5 frame slice of frame difference measurements.
195 *
196 * If phase1 and phase2 are not negative, only the two specified
197 * phases are tested.
198 */
199
200 static int cmp(int *a, int *b) { return *b-*a; }
201
202 static int match(struct vf_priv_s *p, int *diffs,
203 int phase1, int phase2, double *strength)
204 {
205 static const int pattern1[]={ -4, 1, 1, 1, 1 },
206 pattern2[]={ -2, -3, 4, 4, -3 }, *pattern;
207 int f, m, n, t[5];
208
209 pattern=p->deghost>0?pattern2:pattern1;
210
211 for(f=0; f<5; f++)
212 {
213 if(phase1<0 || phase2<0 || f==phase1 || f==phase2)
214 {
215 for(n=t[f]=0; n<5; n++)
216 t[f]+=diffs[n]*pattern[(n-f+5)%5];
217 }
218 else
219 t[f]=INT_MIN;
220 }
221
222 /* find the best match */
223 for(m=0, n=1; n<5; n++)
224 if(t[n]>t[m]) m=n;
225
226 if(strength)
227 {
228 /* the second best match */
229 for(f=m?0:1, n=f+1; n<5; n++)
230 if(n!=m && t[n]>t[f]) f=n;
231
232 *strength=(t[m]>0?(double)(t[m]-t[f])/t[m]:0.0);
233 }
234
235 return m;
236 }
237
238 static int put_image(struct vf_instance_s* vf, mp_image_t *mpi)
239 {
240 mp_image_t *dmpi, *tmpi=0;
241 int n, m, f, newphase;
242 struct vf_priv_s *p=vf->priv;
243 unsigned int checksum;
244 double d;
245
246 dmpi=vf_get_image(vf->next, mpi->imgfmt,
247 MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE |
248 MP_IMGFLAG_PRESERVE | MP_IMGFLAG_READABLE,
249 mpi->width, mpi->height);
250 vf_clone_mpi_attributes(dmpi, mpi);
251
252 newphase=p->phase;
253
254 switch(p->pass)
255 {
256 case 1:
257 fprintf(p->file, "%08x %d\n",
258 (unsigned int)imgop((void *)checksum_plane, mpi, 0, 0),
259 p->frameno?imgop(diff_plane, dmpi, mpi, 0):0);
260 break;
261
262 case 2:
263 if(p->frameno/5>p->bcount)
264 {
265 mp_msg(MSGT_VFILTER, MSGL_ERR,
266 "\n%s: Log file ends prematurely! "
267 "Switching to one pass mode.\n", vf->info->name);
268 p->pass=0;
269 break;
270 }
271
272 checksum=(unsigned int)imgop((void *)checksum_plane, mpi, 0, 0);
273
274 if(checksum!=p->csdata[p->frameno])
275 {
276 for(f=0; f<100; f++)
277 if(p->frameno+f<p->fcount && p->csdata[p->frameno+f]==checksum)
278 break;
279 else if(p->frameno-f>=0 && p->csdata[p->frameno-f]==checksum)
280 {
281 f=-f;
282 break;
283 }
284
285 if(f<100)
286 {
287 mp_msg(MSGT_VFILTER, MSGL_INFO,
288 "\n%s: Mismatch with pass-1: %+d frame(s).\n",
289 vf->info->name, f);
290
291 p->frameno+=f;
292 p->misscount=0;
293 }
294 else if(p->misscount++>=30)
295 {
296 mp_msg(MSGT_VFILTER, MSGL_ERR,
297 "\n%s: Sync with pass-1 lost! "
298 "Switching to one pass mode.\n", vf->info->name);
299 p->pass=0;
300 break;
301 }
302 }
303
304 n=(p->frameno)/5;
305 if(n>=p->bcount) n=p->bcount-1;
306
307 newphase=p->bdata[n];
308 break;
309
310 default:
311 if(p->frameno)
312 {
313 int *sump=p->sum+p->frameno%5,
314 *histp=p->history+p->frameno%p->window;
315
316 *sump-=*histp;
317 *sump+=(*histp=imgop(diff_plane, dmpi, mpi, 0));
318 }
319
320 m=match(p, p->sum, -1, -1, &d);
321
322 if(d>=p->threshold)
323 newphase=m;
324 }
325
326 n=p->ocount++%5;
327
328 if(newphase!=p->phase && ((p->phase+4)%5<n)==((newphase+4)%5<n))
329 {
330 p->phase=newphase;
331 mp_msg(MSGT_VFILTER, MSGL_STATUS,
332 "\n%s: Telecine phase %d.\n", vf->info->name, p->phase);
333 }
334
335 switch((p->frameno++-p->phase+10)%5)
336 {
337 case 0:
338 imgop((void *)memcpy_pic, dmpi, mpi, 0);
339 return 0;
340
341 case 4:
342 if(p->deghost>0)
343 {
344 tmpi=vf_get_image(vf->next, mpi->imgfmt,
345 MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE,
346 mpi->width, mpi->height);
347 vf_clone_mpi_attributes(tmpi, mpi);
348
349 imgop((void *)memcpy_pic, tmpi, mpi, 0);
350 imgop(deghost_plane, tmpi, dmpi, p->deghost);
351 imgop((void *)memcpy_pic, dmpi, mpi, 0);
352 return vf_next_put_image(vf, tmpi);
353 }
354 }
355
356 imgop((void *)memcpy_pic, dmpi, mpi, 0);
357 return vf_next_put_image(vf, dmpi);
358 }
359
360 static int analyze(struct vf_priv_s *p)
361 {
362 int *buf=0, *bp, bufsize=0, n, b, f, i, j, m, s;
363 unsigned int *cbuf=0, *cp;
364 char *pbuf;
365 char lbuf[256];
366 int sum[5];
367 double d;
368
369 /* read the file */
370
371 n=15;
372 while(fgets(lbuf, 256, p->file))
373 {
374 if(n>=bufsize-19)
375 {
376 bufsize=bufsize?bufsize*2:30000;
377 if((bp=realloc(buf, bufsize*sizeof *buf))) buf=bp;
378 if((cp=realloc(cbuf, bufsize*sizeof *cbuf))) cbuf=cp;
379
380 if(!bp || !cp)
381 {
382 mp_msg(MSGT_VFILTER, MSGL_FATAL, "%s: Not enough memory.\n",
383 vf_info_divtc.name);
384 free(buf);
385 free(cbuf);
386 return 0;
387 }
388 }
389 sscanf(lbuf, "%x %d", cbuf+n, buf+n);
390 n++;
391 }
392
393 if(!n)
394 {
395 mp_msg(MSGT_VFILTER, MSGL_FATAL, "%s: Empty 2-pass log file.\n",
396 vf_info_divtc.name);
397 free(buf);
398 free(cbuf);
399 return 0;
400 }
401
402 /* generate some dummy data past the beginning and end of the array */
403
404 buf+=15, cbuf+=15;
405 n-=15;
406
407 memcpy(buf-15, buf, 15*sizeof *buf);
408 memset(cbuf-15, 0, 15*sizeof *cbuf);
409
410 while(n%5)
411 buf[n]=buf[n-5], cbuf[n]=0, n++;
412
413 memcpy(buf+n, buf+n-15, 15*sizeof *buf);
414 memset(cbuf+n, 0, 15*sizeof *cbuf);
415
416 p->csdata=cbuf;
417 p->fcount=n;
418
419 /* array with one slot for each slice of 5 frames */
420
421 p->bdata=pbuf=malloc(p->bcount=b=(n/5));
422 memset(pbuf, 255, b);
423
424 /* resolve the automatic mode */
425
426 if(p->deghost<0)
427 {
428 int deghost=-p->deghost;
429 double s0=0.0, s1=0.0;
430
431 for(f=0; f<n; f+=5)
432 {
433 p->deghost=0; match(p, buf+f, -1, -1, &d); s0+=d;
434 p->deghost=1; match(p, buf+f, -1, -1, &d); s1+=d;
435 }
436
437 p->deghost=s1>s0?deghost:0;
438
439 mp_msg(MSGT_VFILTER, MSGL_INFO,
440 "%s: Deghosting %-3s (relative pattern strength %+.2fdB).\n",
441 vf_info_divtc.name,
442 p->deghost?"ON":"OFF",
443 10.0*log10(s1/s0));
444 }
445
446 /* analyze the data */
447
448 for(f=0; f<5; f++)
449 for(sum[f]=0, n=-15; n<20; n+=5)
450 sum[f]+=buf[n+f];
451
452 for(f=0; f<b; f++)
453 {
454 m=match(p, sum, -1, -1, &d);
455
456 if(d>=p->threshold)
457 pbuf[f]=m;
458
459 if(f<b-1)
460 for(n=0; n<5; n++)
461 sum[n]=sum[n]-buf[5*(f-3)+n]+buf[5*(f+4)+n];
462 }
463
464 /* fill in the gaps */
465
466 /* the beginning */
467 for(f=0; f<b && pbuf[f]==-1; f++);
468
469 if(f==b)
470 {
471 free(buf-15);
472 mp_msg(MSGT_VFILTER, MSGL_FATAL, "%s: No telecine pattern found!\n",
473 vf_info_divtc.name);
474 return 0;
475 }
476
477 for(n=0; n<f; pbuf[n++]=pbuf[f]);
478
479 /* the end */
480 for(f=b-1; pbuf[f]==-1; f--);
481 for(n=f+1; n<b; pbuf[n++]=pbuf[f]);
482
483 /* the rest */
484 for(f=0;;)
485 {
486 while(f<b && pbuf[f]!=-1) f++;
487 if(f==b) break;
488 for(n=f; pbuf[n]==-1; n++);
489
490 if(pbuf[f-1]==pbuf[n])
491 {
492 /* just a gap */
493 while(f<n) pbuf[f++]=pbuf[n];
494 }
495 else
496 {
497 /* phase change, reanalyze the original data in the gap with zero
498 threshold for only the two phases that appear at the ends */
499
500 for(i=0; i<5; i++)
501 for(sum[i]=0, j=5*f-15; j<5*f; j+=5)
502 sum[i]+=buf[i+j];
503
504 for(i=f; i<n; i++)
505 {
506 pbuf[i]=match(p, sum, pbuf[f-1], pbuf[n], 0);
507
508 for(j=0; j<5; j++)
509 sum[j]=sum[j]-buf[5*(i-3)+j]+buf[5*(i+4)+j];
510 }
511
512 /* estimate the transition point by dividing the gap
513 in the same proportion as the number of matches of each kind */
514
515 for(i=f, m=f; i<n; i++)
516 if(pbuf[i]==pbuf[f-1]) m++;
517
518 /* find the transition of the right direction nearest to the
519 estimated point */
520
521 if(m>f && m<n)
522 {
523 for(j=m; j>f; j--)
524 if(pbuf[j-1]==pbuf[f-1] && pbuf[j]==pbuf[n]) break;
525 for(s=m; s<n; s++)
526 if(pbuf[s-1]==pbuf[f-1] && pbuf[s]==pbuf[n]) break;
527
528 m=(s-m<m-j)?s:j;
529 }
530
531 /* and rewrite the data to allow only this one transition */
532
533 for(i=f; i<m; i++)
534 pbuf[i]=pbuf[f-1];
535
536 for(; i<n; i++)
537 pbuf[i]=pbuf[n];
538
539 f=n;
540 }
541 }
542
543 free(buf-15);
544
545 return 1;
546 }
547
548 static int query_format(struct vf_instance_s* vf, unsigned int fmt)
549 {
550 switch(fmt)
551 {
552 case IMGFMT_444P: case IMGFMT_IYUV: case IMGFMT_RGB24:
553 case IMGFMT_422P: case IMGFMT_UYVY: case IMGFMT_BGR24:
554 case IMGFMT_411P: case IMGFMT_YUY2: case IMGFMT_IF09:
555 case IMGFMT_YV12: case IMGFMT_I420: case IMGFMT_YVU9:
556 case IMGFMT_IUYV: case IMGFMT_Y800: case IMGFMT_Y8:
557 return vf_next_query_format(vf,fmt);
558 }
559
560 return 0;
561 }
562
563 static void uninit(struct vf_instance_s* vf)
564 {
565 if(vf->priv)
566 {
567 if(vf->priv->file) fclose(vf->priv->file);
568 if(vf->priv->csdata) free(vf->priv->csdata-15);
569 free(vf->priv->bdata);
570 free(vf->priv->history);
571 free(vf->priv);
572 }
573 }
574
575 static int open(vf_instance_t *vf, char* args)
576 {
577 struct vf_priv_s *p;
578 char *filename="framediff.log", *ap, *q, *a;
579
580 if(args && !(args=strdup(args)))
581 {
582 nomem:
583 mp_msg(MSGT_VFILTER, MSGL_FATAL,
584 "%s: Not enough memory.\n", vf->info->name);
585 fail:
586 uninit(vf);
587 free(args);
588 return 0;
589 }
590
591 vf->put_image=put_image;
592 vf->uninit=uninit;
593 vf->query_format=query_format;
594 vf->default_reqs=VFCAP_ACCEPT_STRIDE;
595 if(!(vf->priv=p=calloc(1, sizeof(struct vf_priv_s))))
596 goto nomem;
597
598 p->phase=5;
599 p->threshold=0.5;
600 p->window=30;
601
602 if((ap=args))
603 while(*ap)
604 {
605 q=ap;
606 if((ap=strchr(q, ':'))) *ap++=0; else ap=q+strlen(q);
607 if((a=strchr(q, '='))) *a++=0; else a=q+strlen(q);
608
609 switch(*q)
610 {
611 case 0: break;
612 case 'f': filename=a; break;
613 case 't': p->threshold=atof(a); break;
614 case 'w': p->window=5*(atoi(a)+4)/5; break;
615 case 'd': p->deghost=atoi(a); break;
616 case 'p':
617 if(q[1]=='h') p->phase=atoi(a);
618 else p->pass=atoi(a);
619 break;
620
621 case 'h':
622 mp_msg(MSGT_VFILTER, MSGL_INFO,
623 "\n%s options:\n\n"
624 "pass=1|2 - Use 2-pass mode.\n"
625 "file=filename - Set the 2-pass log file name "
626 "(default %s).\n"
627 "threshold=value - Set the pattern recognition "
628 "sensitivity (default %g).\n"
629 "deghost=value - Select deghosting threshold "
630 "(default %d).\n"
631 "window=numframes - Set the statistics window "
632 "for 1-pass mode (default %d).\n"
633 "phase=0|1|2|3|4 - Set the initial phase "
634 "for 1-pass mode (default %d).\n\n"
635 "The option names can be abbreviated to the shortest "
636 "unique prefix.\n\n",
637 vf->info->name, filename, p->threshold, p->deghost,
638 p->window, p->phase%5);
639 break;
640
641 default:
642 mp_msg(MSGT_VFILTER, MSGL_FATAL,
643 "%s: Unknown argument %s.\n", vf->info->name, q);
644 goto fail;
645 }
646 }
647
648 switch(p->pass)
649 {
650 case 1:
651 if(!(p->file=fopen(filename, "w")))
652 {
653 mp_msg(MSGT_VFILTER, MSGL_FATAL,
654 "%s: Can't create file %s.\n", vf->info->name, filename);
655 goto fail;
656 }
657
658 break;
659
660 case 2:
661 if(!(p->file=fopen(filename, "r")))
662 {
663 mp_msg(MSGT_VFILTER, MSGL_FATAL,
664 "%s: Can't open file %s.\n", vf->info->name, filename);
665 goto fail;
666 }
667
668 if(!analyze(p))
669 goto fail;
670
671 fclose(p->file);
672 p->file=0;
673 break;
674 }
675
676 if(p->window<5) p->window=5;
677 if(!(p->history=calloc(sizeof *p->history, p->window)))
678 goto nomem;
679
680 diff=
681 #ifdef HAVE_MMX
682 gCpuCaps.hasMMX?diff_MMX:
683 #endif
684 diff_C;
685
686 free(args);
687 return 1;
688 }
689
690 vf_info_t vf_info_divtc =
691 {
692 "inverse telecine for deinterlaced video",
693 "divtc",
694 "Ville Saari",
695 "",
696 open,
697 NULL
698 };