Mercurial > mplayer.hg
comparison libmpcodecs/vf_detc.c @ 9467:9fae4150ec43
experimental de-telecine filter. not documented or configurable yet,
but defaults seem to work ok. may change drastically over the next few
weeks.
please test it an report results!
author | rfelker |
---|---|
date | Thu, 20 Feb 2003 03:16:41 +0000 |
parents | |
children | 12eae4cb4e56 |
comparison
equal
deleted
inserted
replaced
9466:08c717b7b886 | 9467:9fae4150ec43 |
---|---|
1 #include <stdio.h> | |
2 #include <stdlib.h> | |
3 #include <string.h> | |
4 | |
5 #include "../config.h" | |
6 #include "../mp_msg.h" | |
7 | |
8 #include "img_format.h" | |
9 #include "mp_image.h" | |
10 #include "vf.h" | |
11 | |
12 #include "../libvo/fastmemcpy.h" | |
13 | |
14 struct metrics { | |
15 int even; | |
16 int odd; | |
17 int noise; | |
18 int temp; | |
19 }; | |
20 | |
21 struct vf_priv_s { | |
22 int frame; | |
23 int autosync; | |
24 int lastsync; | |
25 int lastdrop; | |
26 int oddfactor, noisefactor; | |
27 int resync; | |
28 struct metrics pm, hi, lo; | |
29 int prevscore; | |
30 }; | |
31 | |
32 static inline void *my_memcpy_pic(void * dst, void * src, int bytesPerLine, int height, int dstStride, int srcStride) | |
33 { | |
34 int i; | |
35 void *retval=dst; | |
36 | |
37 for(i=0; i<height; i++) | |
38 { | |
39 memcpy(dst, src, bytesPerLine); | |
40 src+= srcStride; | |
41 dst+= dstStride; | |
42 } | |
43 | |
44 return retval; | |
45 } | |
46 | |
47 static void block_diffs(struct metrics *m, unsigned char *old, unsigned char *new, int os, int ns) | |
48 { | |
49 int i, x, even=0, odd=0, noise=0, temp=0, sum=0; | |
50 for (i = 8; i; i--) { | |
51 for (x = 0; x < 16; x++) { | |
52 even += abs(new[x]-old[x]); | |
53 odd += abs(new[x+ns]-old[x+os]); | |
54 sum += new[x]; | |
55 noise += new[x+ns]; | |
56 temp += old[x+os]; | |
57 } | |
58 old += 2*os; new += 2*ns; | |
59 } | |
60 m->even = even; | |
61 m->odd = odd; | |
62 m->noise = abs(noise-sum); | |
63 m->temp = abs(temp-sum); | |
64 } | |
65 | |
66 | |
67 static void diff_fields(struct metrics *m, unsigned char *old, unsigned char *new, int w, int h, int os, int ns) | |
68 { | |
69 int x, y, me=0, mo=0, mn=0, mt=0; | |
70 struct metrics l; | |
71 for (y = 0; y < h-15; y += 16) { | |
72 for (x = 0; x < w-15; x += 16) { | |
73 block_diffs(&l, old+x+y*os, new+x+y*ns, os, ns); | |
74 if (l.even > me) me = l.even; | |
75 if (l.odd > mo) mo = l.odd; | |
76 if (l.noise > mn) mn = l.noise; | |
77 if (l.temp > mt) mt = l.temp; | |
78 } | |
79 } | |
80 m->even = me; | |
81 m->odd = mo; | |
82 m->noise = mn; | |
83 m->temp = mt; | |
84 } | |
85 | |
86 static status(int f, struct metrics *m, int s) | |
87 { | |
88 mp_msg(MSGT_VFILTER, MSGL_V, "frame %d: e=%d o=%d n=%d t=%d s=%d\n", | |
89 f, m->even, m->odd, m->noise, m->temp, s); | |
90 } | |
91 | |
92 static int put_image(struct vf_instance_s* vf, mp_image_t *mpi) | |
93 { | |
94 struct vf_priv_s *p = vf->priv; | |
95 mp_image_t *dmpi; | |
96 int i; | |
97 struct metrics m; | |
98 int isdup, notdup; | |
99 int islaced, notlaced; | |
100 int tcstart, tcend; | |
101 int tcscore; | |
102 | |
103 if (p->frame >= 0) | |
104 p->frame = (p->frame+1)%5; | |
105 | |
106 dmpi = vf_get_image(vf->next, mpi->imgfmt, | |
107 MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE | | |
108 MP_IMGFLAG_PRESERVE | MP_IMGFLAG_READABLE, | |
109 mpi->width, mpi->height); | |
110 | |
111 diff_fields(&m, dmpi->planes[0], mpi->planes[0], | |
112 mpi->w, mpi->h, dmpi->stride[0], mpi->stride[0]); | |
113 | |
114 isdup = m.even < p->lo.even; | |
115 notdup = m.even > p->hi.even; | |
116 | |
117 tcscore = (m.odd > p->lo.odd) + (m.odd > p->hi.odd) + (m.odd > 4*m.even) | |
118 + (m.noise > p->lo.noise) + (m.noise > p->hi.noise) | |
119 + (m.noise > m.temp) | |
120 + (m.even * p->pm.odd > m.odd * p->pm.even); | |
121 | |
122 status(p->frame, &m, tcscore); | |
123 | |
124 vf->priv->pm = m; | |
125 vf->priv->prevscore = tcscore; | |
126 | |
127 switch (vf->priv->frame) { | |
128 case 0: | |
129 case 1: | |
130 case 2: | |
131 if (isdup && (tcscore > 3)) { | |
132 //status(p->frame, &m, tcscore); | |
133 mp_msg(MSGT_VFILTER, MSGL_V, "heavy lacing, trying to resync with telecine!\n"); | |
134 vf->priv->frame = 3; | |
135 return 0; | |
136 } else if (tcscore > 5) { | |
137 //status(p->frame, &m, tcscore); | |
138 mp_msg(MSGT_VFILTER, MSGL_V, "laced scene change, trying to resync with telecine!\n"); | |
139 vf->priv->frame = 3; | |
140 return 0; | |
141 } | |
142 break; | |
143 case 3: | |
144 if (notdup && (m.noise < p->hi.noise)) { | |
145 //status(p->frame, &m, tcscore); | |
146 mp_msg(MSGT_VFILTER, MSGL_V, "non-duplicate field; lost telecine tracking!\n"); | |
147 vf->priv->frame = -1; | |
148 } | |
149 break; | |
150 case 4: | |
151 if (m.temp > p->hi.temp) { /* bad match */ | |
152 //status(p->frame, &m, tcscore); | |
153 if (m.noise < p->hi.noise) { | |
154 mp_msg(MSGT_VFILTER, MSGL_V, "mismatched non-interlaced frame; lost telecine tracking!\n"); | |
155 vf->priv->frame = -1; | |
156 } else { | |
157 mp_msg(MSGT_VFILTER, MSGL_V, "mismatched interlaced frame; trying to resync!\n"); | |
158 vf->priv->frame = 3; | |
159 } | |
160 } | |
161 break; | |
162 default: | |
163 if (!notdup && (tcscore > 2)) { | |
164 //status(p->frame, &m, tcscore); | |
165 mp_msg(MSGT_VFILTER, MSGL_V, "caught the telecine start!\n"); | |
166 vf->priv->frame = 3; | |
167 } | |
168 break; | |
169 } | |
170 | |
171 if (vf->priv->frame < 3) { | |
172 memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h, | |
173 dmpi->stride[0], mpi->stride[0]); | |
174 if (mpi->flags & MP_IMGFLAG_PLANAR) { | |
175 memcpy_pic(dmpi->planes[1], mpi->planes[1], | |
176 mpi->chroma_width, mpi->chroma_height, | |
177 dmpi->stride[1], mpi->stride[1]); | |
178 memcpy_pic(dmpi->planes[2], mpi->planes[2], | |
179 mpi->chroma_width, mpi->chroma_height, | |
180 dmpi->stride[2], mpi->stride[2]); | |
181 } | |
182 } else if (vf->priv->frame == 3) { | |
183 my_memcpy_pic(dmpi->planes[0]+dmpi->stride[0], | |
184 mpi->planes[0]+mpi->stride[0], mpi->w, mpi->h/2, | |
185 dmpi->stride[0]*2, mpi->stride[0]*2); | |
186 if (mpi->flags & MP_IMGFLAG_PLANAR) { | |
187 my_memcpy_pic(dmpi->planes[1]+dmpi->stride[1], | |
188 mpi->planes[1]+mpi->stride[1], | |
189 mpi->chroma_width, mpi->chroma_height/2, | |
190 dmpi->stride[1]*2, mpi->stride[1]*2); | |
191 my_memcpy_pic(dmpi->planes[2]+dmpi->stride[2], | |
192 mpi->planes[2]+mpi->stride[2], | |
193 mpi->chroma_width, mpi->chroma_height/2, | |
194 dmpi->stride[2]*2, mpi->stride[2]*2); | |
195 } | |
196 p->lastdrop = 0; | |
197 return 0; | |
198 } else { | |
199 my_memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h/2, | |
200 dmpi->stride[0]*2, mpi->stride[0]*2); | |
201 if (mpi->flags & MP_IMGFLAG_PLANAR) { | |
202 my_memcpy_pic(dmpi->planes[1], mpi->planes[1], | |
203 mpi->chroma_width, mpi->chroma_height/2, | |
204 dmpi->stride[1]*2, mpi->stride[1]*2); | |
205 my_memcpy_pic(dmpi->planes[2], mpi->planes[2], | |
206 mpi->chroma_width, mpi->chroma_height/2, | |
207 dmpi->stride[2]*2, mpi->stride[2]*2); | |
208 } | |
209 } | |
210 if (++p->lastdrop >= 5) { | |
211 mp_msg(MSGT_VFILTER, MSGL_V, "dropping frame!\n"); | |
212 p->lastdrop = 0; | |
213 return 0; | |
214 } | |
215 return vf_next_put_image(vf, dmpi); | |
216 } | |
217 | |
218 static int query_format(struct vf_instance_s* vf, unsigned int fmt) | |
219 { | |
220 /* FIXME - figure out which other formats work */ | |
221 switch (fmt) { | |
222 case IMGFMT_YV12: | |
223 case IMGFMT_IYUV: | |
224 case IMGFMT_I420: | |
225 return vf_next_query_format(vf, fmt); | |
226 } | |
227 return 0; | |
228 } | |
229 | |
230 static int config(struct vf_instance_s* vf, | |
231 int width, int height, int d_width, int d_height, | |
232 unsigned int flags, unsigned int outfmt) | |
233 { | |
234 return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |
235 } | |
236 | |
237 static void uninit(struct vf_instance_s* vf) | |
238 { | |
239 free(vf->priv); | |
240 } | |
241 | |
242 static int open(vf_instance_t *vf, char* args) | |
243 { | |
244 struct vf_priv_s *p; | |
245 vf->config = config; | |
246 vf->put_image = put_image; | |
247 vf->query_format = query_format; | |
248 vf->uninit = uninit; | |
249 vf->default_reqs = VFCAP_ACCEPT_STRIDE; | |
250 vf->priv = p = calloc(1, sizeof(struct vf_priv_s)); | |
251 if (args) sscanf(args, "%d:%d", &vf->priv->frame, &vf->priv->autosync); | |
252 p->frame = -1; | |
253 p->lastsync = 10; | |
254 p->lo.even = 1760; | |
255 p->hi.even = 2880; | |
256 p->lo.odd = 2560; | |
257 p->hi.odd = 10240; | |
258 p->lo.noise = 4480; | |
259 p->hi.noise = 10240; | |
260 p->lo.temp = 6400; | |
261 p->hi.temp = 12800; | |
262 vf->priv->oddfactor = 3; | |
263 vf->priv->noisefactor = 6; | |
264 return 1; | |
265 } | |
266 | |
267 vf_info_t vf_info_detc = { | |
268 "de-telecine filter", | |
269 "detc", | |
270 "Rich Felker", | |
271 "", | |
272 open | |
273 }; | |
274 | |
275 |