• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • Examples
  • File List
  • Globals

libavfilter/libmpcodecs/vf_detc.c

Go to the documentation of this file.
00001 /*
00002  * This file is part of MPlayer.
00003  *
00004  * MPlayer is free software; you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License as published by
00006  * the Free Software Foundation; either version 2 of the License, or
00007  * (at your option) any later version.
00008  *
00009  * MPlayer is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License along
00015  * with MPlayer; if not, write to the Free Software Foundation, Inc.,
00016  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00017  */
00018 
00019 #include <stdio.h>
00020 #include <stdlib.h>
00021 #include <string.h>
00022 
00023 #include "config.h"
00024 #include "mp_msg.h"
00025 
00026 #include "img_format.h"
00027 #include "mp_image.h"
00028 #include "vf.h"
00029 
00030 #include "libvo/fastmemcpy.h"
00031 
00032 struct metrics {
00033         int even;
00034         int odd;
00035         int noise;
00036         int temp;
00037 };
00038 
00039 struct vf_priv_s {
00040         int frame;
00041         int drop, lastdrop;
00042         struct metrics pm;
00043         int thres[5];
00044         int inframes, outframes;
00045         int mode;
00046         int (*analyze)(struct vf_priv_s *, mp_image_t *, mp_image_t *);
00047         int needread;
00048 };
00049 
00050 #define COMPE(a,b,e) (abs((a)-(b)) < (((a)+(b))>>(e)))
00051 #define COMPARABLE(a,b) COMPE((a),(b),2)
00052 #define VERYCLOSE(a,b) COMPE((a),(b),3)
00053 
00054 #define OUTER_TC_NBHD(s) ( \
00055  COMPARABLE((s)[-1].m.even,(s)[-1].m.odd) && \
00056  COMPARABLE((s)[1].m.even,(s)[0].m.odd) && \
00057  COMPARABLE((s)[2].m.even,(s)[1].m.odd) && \
00058  COMPARABLE((s)[-1].m.noise,(s)[0].m.temp) && \
00059  COMPARABLE((s)[2].m.noise,(s)[2].m.temp) )
00060 
00061 #define INNER_TC_NBHD(s,l,h) ( \
00062  COMPARABLE((s)[0].m.even,(l)) && \
00063  COMPARABLE((s)[2].m.odd,(l)) && ( \
00064  COMPARABLE((s)[0].m.noise,(h)) || \
00065  COMPARABLE((s)[1].m.noise,(h)) ) )
00066 
00067 enum {
00068         TC_DROP,
00069         TC_PROG,
00070         TC_IL1,
00071         TC_IL2
00072 };
00073 
00074 static void block_diffs(struct metrics *m, unsigned char *old, unsigned char *new, int os, int ns)
00075 {
00076         int x, y, even=0, odd=0, noise, temp;
00077         unsigned char *oldp, *newp;
00078         m->noise = m->temp = 0;
00079         for (x = 8; x; x--) {
00080                 oldp = old++;
00081                 newp = new++;
00082                 noise = temp = 0;
00083                 for (y = 4; y; y--) {
00084                         even += abs(newp[0]-oldp[0]);
00085                         odd += abs(newp[ns]-oldp[os]);
00086                         noise += newp[ns]-newp[0];
00087                         temp += oldp[os]-newp[0];
00088                         oldp += os<<1;
00089                         newp += ns<<1;
00090                 }
00091                 m->noise += abs(noise);
00092                 m->temp += abs(temp);
00093         }
00094         m->even = even;
00095         m->odd = odd;
00096 }
00097 
00098 static void diff_planes(struct metrics *m, unsigned char *old, unsigned char *new, int w, int h, int os, int ns)
00099 {
00100         int x, y, me=0, mo=0, mn=0, mt=0;
00101         struct metrics l;
00102         for (y = 0; y < h-7; y += 8) {
00103                 for (x = 0; x < w-7; x += 8) {
00104                         block_diffs(&l, old+x+y*os, new+x+y*ns, os, ns);
00105                         if (l.even > me) me = l.even;
00106                         if (l.odd > mo) mo = l.odd;
00107                         if (l.noise > mn) mn = l.noise;
00108                         if (l.temp > mt) mt = l.temp;
00109                 }
00110         }
00111         m->even = me;
00112         m->odd = mo;
00113         m->noise = mn;
00114         m->temp = mt;
00115 }
00116 
00117 static void diff_fields(struct metrics *metr, mp_image_t *old, mp_image_t *new)
00118 {
00119         struct metrics m, mu, mv;
00120         diff_planes(&m, old->planes[0], new->planes[0],
00121                 new->w, new->h, old->stride[0], new->stride[0]);
00122         if (new->flags & MP_IMGFLAG_PLANAR) {
00123                 diff_planes(&mu, old->planes[1], new->planes[1],
00124                         new->chroma_width, new->chroma_height,
00125                         old->stride[1], new->stride[1]);
00126                 diff_planes(&mv, old->planes[2], new->planes[2],
00127                         new->chroma_width, new->chroma_height,
00128                         old->stride[2], new->stride[2]);
00129                 if (mu.even > m.even) m.even = mu.even;
00130                 if (mu.odd > m.odd) m.odd = mu.odd;
00131                 if (mu.noise > m.noise) m.noise = mu.noise;
00132                 if (mu.temp > m.temp) m.temp = mu.temp;
00133                 if (mv.even > m.even) m.even = mv.even;
00134                 if (mv.odd > m.odd) m.odd = mv.odd;
00135                 if (mv.noise > m.noise) m.noise = mv.noise;
00136                 if (mv.temp > m.temp) m.temp = mv.temp;
00137         }
00138         *metr = m;
00139 }
00140 
00141 static void status(int f, struct metrics *m)
00142 {
00143         mp_msg(MSGT_VFILTER, MSGL_V, "frame %d: e=%d o=%d n=%d t=%d\n",
00144                 f, m->even, m->odd, m->noise, m->temp);
00145 }
00146 
00147 static int analyze_fixed_pattern(struct vf_priv_s *p, mp_image_t *new, mp_image_t *old)
00148 {
00149         if (p->frame >= 0) p->frame = (p->frame+1)%5;
00150         mp_msg(MSGT_VFILTER, MSGL_V, "frame %d\n", p->frame);
00151         switch (p->frame) {
00152         case -1: case 0: case 1: case 2:
00153                 return TC_PROG;
00154         case 3:
00155                 return TC_IL1;
00156         case 4:
00157                 return TC_IL2;
00158         }
00159         return 0;
00160 }
00161 
00162 static int analyze_aggressive(struct vf_priv_s *p, mp_image_t *new, mp_image_t *old)
00163 {
00164         struct metrics m, pm;
00165 
00166         if (p->frame >= 0) p->frame = (p->frame+1)%5;
00167 
00168         diff_fields(&m, old, new);
00169 
00170         status(p->frame, &m);
00171 
00172         pm = p->pm;
00173         p->pm = m;
00174 
00175         if (p->frame == 4) {
00176                 /* We need to break at scene changes, but is this a valid test? */
00177                 if ((m.even > p->thres[2]) && (m.odd > p->thres[2]) && (m.temp > p->thres[3])
00178                         && (m.temp > 5*pm.temp) && (m.temp*2 > m.noise)) {
00179                         mp_msg(MSGT_VFILTER, MSGL_V, "scene change breaking telecine!\n");
00180                         p->frame = -1;
00181                         return TC_DROP;
00182                 }
00183                 /* Thres. is to compensate for quantization errors when noise is low */
00184                 if (m.noise - m.temp > -p->thres[4]) {
00185                         if (COMPARABLE(m.even, pm.odd)) {
00186                                 //mp_msg(MSGT_VFILTER, MSGL_V, "confirmed field match!\n");
00187                                 return TC_IL2;
00188                         } else if ((m.even < p->thres[0]) && (m.odd < p->thres[0]) && VERYCLOSE(m.even, m.odd)
00189                                 && VERYCLOSE(m.noise,m.temp) && VERYCLOSE(m.noise,pm.noise)) {
00190                                 mp_msg(MSGT_VFILTER, MSGL_V, "interlaced frame appears in duplicate!!!\n");
00191                                 p->pm = pm; /* hack :) */
00192                                 p->frame = 3;
00193                                 return TC_IL1;
00194                         }
00195                 } else {
00196                         mp_msg(MSGT_VFILTER, MSGL_V, "mismatched telecine fields!\n");
00197                         p->frame = -1;
00198                 }
00199         }
00200 
00201         if (2*m.even*m.temp < m.odd*m.noise) {
00202                 mp_msg(MSGT_VFILTER, MSGL_V, "caught telecine sync!\n");
00203                 p->frame = 3;
00204                 return TC_IL1;
00205         }
00206 
00207         if (p->frame < 3) {
00208                 if (m.noise > p->thres[3]) {
00209                         if (m.noise > 2*m.temp) {
00210                                 mp_msg(MSGT_VFILTER, MSGL_V, "merging fields out of sequence!\n");
00211                                 return TC_IL2;
00212                         }
00213                         if ((m.noise > 2*pm.noise) && (m.even > p->thres[2]) && (m.odd > p->thres[2])) {
00214                                 mp_msg(MSGT_VFILTER, MSGL_V, "dropping horrible interlaced frame!\n");
00215                                 return TC_DROP;
00216                         }
00217                 }
00218         }
00219 
00220         switch (p->frame) {
00221         case -1:
00222                 if (4*m.noise > 5*m.temp) {
00223                         mp_msg(MSGT_VFILTER, MSGL_V, "merging fields out of sequence!\n");
00224                         return TC_IL2;
00225                 }
00226         case 0:
00227         case 1:
00228         case 2:
00229                 return TC_PROG;
00230         case 3:
00231                 if ((m.even > p->thres[1]) && (m.even > m.odd) && (m.temp > m.noise)) {
00232                         mp_msg(MSGT_VFILTER, MSGL_V, "lost telecine tracking!\n");
00233                         p->frame = -1;
00234                         return TC_PROG;
00235                 }
00236                 return TC_IL1;
00237         case 4:
00238                 return TC_IL2;
00239         }
00240         return 0;
00241 }
00242 
00243 static void copy_image(mp_image_t *dmpi, mp_image_t *mpi, int field)
00244 {
00245         switch (field) {
00246         case 0:
00247                 my_memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h/2,
00248                         dmpi->stride[0]*2, mpi->stride[0]*2);
00249                 if (mpi->flags & MP_IMGFLAG_PLANAR) {
00250                         my_memcpy_pic(dmpi->planes[1], mpi->planes[1],
00251                                 mpi->chroma_width, mpi->chroma_height/2,
00252                                 dmpi->stride[1]*2, mpi->stride[1]*2);
00253                         my_memcpy_pic(dmpi->planes[2], mpi->planes[2],
00254                                 mpi->chroma_width, mpi->chroma_height/2,
00255                                 dmpi->stride[2]*2, mpi->stride[2]*2);
00256                 }
00257                 break;
00258         case 1:
00259                 my_memcpy_pic(dmpi->planes[0]+dmpi->stride[0],
00260                         mpi->planes[0]+mpi->stride[0], mpi->w, mpi->h/2,
00261                         dmpi->stride[0]*2, mpi->stride[0]*2);
00262                 if (mpi->flags & MP_IMGFLAG_PLANAR) {
00263                         my_memcpy_pic(dmpi->planes[1]+dmpi->stride[1],
00264                                 mpi->planes[1]+mpi->stride[1],
00265                                 mpi->chroma_width, mpi->chroma_height/2,
00266                                 dmpi->stride[1]*2, mpi->stride[1]*2);
00267                         my_memcpy_pic(dmpi->planes[2]+dmpi->stride[2],
00268                                 mpi->planes[2]+mpi->stride[2],
00269                                 mpi->chroma_width, mpi->chroma_height/2,
00270                                 dmpi->stride[2]*2, mpi->stride[2]*2);
00271                 }
00272                 break;
00273         case 2:
00274                 memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h,
00275                         dmpi->stride[0], mpi->stride[0]);
00276                 if (mpi->flags & MP_IMGFLAG_PLANAR) {
00277                         memcpy_pic(dmpi->planes[1], mpi->planes[1],
00278                                 mpi->chroma_width, mpi->chroma_height,
00279                                 dmpi->stride[1], mpi->stride[1]);
00280                         memcpy_pic(dmpi->planes[2], mpi->planes[2],
00281                                 mpi->chroma_width, mpi->chroma_height,
00282                                 dmpi->stride[2], mpi->stride[2]);
00283                 }
00284                 break;
00285         }
00286 }
00287 
00288 static int do_put_image(struct vf_instance *vf, mp_image_t *dmpi)
00289 {
00290         struct vf_priv_s *p = vf->priv;
00291         int dropflag;
00292 
00293         switch (p->drop) {
00294         default:
00295                 dropflag = 0;
00296                 break;
00297         case 1:
00298                 dropflag = (++p->lastdrop >= 5);
00299                 break;
00300         case 2:
00301                 dropflag = (++p->lastdrop >= 5) && (4*p->inframes <= 5*p->outframes);
00302                 break;
00303         }
00304 
00305         if (dropflag) {
00306                 mp_msg(MSGT_VFILTER, MSGL_V, "drop! [%d/%d=%g]\n",
00307                         p->outframes, p->inframes, (float)p->outframes/p->inframes);
00308                 p->lastdrop = 0;
00309                 return 0;
00310         }
00311 
00312         p->outframes++;
00313         return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE);
00314 }
00315 
00316 static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
00317 {
00318         int ret=0;
00319         mp_image_t *dmpi;
00320         struct vf_priv_s *p = vf->priv;
00321 
00322         p->inframes++;
00323 
00324         if (p->needread) dmpi = vf_get_image(vf->next, mpi->imgfmt,
00325                 MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE |
00326                 MP_IMGFLAG_PRESERVE | MP_IMGFLAG_READABLE,
00327                 mpi->width, mpi->height);
00328         /* FIXME: is there a good way to get rid of static type? */
00329         else dmpi = vf_get_image(vf->next, mpi->imgfmt,
00330                 MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE |
00331                 MP_IMGFLAG_PRESERVE, mpi->width, mpi->height);
00332 
00333         switch (p->analyze(p, mpi, dmpi)) {
00334         case TC_DROP:
00335                 /* Don't copy anything unless we'll need to read it. */
00336                 if (p->needread) copy_image(dmpi, mpi, 2);
00337                 p->lastdrop = 0;
00338                 break;
00339         case TC_PROG:
00340                 /* Copy and display the whole frame. */
00341                 copy_image(dmpi, mpi, 2);
00342                 ret = do_put_image(vf, dmpi);
00343                 break;
00344         case TC_IL1:
00345                 /* Only copy bottom field unless we need to read. */
00346                 if (p->needread) copy_image(dmpi, mpi, 2);
00347                 else copy_image(dmpi, mpi, 1);
00348                 p->lastdrop = 0;
00349                 break;
00350         case TC_IL2:
00351                 /* Copy top field and show frame, then copy bottom if needed. */
00352                 copy_image(dmpi, mpi, 0);
00353                 ret = do_put_image(vf, dmpi);
00354                 if (p->needread) copy_image(dmpi, mpi, 1);
00355                 break;
00356         }
00357         return ret;
00358 }
00359 
00360 static int query_format(struct vf_instance *vf, unsigned int fmt)
00361 {
00362         /* FIXME - figure out which other formats work */
00363         switch (fmt) {
00364         case IMGFMT_YV12:
00365         case IMGFMT_IYUV:
00366         case IMGFMT_I420:
00367                 return vf_next_query_format(vf, fmt);
00368         }
00369         return 0;
00370 }
00371 
00372 static int config(struct vf_instance *vf,
00373         int width, int height, int d_width, int d_height,
00374         unsigned int flags, unsigned int outfmt)
00375 {
00376         return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
00377 }
00378 
00379 static void uninit(struct vf_instance *vf)
00380 {
00381         free(vf->priv);
00382 }
00383 
00384 static struct {
00385         const char *name;
00386         int (*func)(struct vf_priv_s *p, mp_image_t *new, mp_image_t *old);
00387         int needread;
00388 } anal_funcs[] = {
00389         { "fixed", analyze_fixed_pattern, 0 },
00390         { "aggressive", analyze_aggressive, 1 },
00391         { NULL, NULL, 0 }
00392 };
00393 
00394 #define STARTVARS if (0)
00395 #define GETVAR(str, name, out, func) \
00396  else if (!strncmp((str), name "=", sizeof(name))) \
00397  (out) = (func)((str) + sizeof(name))
00398 
00399 static void parse_var(struct vf_priv_s *p, char *var)
00400 {
00401         STARTVARS;
00402         GETVAR(var, "dr", p->drop, atoi);
00403         GETVAR(var, "t0", p->thres[0], atoi);
00404         GETVAR(var, "t1", p->thres[1], atoi);
00405         GETVAR(var, "t2", p->thres[2], atoi);
00406         GETVAR(var, "t3", p->thres[3], atoi);
00407         GETVAR(var, "t4", p->thres[4], atoi);
00408         GETVAR(var, "fr", p->frame, atoi);
00409         GETVAR(var, "am", p->mode, atoi);
00410 }
00411 
00412 static void parse_args(struct vf_priv_s *p, char *args)
00413 {
00414         char *next, *orig;
00415         for (args=orig=av_strdup(args); args; args=next) {
00416                 next = strchr(args, ':');
00417                 if (next) *next++ = 0;
00418                 parse_var(p, args);
00419         }
00420         free(orig);
00421 }
00422 
00423 static int vf_open(vf_instance_t *vf, char *args)
00424 {
00425         struct vf_priv_s *p;
00426         vf->config = config;
00427         vf->put_image = put_image;
00428         vf->query_format = query_format;
00429         vf->uninit = uninit;
00430         vf->default_reqs = VFCAP_ACCEPT_STRIDE;
00431         vf->priv = p = calloc(1, sizeof(struct vf_priv_s));
00432         p->frame = -1;
00433         p->thres[0] = 440;
00434         p->thres[1] = 720;
00435         p->thres[2] = 2500;
00436         p->thres[3] = 2500;
00437         p->thres[4] = 800;
00438         p->drop = 0;
00439         p->mode = 1;
00440         if (args) parse_args(p, args);
00441         p->analyze = anal_funcs[p->mode].func;
00442         p->needread = anal_funcs[p->mode].needread;
00443         return 1;
00444 }
00445 
00446 const vf_info_t vf_info_detc = {
00447     "de-telecine filter",
00448     "detc",
00449     "Rich Felker",
00450     "",
00451     vf_open,
00452     NULL
00453 };

Generated on Wed Apr 11 2012 07:31:35 for FFmpeg by  doxygen 1.7.1