vf_ivtc.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. /*
  2. * This file is part of MPlayer.
  3. *
  4. * MPlayer is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * MPlayer is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along
  15. * with MPlayer; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. */
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include "config.h"
  22. #include "mp_msg.h"
  23. #include "cpudetect.h"
  24. #include "img_format.h"
  25. #include "mp_image.h"
  26. #include "vf.h"
  27. #include "libvo/fastmemcpy.h"
  28. struct metrics {
  29. /* difference: total, even lines, odd lines */
  30. int d, e, o;
  31. /* noise: temporal, spacial (current), spacial (past) */
  32. int t, s, p;
  33. };
  34. struct frameinfo {
  35. /* peak, relative, mean */
  36. struct metrics p, r, m;
  37. };
  38. struct vf_priv_s {
  39. struct frameinfo fi[2];
  40. mp_image_t *dmpi;
  41. int first;
  42. int drop, lastdrop, dropnext;
  43. int inframes, outframes;
  44. };
  45. enum {
  46. F_DROP,
  47. F_MERGE,
  48. F_NEXT,
  49. F_SHOW
  50. };
  51. #if HAVE_MMX && HAVE_EBX_AVAILABLE
  52. static void block_diffs_MMX(struct metrics *m, unsigned char *old, unsigned char *new, int os, int ns)
  53. {
  54. int i;
  55. short out[24]; // output buffer for the partial metrics from the mmx code
  56. __asm__ (
  57. "movl $4, %%ecx \n\t"
  58. "pxor %%mm4, %%mm4 \n\t" // 4 even difference sums
  59. "pxor %%mm5, %%mm5 \n\t" // 4 odd difference sums
  60. "pxor %%mm7, %%mm7 \n\t" // all zeros
  61. ASMALIGN(4)
  62. "1: \n\t"
  63. // Even difference
  64. "movq (%%"REG_S"), %%mm0 \n\t"
  65. "movq (%%"REG_S"), %%mm2 \n\t"
  66. "add %%"REG_a", %%"REG_S" \n\t"
  67. "movq (%%"REG_D"), %%mm1 \n\t"
  68. "add %%"REG_b", %%"REG_D" \n\t"
  69. "psubusb %%mm1, %%mm2 \n\t"
  70. "psubusb %%mm0, %%mm1 \n\t"
  71. "movq %%mm2, %%mm0 \n\t"
  72. "movq %%mm1, %%mm3 \n\t"
  73. "punpcklbw %%mm7, %%mm0 \n\t"
  74. "punpcklbw %%mm7, %%mm1 \n\t"
  75. "punpckhbw %%mm7, %%mm2 \n\t"
  76. "punpckhbw %%mm7, %%mm3 \n\t"
  77. "paddw %%mm0, %%mm4 \n\t"
  78. "paddw %%mm1, %%mm4 \n\t"
  79. "paddw %%mm2, %%mm4 \n\t"
  80. "paddw %%mm3, %%mm4 \n\t"
  81. // Odd difference
  82. "movq (%%"REG_S"), %%mm0 \n\t"
  83. "movq (%%"REG_S"), %%mm2 \n\t"
  84. "add %%"REG_a", %%"REG_S" \n\t"
  85. "movq (%%"REG_D"), %%mm1 \n\t"
  86. "add %%"REG_b", %%"REG_D" \n\t"
  87. "psubusb %%mm1, %%mm2 \n\t"
  88. "psubusb %%mm0, %%mm1 \n\t"
  89. "movq %%mm2, %%mm0 \n\t"
  90. "movq %%mm1, %%mm3 \n\t"
  91. "punpcklbw %%mm7, %%mm0 \n\t"
  92. "punpcklbw %%mm7, %%mm1 \n\t"
  93. "punpckhbw %%mm7, %%mm2 \n\t"
  94. "punpckhbw %%mm7, %%mm3 \n\t"
  95. "paddw %%mm0, %%mm5 \n\t"
  96. "paddw %%mm1, %%mm5 \n\t"
  97. "paddw %%mm2, %%mm5 \n\t"
  98. "paddw %%mm3, %%mm5 \n\t"
  99. "decl %%ecx \n\t"
  100. "jnz 1b \n\t"
  101. "movq %%mm4, (%%"REG_d") \n\t"
  102. "movq %%mm5, 8(%%"REG_d") \n\t"
  103. :
  104. : "S" (old), "D" (new), "a" (os), "b" (ns), "d" (out)
  105. : "memory"
  106. );
  107. m->e = out[0]+out[1]+out[2]+out[3];
  108. m->o = out[4]+out[5]+out[6]+out[7];
  109. m->d = m->e + m->o;
  110. __asm__ (
  111. // First loop to measure first four columns
  112. "movl $4, %%ecx \n\t"
  113. "pxor %%mm4, %%mm4 \n\t" // Past spacial noise
  114. "pxor %%mm5, %%mm5 \n\t" // Temporal noise
  115. "pxor %%mm6, %%mm6 \n\t" // Current spacial noise
  116. ASMALIGN(4)
  117. "2: \n\t"
  118. "movq (%%"REG_S"), %%mm0 \n\t"
  119. "movq (%%"REG_S",%%"REG_a"), %%mm1 \n\t"
  120. "add %%"REG_a", %%"REG_S" \n\t"
  121. "add %%"REG_a", %%"REG_S" \n\t"
  122. "movq (%%"REG_D"), %%mm2 \n\t"
  123. "movq (%%"REG_D",%%"REG_b"), %%mm3 \n\t"
  124. "add %%"REG_b", %%"REG_D" \n\t"
  125. "add %%"REG_b", %%"REG_D" \n\t"
  126. "punpcklbw %%mm7, %%mm0 \n\t"
  127. "punpcklbw %%mm7, %%mm1 \n\t"
  128. "punpcklbw %%mm7, %%mm2 \n\t"
  129. "punpcklbw %%mm7, %%mm3 \n\t"
  130. "paddw %%mm1, %%mm4 \n\t"
  131. "paddw %%mm1, %%mm5 \n\t"
  132. "paddw %%mm3, %%mm6 \n\t"
  133. "psubw %%mm0, %%mm4 \n\t"
  134. "psubw %%mm2, %%mm5 \n\t"
  135. "psubw %%mm2, %%mm6 \n\t"
  136. "decl %%ecx \n\t"
  137. "jnz 2b \n\t"
  138. "movq %%mm0, %%mm1 \n\t"
  139. "movq %%mm0, %%mm2 \n\t"
  140. "movq %%mm0, %%mm3 \n\t"
  141. "pcmpgtw %%mm4, %%mm1 \n\t"
  142. "pcmpgtw %%mm5, %%mm2 \n\t"
  143. "pcmpgtw %%mm6, %%mm3 \n\t"
  144. "pxor %%mm1, %%mm4 \n\t"
  145. "pxor %%mm2, %%mm5 \n\t"
  146. "pxor %%mm3, %%mm6 \n\t"
  147. "psubw %%mm1, %%mm4 \n\t"
  148. "psubw %%mm2, %%mm5 \n\t"
  149. "psubw %%mm3, %%mm6 \n\t"
  150. "movq %%mm4, (%%"REG_d") \n\t"
  151. "movq %%mm5, 16(%%"REG_d") \n\t"
  152. "movq %%mm6, 32(%%"REG_d") \n\t"
  153. "mov %%"REG_a", %%"REG_c" \n\t"
  154. "shl $3, %%"REG_c" \n\t"
  155. "sub %%"REG_c", %%"REG_S" \n\t"
  156. "mov %%"REG_b", %%"REG_c" \n\t"
  157. "shl $3, %%"REG_c" \n\t"
  158. "sub %%"REG_c", %%"REG_D" \n\t"
  159. // Second loop for the last four columns
  160. "movl $4, %%ecx \n\t"
  161. "pxor %%mm4, %%mm4 \n\t"
  162. "pxor %%mm5, %%mm5 \n\t"
  163. "pxor %%mm6, %%mm6 \n\t"
  164. ASMALIGN(4)
  165. "3: \n\t"
  166. "movq (%%"REG_S"), %%mm0 \n\t"
  167. "movq (%%"REG_S",%%"REG_a"), %%mm1 \n\t"
  168. "add %%"REG_a", %%"REG_S" \n\t"
  169. "add %%"REG_a", %%"REG_S" \n\t"
  170. "movq (%%"REG_D"), %%mm2 \n\t"
  171. "movq (%%"REG_D",%%"REG_b"), %%mm3 \n\t"
  172. "add %%"REG_b", %%"REG_D" \n\t"
  173. "add %%"REG_b", %%"REG_D" \n\t"
  174. "punpckhbw %%mm7, %%mm0 \n\t"
  175. "punpckhbw %%mm7, %%mm1 \n\t"
  176. "punpckhbw %%mm7, %%mm2 \n\t"
  177. "punpckhbw %%mm7, %%mm3 \n\t"
  178. "paddw %%mm1, %%mm4 \n\t"
  179. "paddw %%mm1, %%mm5 \n\t"
  180. "paddw %%mm3, %%mm6 \n\t"
  181. "psubw %%mm0, %%mm4 \n\t"
  182. "psubw %%mm2, %%mm5 \n\t"
  183. "psubw %%mm2, %%mm6 \n\t"
  184. "decl %%ecx \n\t"
  185. "jnz 3b \n\t"
  186. "movq %%mm0, %%mm1 \n\t"
  187. "movq %%mm0, %%mm2 \n\t"
  188. "movq %%mm0, %%mm3 \n\t"
  189. "pcmpgtw %%mm4, %%mm1 \n\t"
  190. "pcmpgtw %%mm5, %%mm2 \n\t"
  191. "pcmpgtw %%mm6, %%mm3 \n\t"
  192. "pxor %%mm1, %%mm4 \n\t"
  193. "pxor %%mm2, %%mm5 \n\t"
  194. "pxor %%mm3, %%mm6 \n\t"
  195. "psubw %%mm1, %%mm4 \n\t"
  196. "psubw %%mm2, %%mm5 \n\t"
  197. "psubw %%mm3, %%mm6 \n\t"
  198. "movq %%mm4, 8(%%"REG_d") \n\t"
  199. "movq %%mm5, 24(%%"REG_d") \n\t"
  200. "movq %%mm6, 40(%%"REG_d") \n\t"
  201. "emms \n\t"
  202. :
  203. : "S" (old), "D" (new), "a" ((long)os), "b" ((long)ns), "d" (out)
  204. : "memory"
  205. );
  206. m->p = m->t = m->s = 0;
  207. for (i=0; i<8; i++) {
  208. m->p += out[i];
  209. m->t += out[8+i];
  210. m->s += out[16+i];
  211. }
  212. //printf("e=%d o=%d d=%d p=%d t=%d s=%d\n", m->e, m->o, m->d, m->p, m->t, m->s);
  213. }
  214. #endif
  215. //#define MAG(a) ((a)*(a))
  216. //#define MAG(a) (abs(a))
  217. #define MAG(a) (((a)^((a)>>31))-((a)>>31))
  218. //#define LOWPASS(s) (((s)[-2] + 4*(s)[-1] + 6*(s)[0] + 4*(s)[1] + (s)[2])>>4)
  219. //#define LOWPASS(s) (((s)[-1] + 2*(s)[0] + (s)[1])>>2)
  220. #define LOWPASS(s) ((s)[0])
  221. static void block_diffs_C(struct metrics *m, unsigned char *old, unsigned char *new, int os, int ns)
  222. {
  223. int x, y, e=0, o=0, s=0, p=0, t=0;
  224. unsigned char *oldp, *newp;
  225. m->s = m->p = m->t = 0;
  226. for (x = 8; x; x--) {
  227. oldp = old++;
  228. newp = new++;
  229. s = p = t = 0;
  230. for (y = 4; y; y--) {
  231. e += MAG(newp[0]-oldp[0]);
  232. o += MAG(newp[ns]-oldp[os]);
  233. s += newp[ns]-newp[0];
  234. p += oldp[os]-oldp[0];
  235. t += oldp[os]-newp[0];
  236. oldp += os<<1;
  237. newp += ns<<1;
  238. }
  239. m->s += MAG(s);
  240. m->p += MAG(p);
  241. m->t += MAG(t);
  242. }
  243. m->e = e;
  244. m->o = o;
  245. m->d = e+o;
  246. }
  247. static void (*block_diffs)(struct metrics *, unsigned char *, unsigned char *, int, int);
  248. #define MAXUP(a,b) ((a) = ((a)>(b)) ? (a) : (b))
  249. static void diff_planes(struct frameinfo *fi,
  250. unsigned char *old, unsigned char *new, int w, int h, int os, int ns)
  251. {
  252. int x, y;
  253. struct metrics l;
  254. struct metrics *peak=&fi->p, *rel=&fi->r, *mean=&fi->m;
  255. memset(peak, 0, sizeof(struct metrics));
  256. memset(rel, 0, sizeof(struct metrics));
  257. memset(mean, 0, sizeof(struct metrics));
  258. for (y = 0; y < h-7; y += 8) {
  259. for (x = 8; x < w-8-7; x += 8) {
  260. block_diffs(&l, old+x+y*os, new+x+y*ns, os, ns);
  261. mean->d += l.d;
  262. mean->e += l.e;
  263. mean->o += l.o;
  264. mean->s += l.s;
  265. mean->p += l.p;
  266. mean->t += l.t;
  267. MAXUP(peak->d, l.d);
  268. MAXUP(peak->e, l.e);
  269. MAXUP(peak->o, l.o);
  270. MAXUP(peak->s, l.s);
  271. MAXUP(peak->p, l.p);
  272. MAXUP(peak->t, l.t);
  273. MAXUP(rel->e, l.e-l.o);
  274. MAXUP(rel->o, l.o-l.e);
  275. MAXUP(rel->s, l.s-l.t);
  276. MAXUP(rel->p, l.p-l.t);
  277. MAXUP(rel->t, l.t-l.p);
  278. MAXUP(rel->d, l.t-l.s); /* hack */
  279. }
  280. }
  281. x = (w/8-2)*(h/8);
  282. mean->d /= x;
  283. mean->e /= x;
  284. mean->o /= x;
  285. mean->s /= x;
  286. mean->p /= x;
  287. mean->t /= x;
  288. }
  289. static void diff_fields(struct frameinfo *fi, mp_image_t *old, mp_image_t *new)
  290. {
  291. diff_planes(fi, old->planes[0], new->planes[0],
  292. new->w, new->h, old->stride[0], new->stride[0]);
  293. }
  294. static void stats(struct frameinfo *f)
  295. {
  296. mp_msg(MSGT_VFILTER, MSGL_V, " pd=%d re=%d ro=%d rp=%d rt=%d rs=%d rd=%d pp=%d pt=%d ps=%d\r",
  297. f->p.d, f->r.e, f->r.o, f->r.p, f->r.t, f->r.s, f->r.d, f->p.p, f->p.t, f->p.s);
  298. }
  299. static int foo(struct vf_priv_s *p, mp_image_t *new, mp_image_t *cur)
  300. {
  301. struct frameinfo *f = p->fi;
  302. f[0] = f[1];
  303. diff_fields(&f[1], cur, new);
  304. stats(&f[1]);
  305. // Immediately drop this frame if it's already been used.
  306. if (p->dropnext) {
  307. p->dropnext = 0;
  308. return F_DROP;
  309. }
  310. // Sometimes a pulldown frame comes all by itself, so both
  311. // its top and bottom field are duplicates from the adjacent
  312. // two frames. We can just drop such a frame, but we
  313. // immediately show the next frame instead to keep the frame
  314. // drops evenly spaced during normal 3:2 pulldown sequences.
  315. if ((3*f[1].r.o < f[1].r.e) && (f[1].r.s < f[1].r.d)) {
  316. p->dropnext = 1;
  317. return F_NEXT;
  318. }
  319. // If none of these conditions hold, we will consider the frame
  320. // progressive and just show it as-is.
  321. if (!( (3*f[0].r.e < f[0].r.o) ||
  322. ((2*f[0].r.d < f[0].r.s) && (f[0].r.s > 1200)) ||
  323. ((2*f[1].r.t < f[1].r.p) && (f[1].r.p > 1200)) ))
  324. return F_SHOW;
  325. // Otherwise, we have to decide whether to merge or drop.
  326. // If the noise metric only increases minimally, we're off
  327. // to a good start...
  328. if (((2*f[1].r.t < 3*f[1].r.p) && (f[1].r.t < 3600)) ||
  329. (f[1].r.t < 900) || (f[1].r.d < 900)) {
  330. // ...and if noise decreases or the duplicate even field
  331. // is detected, we go ahead with the merge.
  332. if ((3*f[0].r.e < f[0].r.o) || (2*f[1].r.t < f[1].r.p)) {
  333. p->dropnext = 1;
  334. return F_MERGE;
  335. }
  336. }
  337. return F_DROP;
  338. }
  339. static void copy_image(mp_image_t *dmpi, mp_image_t *mpi, int field)
  340. {
  341. switch (field) {
  342. case 0:
  343. my_memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h/2,
  344. dmpi->stride[0]*2, mpi->stride[0]*2);
  345. if (mpi->flags & MP_IMGFLAG_PLANAR) {
  346. my_memcpy_pic(dmpi->planes[1], mpi->planes[1],
  347. mpi->chroma_width, mpi->chroma_height/2,
  348. dmpi->stride[1]*2, mpi->stride[1]*2);
  349. my_memcpy_pic(dmpi->planes[2], mpi->planes[2],
  350. mpi->chroma_width, mpi->chroma_height/2,
  351. dmpi->stride[2]*2, mpi->stride[2]*2);
  352. }
  353. break;
  354. case 1:
  355. my_memcpy_pic(dmpi->planes[0]+dmpi->stride[0],
  356. mpi->planes[0]+mpi->stride[0], mpi->w, mpi->h/2,
  357. dmpi->stride[0]*2, mpi->stride[0]*2);
  358. if (mpi->flags & MP_IMGFLAG_PLANAR) {
  359. my_memcpy_pic(dmpi->planes[1]+dmpi->stride[1],
  360. mpi->planes[1]+mpi->stride[1],
  361. mpi->chroma_width, mpi->chroma_height/2,
  362. dmpi->stride[1]*2, mpi->stride[1]*2);
  363. my_memcpy_pic(dmpi->planes[2]+dmpi->stride[2],
  364. mpi->planes[2]+mpi->stride[2],
  365. mpi->chroma_width, mpi->chroma_height/2,
  366. dmpi->stride[2]*2, mpi->stride[2]*2);
  367. }
  368. break;
  369. case 2:
  370. memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h,
  371. dmpi->stride[0], mpi->stride[0]);
  372. if (mpi->flags & MP_IMGFLAG_PLANAR) {
  373. memcpy_pic(dmpi->planes[1], mpi->planes[1],
  374. mpi->chroma_width, mpi->chroma_height,
  375. dmpi->stride[1], mpi->stride[1]);
  376. memcpy_pic(dmpi->planes[2], mpi->planes[2],
  377. mpi->chroma_width, mpi->chroma_height,
  378. dmpi->stride[2], mpi->stride[2]);
  379. }
  380. break;
  381. }
  382. }
  383. static int do_put_image(struct vf_instance *vf, mp_image_t *dmpi)
  384. {
  385. struct vf_priv_s *p = vf->priv;
  386. int dropflag=0;
  387. if (!p->dropnext) switch (p->drop) {
  388. case 0:
  389. dropflag = 0;
  390. break;
  391. case 1:
  392. dropflag = (++p->lastdrop >= 5);
  393. break;
  394. case 2:
  395. dropflag = (++p->lastdrop >= 5) && (4*p->inframes <= 5*p->outframes);
  396. break;
  397. }
  398. if (dropflag) {
  399. //mp_msg(MSGT_VFILTER, MSGL_V, "drop! [%d/%d=%g]\n",
  400. // p->outframes, p->inframes, (float)p->outframes/p->inframes);
  401. mp_msg(MSGT_VFILTER, MSGL_V, "!");
  402. p->lastdrop = 0;
  403. return 0;
  404. }
  405. p->outframes++;
  406. return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE);
  407. }
  408. static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
  409. {
  410. int ret=0;
  411. struct vf_priv_s *p = vf->priv;
  412. p->inframes++;
  413. if (p->first) { /* hack */
  414. p->first = 0;
  415. return 1;
  416. }
  417. if (!p->dmpi) p->dmpi = vf_get_image(vf->next, mpi->imgfmt,
  418. MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE |
  419. MP_IMGFLAG_PRESERVE | MP_IMGFLAG_READABLE,
  420. mpi->width, mpi->height);
  421. /* FIXME -- not correct, off by one frame! */
  422. p->dmpi->qscale = mpi->qscale;
  423. p->dmpi->qstride = mpi->qstride;
  424. p->dmpi->qscale_type = mpi->qscale_type;
  425. switch (foo(p, mpi, p->dmpi)) {
  426. case F_DROP:
  427. copy_image(p->dmpi, mpi, 2);
  428. ret = 0;
  429. p->lastdrop = 0;
  430. mp_msg(MSGT_VFILTER, MSGL_V, "DROP\n");
  431. break;
  432. case F_MERGE:
  433. copy_image(p->dmpi, mpi, 0);
  434. ret = do_put_image(vf, p->dmpi);
  435. copy_image(p->dmpi, mpi, 1);
  436. mp_msg(MSGT_VFILTER, MSGL_V, "MERGE\n");
  437. p->dmpi = NULL;
  438. break;
  439. case F_NEXT:
  440. copy_image(p->dmpi, mpi, 2);
  441. ret = do_put_image(vf, p->dmpi);
  442. mp_msg(MSGT_VFILTER, MSGL_V, "NEXT\n");
  443. p->dmpi = NULL;
  444. break;
  445. case F_SHOW:
  446. ret = do_put_image(vf, p->dmpi);
  447. copy_image(p->dmpi, mpi, 2);
  448. mp_msg(MSGT_VFILTER, MSGL_V, "OK\n");
  449. p->dmpi = NULL;
  450. break;
  451. }
  452. return ret;
  453. }
  454. static int query_format(struct vf_instance *vf, unsigned int fmt)
  455. {
  456. switch (fmt) {
  457. case IMGFMT_YV12:
  458. case IMGFMT_IYUV:
  459. case IMGFMT_I420:
  460. return vf_next_query_format(vf, fmt);
  461. }
  462. return 0;
  463. }
  464. static void uninit(struct vf_instance *vf)
  465. {
  466. free(vf->priv);
  467. }
  468. static int vf_open(vf_instance_t *vf, char *args)
  469. {
  470. struct vf_priv_s *p;
  471. vf->put_image = put_image;
  472. vf->query_format = query_format;
  473. vf->uninit = uninit;
  474. vf->default_reqs = VFCAP_ACCEPT_STRIDE;
  475. vf->priv = p = calloc(1, sizeof(struct vf_priv_s));
  476. p->drop = 0;
  477. p->first = 1;
  478. if (args) sscanf(args, "%d", &p->drop);
  479. block_diffs = block_diffs_C;
  480. #if HAVE_MMX && HAVE_EBX_AVAILABLE
  481. if(gCpuCaps.hasMMX) block_diffs = block_diffs_MMX;
  482. #endif
  483. return 1;
  484. }
  485. const vf_info_t vf_info_ivtc = {
  486. "inverse telecine, take 2",
  487. "ivtc",
  488. "Rich Felker",
  489. "",
  490. vf_open,
  491. NULL
  492. };