Mercurial > mplayer.hg
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 }; |