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