7dd642ebc0b166921dd61e205f5d62a89d8eec8a
[ffmpeg.git] / libavfilter / libmpcodecs / vf_phase.c
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
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <limits.h>
23
24 #include "config.h"
25 #include "mp_msg.h"
26
27 #include "img_format.h"
28 #include "mp_image.h"
29 #include "vf.h"
30
31 #include "libvo/fastmemcpy.h"
32
33 enum mode { PROGRESSIVE, TOP_FIRST, BOTTOM_FIRST,
34             TOP_FIRST_ANALYZE, BOTTOM_FIRST_ANALYZE,
35             ANALYZE, FULL_ANALYZE, AUTO, AUTO_ANALYZE };
36
37 #define fixed_mode(p) ((p)<=BOTTOM_FIRST)
38
39 struct vf_priv_s
40    {
41    enum mode mode;
42    int verbose;
43    unsigned char *buf[3];
44    };
45
46 /*
47  * Copy fields from either current or buffered previous frame to the
48  * output and store the current frame unmodified to the buffer.
49  */
50
51 static void do_plane(unsigned char *to, unsigned char *from,
52                      int w, int h, int ts, int fs,
53                      unsigned char **bufp, enum mode mode)
54    {
55    unsigned char *buf, *end;
56    int top;
57
58    if(!*bufp)
59       {
60       mode=PROGRESSIVE;
61       if(!(*bufp=malloc(h*w))) return;
62       }
63
64    for(end=to+h*ts, buf=*bufp, top=1; to<end; from+=fs, to+=ts, buf+=w, top^=1)
65       {
66       fast_memcpy(to, mode==(top?BOTTOM_FIRST:TOP_FIRST)?buf:from, w);
67       fast_memcpy(buf, from, w);
68       }
69    }
70
71 /*
72  * This macro interpolates the value of both fields at a point halfway
73  * between lines and takes the squared difference. In field resolution
74  * the point is a quarter pixel below a line in one field and a quarter
75  * pixel above a line in other.
76  *
77  * (the result is actually multiplied by 25)
78  */
79
80 #define diff(a, as, b, bs) (t=((*a-b[bs])<<2)+a[as<<1]-b[-bs], t*t)
81
82 /*
83  * Find which field combination has the smallest average squared difference
84  * between the fields.
85  */
86
87 static enum mode analyze_plane(unsigned char *old, unsigned char *new,
88                                int w, int h, int os, int ns, enum mode mode,
89                                int verbose, int fields)
90    {
91    double bdiff, pdiff, tdiff, scale;
92    int bdif, tdif, pdif;
93    int top, t;
94    unsigned char *end, *rend;
95
96    if(mode==AUTO)
97       mode=fields&MP_IMGFIELD_ORDERED?fields&MP_IMGFIELD_TOP_FIRST?
98          TOP_FIRST:BOTTOM_FIRST:PROGRESSIVE;
99    else if(mode==AUTO_ANALYZE)
100       mode=fields&MP_IMGFIELD_ORDERED?fields&MP_IMGFIELD_TOP_FIRST?
101          TOP_FIRST_ANALYZE:BOTTOM_FIRST_ANALYZE:FULL_ANALYZE;
102
103    if(fixed_mode(mode))
104       bdiff=pdiff=tdiff=65536.0;
105    else
106       {
107       bdiff=pdiff=tdiff=0.0;
108
109       for(end=new+(h-2)*ns, new+=ns, old+=os, top=0;
110           new<end; new+=ns-w, old+=os-w, top^=1)
111          {
112          pdif=tdif=bdif=0;
113
114          switch(mode)
115             {
116             case TOP_FIRST_ANALYZE:
117                if(top)
118                   for(rend=new+w; new<rend; new++, old++)
119                      pdif+=diff(new, ns, new, ns),
120                      tdif+=diff(new, ns, old, os);
121                else
122                   for(rend=new+w; new<rend; new++, old++)
123                      pdif+=diff(new, ns, new, ns),
124                      tdif+=diff(old, os, new, ns);
125                break;
126
127             case BOTTOM_FIRST_ANALYZE:
128                if(top)
129                   for(rend=new+w; new<rend; new++, old++)
130                      pdif+=diff(new, ns, new, ns),
131                      bdif+=diff(old, os, new, ns);
132                else
133                   for(rend=new+w; new<rend; new++, old++)
134                      pdif+=diff(new, ns, new, ns),
135                      bdif+=diff(new, ns, old, os);
136                break;
137
138             case ANALYZE:
139                if(top)
140                   for(rend=new+w; new<rend; new++, old++)
141                      tdif+=diff(new, ns, old, os),
142                      bdif+=diff(old, os, new, ns);
143                else
144                   for(rend=new+w; new<rend; new++, old++)
145                      bdif+=diff(new, ns, old, os),
146                      tdif+=diff(old, os, new, ns);
147                break;
148
149             default: /* FULL_ANALYZE */
150                if(top)
151                   for(rend=new+w; new<rend; new++, old++)
152                      pdif+=diff(new, ns, new, ns),
153                      tdif+=diff(new, ns, old, os),
154                      bdif+=diff(old, os, new, ns);
155                else
156                   for(rend=new+w; new<rend; new++, old++)
157                      pdif+=diff(new, ns, new, ns),
158                      bdif+=diff(new, ns, old, os),
159                      tdif+=diff(old, os, new, ns);
160             }
161
162          pdiff+=(double)pdif;
163          tdiff+=(double)tdif;
164          bdiff+=(double)bdif;
165          }
166
167       scale=1.0/(w*(h-3))/25.0;
168       pdiff*=scale;
169       tdiff*=scale;
170       bdiff*=scale;
171
172       if(mode==TOP_FIRST_ANALYZE)
173          bdiff=65536.0;
174       else if(mode==BOTTOM_FIRST_ANALYZE)
175          tdiff=65536.0;
176       else if(mode==ANALYZE)
177          pdiff=65536.0;
178
179       if(bdiff<pdiff && bdiff<tdiff)
180          mode=BOTTOM_FIRST;
181       else if(tdiff<pdiff && tdiff<bdiff)
182          mode=TOP_FIRST;
183       else
184          mode=PROGRESSIVE;
185       }
186
187    if( mp_msg_test(MSGT_VFILTER,MSGL_V) )
188       {
189       mp_msg(MSGT_VFILTER, MSGL_INFO, "%c", mode==BOTTOM_FIRST?'b':mode==TOP_FIRST?'t':'p');
190       if(tdiff==65536.0) mp_msg(MSGT_VFILTER, MSGL_INFO,"     N/A "); else mp_msg(MSGT_VFILTER, MSGL_INFO," %8.2f", tdiff);
191       if(bdiff==65536.0) mp_msg(MSGT_VFILTER, MSGL_INFO,"     N/A "); else mp_msg(MSGT_VFILTER, MSGL_INFO," %8.2f", bdiff);
192       if(pdiff==65536.0) mp_msg(MSGT_VFILTER, MSGL_INFO,"     N/A "); else mp_msg(MSGT_VFILTER, MSGL_INFO," %8.2f", pdiff);
193       mp_msg(MSGT_VFILTER, MSGL_INFO,"        \n");
194       }
195
196    return mode;
197    }
198
199 static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
200    {
201    mp_image_t *dmpi;
202    int w;
203    enum mode mode;
204
205    if(!(dmpi=vf_get_image(vf->next, mpi->imgfmt,
206                           MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE,
207                           mpi->w, mpi->h)))
208       return 0;
209
210    w=dmpi->w;
211    if(!(dmpi->flags&MP_IMGFLAG_PLANAR))
212       w*=dmpi->bpp/8;
213
214    mode=vf->priv->mode;
215
216    if(!vf->priv->buf[0])
217       mode=PROGRESSIVE;
218    else
219       mode=analyze_plane(vf->priv->buf[0], mpi->planes[0],
220                          w, dmpi->h, w, mpi->stride[0], mode,
221                          vf->priv->verbose, mpi->fields);
222
223    do_plane(dmpi->planes[0], mpi->planes[0],
224             w, dmpi->h,
225             dmpi->stride[0], mpi->stride[0],
226             &vf->priv->buf[0], mode);
227
228    if(dmpi->flags&MP_IMGFLAG_PLANAR)
229       {
230       do_plane(dmpi->planes[1], mpi->planes[1],
231                dmpi->chroma_width, dmpi->chroma_height,
232                dmpi->stride[1], mpi->stride[1],
233                &vf->priv->buf[1], mode);
234       do_plane(dmpi->planes[2], mpi->planes[2],
235                dmpi->chroma_width, dmpi->chroma_height,
236                dmpi->stride[2], mpi->stride[2],
237                &vf->priv->buf[2], mode);
238       }
239
240    return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE);
241    }
242
243 static void uninit(struct vf_instance *vf)
244    {
245    free(vf->priv->buf[0]);
246    free(vf->priv->buf[1]);
247    free(vf->priv->buf[2]);
248    free(vf->priv);
249    }
250
251 static int vf_open(vf_instance_t *vf, char *args)
252    {
253    vf->put_image = put_image;
254    vf->uninit = uninit;
255    vf->default_reqs = VFCAP_ACCEPT_STRIDE;
256
257    if(!(vf->priv = calloc(1, sizeof(struct vf_priv_s))))
258       {
259       uninit(vf);
260       return 0;
261       }
262
263    vf->priv->mode=AUTO_ANALYZE;
264    vf->priv->verbose=0;
265
266    while(args && *args)
267       {
268       switch(*args)
269          {
270          case 't': vf->priv->mode=TOP_FIRST;            break;
271          case 'a': vf->priv->mode=AUTO;                 break;
272          case 'b': vf->priv->mode=BOTTOM_FIRST;         break;
273          case 'u': vf->priv->mode=ANALYZE;              break;
274          case 'T': vf->priv->mode=TOP_FIRST_ANALYZE;    break;
275          case 'A': vf->priv->mode=AUTO_ANALYZE;         break;
276          case 'B': vf->priv->mode=BOTTOM_FIRST_ANALYZE; break;
277          case 'U': vf->priv->mode=FULL_ANALYZE;         break;
278          case 'p': vf->priv->mode=PROGRESSIVE;          break;
279          case 'v': vf->priv->verbose=1;                 break;
280          case ':': break;
281
282          default:
283             uninit(vf);
284             return 0; /* bad args */
285          }
286
287       if( (args=strchr(args, ':')) ) args++;
288       }
289
290    return 1;
291    }
292
293 const vf_info_t vf_info_phase =
294    {
295    "phase shift fields",
296    "phase",
297    "Ville Saari",
298    "",
299    vf_open,
300    NULL
301    };