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