00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <stdio.h>
00020 #include <stdlib.h>
00021 #include <string.h>
00022 #include <limits.h>
00023 #include <math.h>
00024
00025 #include "config.h"
00026 #include "mp_msg.h"
00027 #include "cpudetect.h"
00028 #include "libavutil/common.h"
00029 #include "mpbswap.h"
00030
00031 #include "img_format.h"
00032 #include "mp_image.h"
00033 #include "vf.h"
00034
00035 #include "libvo/fastmemcpy.h"
00036
00037 const vf_info_t vf_info_divtc;
00038
00039 struct vf_priv_s
00040 {
00041 int deghost, pass, phase, window, fcount, bcount, frameno, misscount,
00042 ocount, sum[5];
00043 double threshold;
00044 FILE *file;
00045 int8_t *bdata;
00046 unsigned int *csdata;
00047 int *history;
00048 };
00049
00050
00051
00052
00053
00054 #if HAVE_MMX && HAVE_EBX_AVAILABLE
00055 static int diff_MMX(unsigned char *old, unsigned char *new, int os, int ns)
00056 {
00057 volatile short out[4];
00058 __asm__ (
00059 "movl $8, %%ecx \n\t"
00060 "pxor %%mm4, %%mm4 \n\t"
00061 "pxor %%mm7, %%mm7 \n\t"
00062
00063 ASMALIGN(4)
00064 "1: \n\t"
00065
00066 "movq (%%"REG_S"), %%mm0 \n\t"
00067 "movq (%%"REG_S"), %%mm2 \n\t"
00068 "add %%"REG_a", %%"REG_S" \n\t"
00069 "movq (%%"REG_D"), %%mm1 \n\t"
00070 "add %%"REG_b", %%"REG_D" \n\t"
00071 "psubusb %%mm1, %%mm2 \n\t"
00072 "psubusb %%mm0, %%mm1 \n\t"
00073 "movq %%mm2, %%mm0 \n\t"
00074 "movq %%mm1, %%mm3 \n\t"
00075 "punpcklbw %%mm7, %%mm0 \n\t"
00076 "punpcklbw %%mm7, %%mm1 \n\t"
00077 "punpckhbw %%mm7, %%mm2 \n\t"
00078 "punpckhbw %%mm7, %%mm3 \n\t"
00079 "paddw %%mm0, %%mm4 \n\t"
00080 "paddw %%mm1, %%mm4 \n\t"
00081 "paddw %%mm2, %%mm4 \n\t"
00082 "paddw %%mm3, %%mm4 \n\t"
00083
00084 "decl %%ecx \n\t"
00085 "jnz 1b \n\t"
00086 "movq %%mm4, (%%"REG_d") \n\t"
00087 "emms \n\t"
00088 :
00089 : "S" (old), "D" (new), "a" ((long)os), "b" ((long)ns), "d" (out)
00090 : "%ecx", "memory"
00091 );
00092 return out[0]+out[1]+out[2]+out[3];
00093 }
00094 #endif
00095
00096 static int diff_C(unsigned char *old, unsigned char *new, int os, int ns)
00097 {
00098 int x, y, d=0;
00099
00100 for(y=8; y; y--, new+=ns, old+=os)
00101 for(x=8; x; x--)
00102 d+=abs(new[x]-old[x]);
00103
00104 return d;
00105 }
00106
00107 static int (*diff)(unsigned char *, unsigned char *, int, int);
00108
00109 static int diff_plane(unsigned char *old, unsigned char *new,
00110 int w, int h, int os, int ns, int arg)
00111 {
00112 int x, y, d, max=0, sum=0, n=0;
00113
00114 for(y=0; y<h-7; y+=8)
00115 {
00116 for(x=0; x<w-7; x+=8)
00117 {
00118 d=diff(old+x+y*os, new+x+y*ns, os, ns);
00119 if(d>max) max=d;
00120 sum+=d;
00121 n++;
00122 }
00123 }
00124
00125 return (sum+n*max)/2;
00126 }
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143 static unsigned int checksum_plane(unsigned char *p, unsigned char *z,
00144 int w, int h, int s, int zs, int arg)
00145 {
00146 unsigned int shift;
00147 uint32_t sum, t;
00148 unsigned char *e, *e2;
00149 #if HAVE_FAST_64BIT
00150 typedef uint64_t wsum_t;
00151 #else
00152 typedef uint32_t wsum_t;
00153 #endif
00154 wsum_t wsum;
00155
00156 for(sum=0; h; h--, p+=s-w)
00157 {
00158 for(shift=0, e=p+w; (int)p&(sizeof(wsum_t)-1) && p<e;)
00159 sum^=*p++<<(shift=(shift-8)&31);
00160
00161 for(wsum=0, e2=e-sizeof(wsum_t)+1; p<e2; p+=sizeof(wsum_t))
00162 wsum^=*(wsum_t *)p;
00163
00164 #if HAVE_FAST_64BIT
00165 t=be2me_32((uint32_t)(wsum>>32^wsum));
00166 #else
00167 t=be2me_32(wsum);
00168 #endif
00169
00170 for(sum^=(t<<shift|t>>(32-shift)); p<e;)
00171 sum^=*p++<<(shift=(shift-8)&31);
00172 }
00173
00174 return sum;
00175 }
00176
00177 static int deghost_plane(unsigned char *d, unsigned char *s,
00178 int w, int h, int ds, int ss, int threshold)
00179 {
00180 int t;
00181 unsigned char *e;
00182
00183 for(; h; h--, s+=ss-w, d+=ds-w)
00184 for(e=d+w; d<e; d++, s++)
00185 if(abs(*d-*s)>=threshold)
00186 *d=(t=(*d<<1)-*s)<0?0:t>255?255:t;
00187
00188 return 0;
00189 }
00190
00191 static int copyop(unsigned char *d, unsigned char *s, int bpl, int h, int dstride, int sstride, int dummy) {
00192 memcpy_pic(d, s, bpl, h, dstride, sstride);
00193 return 0;
00194 }
00195
00196 static int imgop(int(*planeop)(unsigned char *, unsigned char *,
00197 int, int, int, int, int),
00198 mp_image_t *dst, mp_image_t *src, int arg)
00199 {
00200 if(dst->flags&MP_IMGFLAG_PLANAR)
00201 return planeop(dst->planes[0], src?src->planes[0]:0,
00202 dst->w, dst->h,
00203 dst->stride[0], src?src->stride[0]:0, arg)+
00204 planeop(dst->planes[1], src?src->planes[1]:0,
00205 dst->chroma_width, dst->chroma_height,
00206 dst->stride[1], src?src->stride[1]:0, arg)+
00207 planeop(dst->planes[2], src?src->planes[2]:0,
00208 dst->chroma_width, dst->chroma_height,
00209 dst->stride[2], src?src->stride[2]:0, arg);
00210
00211 return planeop(dst->planes[0], src?src->planes[0]:0,
00212 dst->w*(dst->bpp/8), dst->h,
00213 dst->stride[0], src?src->stride[0]:0, arg);
00214 }
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224 static int match(struct vf_priv_s *p, int *diffs,
00225 int phase1, int phase2, double *strength)
00226 {
00227 static const int pattern1[]={ -4, 1, 1, 1, 1 },
00228 pattern2[]={ -2, -3, 4, 4, -3 }, *pattern;
00229 int f, m, n, t[5];
00230
00231 pattern=p->deghost>0?pattern2:pattern1;
00232
00233 for(f=0; f<5; f++)
00234 {
00235 if(phase1<0 || phase2<0 || f==phase1 || f==phase2)
00236 {
00237 for(n=t[f]=0; n<5; n++)
00238 t[f]+=diffs[n]*pattern[(n-f+5)%5];
00239 }
00240 else
00241 t[f]=INT_MIN;
00242 }
00243
00244
00245 for(m=0, n=1; n<5; n++)
00246 if(t[n]>t[m]) m=n;
00247
00248 if(strength)
00249 {
00250
00251 for(f=m?0:1, n=f+1; n<5; n++)
00252 if(n!=m && t[n]>t[f]) f=n;
00253
00254 *strength=(t[m]>0?(double)(t[m]-t[f])/t[m]:0.0);
00255 }
00256
00257 return m;
00258 }
00259
00260 static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
00261 {
00262 mp_image_t *dmpi, *tmpi=0;
00263 int n, m, f, newphase;
00264 struct vf_priv_s *p=vf->priv;
00265 unsigned int checksum;
00266 double d;
00267
00268 dmpi=vf_get_image(vf->next, mpi->imgfmt,
00269 MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE |
00270 MP_IMGFLAG_PRESERVE | MP_IMGFLAG_READABLE,
00271 mpi->width, mpi->height);
00272 vf_clone_mpi_attributes(dmpi, mpi);
00273
00274 newphase=p->phase;
00275
00276 switch(p->pass)
00277 {
00278 case 1:
00279 fprintf(p->file, "%08x %d\n",
00280 (unsigned int)imgop((void *)checksum_plane, mpi, 0, 0),
00281 p->frameno?imgop(diff_plane, dmpi, mpi, 0):0);
00282 break;
00283
00284 case 2:
00285 if(p->frameno/5>p->bcount)
00286 {
00287 mp_msg(MSGT_VFILTER, MSGL_ERR,
00288 "\n%s: Log file ends prematurely! "
00289 "Switching to one pass mode.\n", vf->info->name);
00290 p->pass=0;
00291 break;
00292 }
00293
00294 checksum=(unsigned int)imgop((void *)checksum_plane, mpi, 0, 0);
00295
00296 if(checksum!=p->csdata[p->frameno])
00297 {
00298 for(f=0; f<100; f++)
00299 if(p->frameno+f<p->fcount && p->csdata[p->frameno+f]==checksum)
00300 break;
00301 else if(p->frameno-f>=0 && p->csdata[p->frameno-f]==checksum)
00302 {
00303 f=-f;
00304 break;
00305 }
00306
00307 if(f<100)
00308 {
00309 mp_msg(MSGT_VFILTER, MSGL_INFO,
00310 "\n%s: Mismatch with pass-1: %+d frame(s).\n",
00311 vf->info->name, f);
00312
00313 p->frameno+=f;
00314 p->misscount=0;
00315 }
00316 else if(p->misscount++>=30)
00317 {
00318 mp_msg(MSGT_VFILTER, MSGL_ERR,
00319 "\n%s: Sync with pass-1 lost! "
00320 "Switching to one pass mode.\n", vf->info->name);
00321 p->pass=0;
00322 break;
00323 }
00324 }
00325
00326 n=(p->frameno)/5;
00327 if(n>=p->bcount) n=p->bcount-1;
00328
00329 newphase=p->bdata[n];
00330 break;
00331
00332 default:
00333 if(p->frameno)
00334 {
00335 int *sump=p->sum+p->frameno%5,
00336 *histp=p->history+p->frameno%p->window;
00337
00338 *sump-=*histp;
00339 *sump+=(*histp=imgop(diff_plane, dmpi, mpi, 0));
00340 }
00341
00342 m=match(p, p->sum, -1, -1, &d);
00343
00344 if(d>=p->threshold)
00345 newphase=m;
00346 }
00347
00348 n=p->ocount++%5;
00349
00350 if(newphase!=p->phase && ((p->phase+4)%5<n)==((newphase+4)%5<n))
00351 {
00352 p->phase=newphase;
00353 mp_msg(MSGT_VFILTER, MSGL_STATUS,
00354 "\n%s: Telecine phase %d.\n", vf->info->name, p->phase);
00355 }
00356
00357 switch((p->frameno++-p->phase+10)%5)
00358 {
00359 case 0:
00360 imgop(copyop, dmpi, mpi, 0);
00361 return 0;
00362
00363 case 4:
00364 if(p->deghost>0)
00365 {
00366 tmpi=vf_get_image(vf->next, mpi->imgfmt,
00367 MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE |
00368 MP_IMGFLAG_READABLE,
00369 mpi->width, mpi->height);
00370 vf_clone_mpi_attributes(tmpi, mpi);
00371
00372 imgop(copyop, tmpi, mpi, 0);
00373 imgop(deghost_plane, tmpi, dmpi, p->deghost);
00374 imgop(copyop, dmpi, mpi, 0);
00375 return vf_next_put_image(vf, tmpi, MP_NOPTS_VALUE);
00376 }
00377 }
00378
00379 imgop(copyop, dmpi, mpi, 0);
00380 return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE);
00381 }
00382
00383 static int analyze(struct vf_priv_s *p)
00384 {
00385 int *buf=0, *bp, bufsize=0, n, b, f, i, j, m, s;
00386 unsigned int *cbuf=0, *cp;
00387 int8_t *pbuf;
00388 int8_t lbuf[256];
00389 int sum[5];
00390 double d;
00391
00392
00393
00394 n=15;
00395 while(fgets(lbuf, 256, p->file))
00396 {
00397 if(n>=bufsize-19)
00398 {
00399 bufsize=bufsize?bufsize*2:30000;
00400 if((bp=realloc(buf, bufsize*sizeof *buf))) buf=bp;
00401 if((cp=realloc(cbuf, bufsize*sizeof *cbuf))) cbuf=cp;
00402
00403 if(!bp || !cp)
00404 {
00405 mp_msg(MSGT_VFILTER, MSGL_FATAL, "%s: Not enough memory.\n",
00406 vf_info_divtc.name);
00407 free(buf);
00408 free(cbuf);
00409 return 0;
00410 }
00411 }
00412 sscanf(lbuf, "%x %d", cbuf+n, buf+n);
00413 n++;
00414 }
00415
00416 if(!n)
00417 {
00418 mp_msg(MSGT_VFILTER, MSGL_FATAL, "%s: Empty 2-pass log file.\n",
00419 vf_info_divtc.name);
00420 free(buf);
00421 free(cbuf);
00422 return 0;
00423 }
00424
00425
00426
00427 buf+=15, cbuf+=15;
00428 n-=15;
00429
00430 memcpy(buf-15, buf, 15*sizeof *buf);
00431 memset(cbuf-15, 0, 15*sizeof *cbuf);
00432
00433 while(n%5)
00434 buf[n]=buf[n-5], cbuf[n]=0, n++;
00435
00436 memcpy(buf+n, buf+n-15, 15*sizeof *buf);
00437 memset(cbuf+n, 0, 15*sizeof *cbuf);
00438
00439 p->csdata=cbuf;
00440 p->fcount=n;
00441
00442
00443
00444 p->bdata=pbuf=malloc(p->bcount=b=(n/5));
00445 memset(pbuf, 255, b);
00446
00447
00448
00449 if(p->deghost<0)
00450 {
00451 int deghost=-p->deghost;
00452 double s0=0.0, s1=0.0;
00453
00454 for(f=0; f<n; f+=5)
00455 {
00456 p->deghost=0; match(p, buf+f, -1, -1, &d); s0+=d;
00457 p->deghost=1; match(p, buf+f, -1, -1, &d); s1+=d;
00458 }
00459
00460 p->deghost=s1>s0?deghost:0;
00461
00462 mp_msg(MSGT_VFILTER, MSGL_INFO,
00463 "%s: Deghosting %-3s (relative pattern strength %+.2fdB).\n",
00464 vf_info_divtc.name,
00465 p->deghost?"ON":"OFF",
00466 10.0*log10(s1/s0));
00467 }
00468
00469
00470
00471 for(f=0; f<5; f++)
00472 for(sum[f]=0, n=-15; n<20; n+=5)
00473 sum[f]+=buf[n+f];
00474
00475 for(f=0; f<b; f++)
00476 {
00477 m=match(p, sum, -1, -1, &d);
00478
00479 if(d>=p->threshold)
00480 pbuf[f]=m;
00481
00482 if(f<b-1)
00483 for(n=0; n<5; n++)
00484 sum[n]=sum[n]-buf[5*(f-3)+n]+buf[5*(f+4)+n];
00485 }
00486
00487
00488
00489
00490 for(f=0; f<b && pbuf[f]==-1; f++);
00491
00492 if(f==b)
00493 {
00494 free(buf-15);
00495 mp_msg(MSGT_VFILTER, MSGL_FATAL, "%s: No telecine pattern found!\n",
00496 vf_info_divtc.name);
00497 return 0;
00498 }
00499
00500 for(n=0; n<f; pbuf[n++]=pbuf[f]);
00501
00502
00503 for(f=b-1; pbuf[f]==-1; f--);
00504 for(n=f+1; n<b; pbuf[n++]=pbuf[f]);
00505
00506
00507 for(f=0;;)
00508 {
00509 while(f<b && pbuf[f]!=-1) f++;
00510 if(f==b) break;
00511 for(n=f; pbuf[n]==-1; n++);
00512
00513 if(pbuf[f-1]==pbuf[n])
00514 {
00515
00516 while(f<n) pbuf[f++]=pbuf[n];
00517 }
00518 else
00519 {
00520
00521
00522
00523 for(i=0; i<5; i++)
00524 for(sum[i]=0, j=5*f-15; j<5*f; j+=5)
00525 sum[i]+=buf[i+j];
00526
00527 for(i=f; i<n; i++)
00528 {
00529 pbuf[i]=match(p, sum, pbuf[f-1], pbuf[n], 0);
00530
00531 for(j=0; j<5; j++)
00532 sum[j]=sum[j]-buf[5*(i-3)+j]+buf[5*(i+4)+j];
00533 }
00534
00535
00536
00537
00538 for(i=f, m=f; i<n; i++)
00539 if(pbuf[i]==pbuf[f-1]) m++;
00540
00541
00542
00543
00544 if(m>f && m<n)
00545 {
00546 for(j=m; j>f; j--)
00547 if(pbuf[j-1]==pbuf[f-1] && pbuf[j]==pbuf[n]) break;
00548 for(s=m; s<n; s++)
00549 if(pbuf[s-1]==pbuf[f-1] && pbuf[s]==pbuf[n]) break;
00550
00551 m=(s-m<m-j)?s:j;
00552 }
00553
00554
00555
00556 for(i=f; i<m; i++)
00557 pbuf[i]=pbuf[f-1];
00558
00559 for(; i<n; i++)
00560 pbuf[i]=pbuf[n];
00561
00562 f=n;
00563 }
00564 }
00565
00566 free(buf-15);
00567
00568 return 1;
00569 }
00570
00571 static int query_format(struct vf_instance *vf, unsigned int fmt)
00572 {
00573 switch(fmt)
00574 {
00575 case IMGFMT_444P: case IMGFMT_IYUV: case IMGFMT_RGB24:
00576 case IMGFMT_422P: case IMGFMT_UYVY: case IMGFMT_BGR24:
00577 case IMGFMT_411P: case IMGFMT_YUY2: case IMGFMT_IF09:
00578 case IMGFMT_YV12: case IMGFMT_I420: case IMGFMT_YVU9:
00579 case IMGFMT_IUYV: case IMGFMT_Y800: case IMGFMT_Y8:
00580 return vf_next_query_format(vf,fmt);
00581 }
00582
00583 return 0;
00584 }
00585
00586 static void uninit(struct vf_instance *vf)
00587 {
00588 if(vf->priv)
00589 {
00590 if(vf->priv->file) fclose(vf->priv->file);
00591 if(vf->priv->csdata) free(vf->priv->csdata-15);
00592 free(vf->priv->bdata);
00593 free(vf->priv->history);
00594 free(vf->priv);
00595 }
00596 }
00597
00598 static int vf_open(vf_instance_t *vf, char *args)
00599 {
00600 struct vf_priv_s *p;
00601 const char *filename="framediff.log";
00602 char *ap, *q, *a;
00603
00604 if(args && !(args=av_strdup(args)))
00605 {
00606 nomem:
00607 mp_msg(MSGT_VFILTER, MSGL_FATAL,
00608 "%s: Not enough memory.\n", vf->info->name);
00609 fail:
00610 uninit(vf);
00611 free(args);
00612 return 0;
00613 }
00614
00615 vf->put_image=put_image;
00616 vf->uninit=uninit;
00617 vf->query_format=query_format;
00618 vf->default_reqs=VFCAP_ACCEPT_STRIDE;
00619 if(!(vf->priv=p=calloc(1, sizeof(struct vf_priv_s))))
00620 goto nomem;
00621
00622 p->phase=5;
00623 p->threshold=0.5;
00624 p->window=30;
00625
00626 if((ap=args))
00627 while(*ap)
00628 {
00629 q=ap;
00630 if((ap=strchr(q, ':'))) *ap++=0; else ap=q+strlen(q);
00631 if((a=strchr(q, '='))) *a++=0; else a=q+strlen(q);
00632
00633 switch(*q)
00634 {
00635 case 0: break;
00636 case 'f': filename=a; break;
00637 case 't': p->threshold=atof(a); break;
00638 case 'w': p->window=5*(atoi(a)+4)/5; break;
00639 case 'd': p->deghost=atoi(a); break;
00640 case 'p':
00641 if(q[1]=='h') p->phase=atoi(a);
00642 else p->pass=atoi(a);
00643 break;
00644
00645 case 'h':
00646 mp_msg(MSGT_VFILTER, MSGL_INFO,
00647 "\n%s options:\n\n"
00648 "pass=1|2 - Use 2-pass mode.\n"
00649 "file=filename - Set the 2-pass log file name "
00650 "(default %s).\n"
00651 "threshold=value - Set the pattern recognition "
00652 "sensitivity (default %g).\n"
00653 "deghost=value - Select deghosting threshold "
00654 "(default %d).\n"
00655 "window=numframes - Set the statistics window "
00656 "for 1-pass mode (default %d).\n"
00657 "phase=0|1|2|3|4 - Set the initial phase "
00658 "for 1-pass mode (default %d).\n\n"
00659 "The option names can be abbreviated to the shortest "
00660 "unique prefix.\n\n",
00661 vf->info->name, filename, p->threshold, p->deghost,
00662 p->window, p->phase%5);
00663 break;
00664
00665 default:
00666 mp_msg(MSGT_VFILTER, MSGL_FATAL,
00667 "%s: Unknown argument %s.\n", vf->info->name, q);
00668 goto fail;
00669 }
00670 }
00671
00672 switch(p->pass)
00673 {
00674 case 1:
00675 if(!(p->file=fopen(filename, "w")))
00676 {
00677 mp_msg(MSGT_VFILTER, MSGL_FATAL,
00678 "%s: Can't create file %s.\n", vf->info->name, filename);
00679 goto fail;
00680 }
00681
00682 break;
00683
00684 case 2:
00685 if(!(p->file=fopen(filename, "r")))
00686 {
00687 mp_msg(MSGT_VFILTER, MSGL_FATAL,
00688 "%s: Can't open file %s.\n", vf->info->name, filename);
00689 goto fail;
00690 }
00691
00692 if(!analyze(p))
00693 goto fail;
00694
00695 fclose(p->file);
00696 p->file=0;
00697 break;
00698 }
00699
00700 if(p->window<5) p->window=5;
00701 if(!(p->history=calloc(sizeof *p->history, p->window)))
00702 goto nomem;
00703
00704 diff = diff_C;
00705 #if HAVE_MMX && HAVE_EBX_AVAILABLE
00706 if(gCpuCaps.hasMMX) diff = diff_MMX;
00707 #endif
00708
00709 free(args);
00710 return 1;
00711 }
00712
00713 const vf_info_t vf_info_divtc =
00714 {
00715 "inverse telecine for deinterlaced video",
00716 "divtc",
00717 "Ville Saari",
00718 "",
00719 vf_open,
00720 NULL
00721 };