1 /*
2 * Copyright (c) 2021 Paul B Mahol
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
28
31
32 int mode;
///< 0 is frame, 1 is field
34 int deint;
///< which frames to deinterlace
35 int rslope;
///< best edge slope search radius
36 int redge;
///< best edge match search radius
37 int ecost;
///< edge cost for edge matching
38 int mcost;
///< middle cost for edge matching
39 int dcost;
///< distance cost for edge matching
40 int interp;
///< type of interpolation
41 int linesize[4];
///< bytes of pixel data per line for each plane
44 int field;
///< which field are we on, 0 or 1
51
53 const uint8_t *prev_line, const uint8_t *next_line,
54 const uint8_t *prev2_line, const uint8_t *next2_line,
55 const uint8_t *prev3_line, const uint8_t *next3_line,
58
60 const uint8_t *const next,
61 const uint8_t *const prev2,
62 const uint8_t *const next2,
63 const uint8_t *const prev3,
64 const uint8_t *const next3,
65 int end,
int x,
int k,
int depth);
66
68 const uint16_t *const next,
69 const uint16_t *const prev2,
70 const uint16_t *const next2,
71 const uint16_t *const prev3,
72 const uint16_t *const next3,
73 int end,
int x,
int k,
int depth);
75
77 #define S (MAX_R * 2 + 1)
78
79 #define OFFSET(x) offsetof(ESTDIFContext, x)
80 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
81 #define CONST(name, help, val, u) { name, help, 0, AV_OPT_TYPE_CONST, {.i64=val}, 0, 0, FLAGS, .unit = u }
82
85 CONST(
"frame",
"send one frame for each frame", 0,
"mode"),
86 CONST(
"field",
"send one frame for each field", 1,
"mode"),
88 CONST(
"tff",
"assume top field first", 0,
"parity"),
89 CONST(
"bff",
"assume bottom field first", 1,
"parity"),
90 CONST(
"auto",
"auto detect parity", -1,
"parity"),
92 CONST(
"all",
"deinterlace all frames", 0,
"deint"),
93 CONST(
"interlaced",
"only deinterlace frames marked as interlaced", 1,
"deint"),
100 CONST(
"2p",
"two-point interpolation", 0,
"interp"),
101 CONST(
"4p",
"four-point interpolation", 1,
"interp"),
102 CONST(
"6p",
"six-point interpolation", 2,
"interp"),
104 };
105
107
132 };
133
135 {
141
145
146 return 0;
147 }
148
152
153 #define MIDL(type, ss) \
154 static unsigned midl_##ss(const type *const prev, \
155 const type *const next, \
156 int end, int x, int k) \
157 { \
158 return (prev[av_clip(x + k, 0, end)] + \
159 next[av_clip(x - k, 0, end)] + 1) >> 1; \
160 }
161
164
165 #define MID2(type, ss) \
166 static unsigned mid2_##ss(const type *const prev, \
167 const type *const next, \
168 const type *const prev2, \
169 const type *const next2, \
170 const type *const prev3, \
171 const type *const next3, \
172 int end, int x, int k, int depth) \
173 { \
174 return (prev[av_clip(x + k, 0, end)] + \
175 next[av_clip(x - k, 0, end)] + 1) >> 1; \
176 }
177
180
181 #define MID4(type, ss) \
182 static unsigned mid4_##ss(const type *const prev, \
183 const type *const next, \
184 const type *const prev2, \
185 const type *const next2, \
186 const type *const prev3, \
187 const type *const next3, \
188 int end, int x, int k, int depth) \
189 { \
190 return av_clip_uintp2_c(( \
191 9 * (prev[av_clip(x + k, 0, end)] + \
192 next[av_clip(x - k, 0, end)]) - \
193 1 * (prev2[av_clip(x + k*3, 0, end)] + \
194 next2[av_clip(x - k*3, 0, end)]) + 8) >> 4, \
195 depth); \
196 }
197
200
201 #define MID6(type, ss) \
202 static unsigned mid6_##ss(const type *const prev, \
203 const type *const next, \
204 const type *const prev2, \
205 const type *const next2, \
206 const type *const prev3, \
207 const type *const next3, \
208 int end, int x, int k, int depth) \
209 { \
210 return av_clip_uintp2_c(( \
211 20 * (prev[av_clip(x + k, 0, end)] + \
212 next[av_clip(x - k, 0, end)]) - \
213 5 * (prev2[av_clip(x + k*3, 0, end)] + \
214 next2[av_clip(x - k*3, 0, end)]) + \
215 1 * (prev3[av_clip(x + k*5, 0, end)] + \
216 next3[av_clip(x - k*5, 0, end)]) + 16) >> 5, \
217 depth); \
218 }
219
222
223 #define DIFF(type, ss) \
224 static unsigned diff_##ss(const type *const prev, \
225 const type *const next, \
226 int x, int y) \
227 { \
228 return FFABS(prev[x] - next[y]); \
229 }
230
233
234 #define COST(type, ss) \
235 static unsigned cost_##ss(const type *const prev, \
236 const type *const next, \
237 int end, int x, int k) \
238 { \
239 const int m = midl_##ss(prev, next, end, x, k); \
240 const int p = prev[x]; \
241 const int n = next[x]; \
242 \
243 return FFABS(p - m) + FFABS(n - m); \
244 }
245
248
249 #define INTERPOLATE(type, atype, amax, ss) \
250 static void interpolate_##ss(ESTDIFContext *s, uint8_t *ddst, \
251 const uint8_t *const pprev_line, \
252 const uint8_t *const nnext_line, \
253 const uint8_t *const pprev2_line, \
254 const uint8_t *const nnext2_line, \
255 const uint8_t *const pprev3_line, \
256 const uint8_t *const nnext3_line, \
257 int x, int width, int rslope, \
258 int redge, int depth, \
259 int *K) \
260 { \
261 type *dst = (type *)ddst; \
262 const type *const prev_line = (const type *const)pprev_line; \
263 const type *const prev2_line = (const type *const)pprev2_line; \
264 const type *const prev3_line = (const type *const)pprev3_line; \
265 const type *const next_line = (const type *const)nnext_line; \
266 const type *const next2_line = (const type *const)nnext2_line; \
267 const type *const next3_line = (const type *const)nnext3_line; \
268 const int interp = s->interp; \
269 const int ecost = s->ecost; \
270 const int dcost = s->dcost; \
271 const int mcost = s->mcost; \
272 atype sd[S], sD[S], di = 0; \
273 const int end = width - 1; \
274 atype dmin = amax; \
275 int id = 0, iD = 0; \
276 int k = *K; \
277 \
278 for (int i = -rslope; i <= rslope && abs(k) > rslope; i++) { \
279 atype sum = 0; \
280 \
281 for (int j = -redge; j <= redge; j++) { \
282 const int xx = av_clip(x + i + j, 0, end); \
283 const int yy = av_clip(x - i + j, 0, end); \
284 sum += diff_##ss(prev_line, next_line, xx, yy); \
285 sum += diff_##ss(prev2_line, prev_line, xx, yy); \
286 sum += diff_##ss(next_line, next2_line, xx, yy); \
287 } \
288 \
289 sD[i + rslope] = ecost * sum; \
290 sD[i + rslope] += mcost * cost_##ss(prev_line, next_line, end, x, i);\
291 sD[i + rslope] += dcost * abs(i); \
292 \
293 if (dmin > sD[i + rslope]) { \
294 dmin = sD[i + rslope]; \
295 di = 1; \
296 iD = i; \
297 } \
298 } \
299 \
300 for (int i = -rslope; i <= rslope; i++) { \
301 atype sum = 0; \
302 \
303 for (int j = -redge; j <= redge; j++) { \
304 const int xx = av_clip(x + k + i + j, 0, end); \
305 const int yy = av_clip(x - k - i + j, 0, end); \
306 sum += diff_##ss(prev_line, next_line, xx, yy); \
307 sum += diff_##ss(prev2_line, prev_line, xx, yy); \
308 sum += diff_##ss(next_line, next2_line, xx, yy); \
309 } \
310 \
311 sd[i + rslope] = ecost * sum; \
312 sd[i + rslope] += mcost * cost_##ss(prev_line, next_line, end, x, k+i);\
313 sd[i + rslope] += dcost * abs(k + i); \
314 \
315 if (dmin > sd[i + rslope]) { \
316 dmin = sd[i + rslope]; \
317 di = 0; \
318 id = i; \
319 } \
320 } \
321 \
322 k = di ? iD : k + id; \
323 \
324 dst[x] = s->mid_##ss[interp](prev_line, next_line, \
325 prev2_line, next2_line, \
326 prev3_line, next3_line, \
327 end, x, k, depth); \
328 \
329 *K = k; \
330 }
331
334
336 int jobnr, int nb_jobs)
337 {
342 const int rslope =
s->rslope;
343 const int redge =
s->redge;
344 const int depth =
s->depth;
348
349 for (
int plane = 0; plane <
s->nb_planes; plane++) {
350 const uint8_t *src_data = in->
data[plane];
351 uint8_t *dst_data =
out->data[plane];
352 const int linesize =
s->linesize[plane];
353 const int width =
s->planewidth[plane];
354 const int height =
s->planeheight[plane];
355 const int src_linesize = in->
linesize[plane];
356 const int dst_linesize =
out->linesize[plane];
357 const int start = (
height * jobnr) / nb_jobs;
358 const int end = (
height * (jobnr+1)) / nb_jobs;
359 const uint8_t *prev_line, *prev2_line, *next_line, *next2_line, *in_line;
360 const uint8_t *prev3_line, *next3_line;
361 uint8_t *out_line;
362 int y_out;
363
364 y_out = start + (tff ^ (start & 1));
365
366 in_line = src_data + (y_out * src_linesize);
367 out_line = dst_data + (y_out * dst_linesize);
368
369 while (y_out < end) {
370 memcpy(out_line, in_line, linesize);
371 y_out += 2;
372 in_line += src_linesize * 2;
373 out_line += dst_linesize * 2;
374 }
375
376 y_out = start + ((!tff) ^ (start & 1));
377 out_line = dst_data + (y_out * dst_linesize);
378
379 for (int y = y_out; y < end; y += 2) {
380 int y_prev3_in = y - 5;
381 int y_next3_in = y + 5;
382 int y_prev2_in = y - 3;
383 int y_next2_in = y + 3;
384 int y_prev_in = y - 1;
385 int y_next_in = y + 1;
386 int k;
387
388 while (y_prev3_in < 0)
389 y_prev3_in += 2;
390
391 while (y_next3_in >=
height)
392 y_next3_in -= 2;
393
394 while (y_prev2_in < 0)
395 y_prev2_in += 2;
396
397 while (y_next2_in >=
height)
398 y_next2_in -= 2;
399
400 while (y_prev_in < 0)
401 y_prev_in += 2;
402
403 while (y_next_in >=
height)
404 y_next_in -= 2;
405
406 prev3_line = src_data + (y_prev3_in * src_linesize);
407 next3_line = src_data + (y_next3_in * src_linesize);
408
409 prev2_line = src_data + (y_prev2_in * src_linesize);
410 next2_line = src_data + (y_next2_in * src_linesize);
411
412 prev_line = src_data + (y_prev_in * src_linesize);
413 next_line = src_data + (y_next_in * src_linesize);
414
415 k = 0;
416
417 for (
int x = 0; x <
width; x++) {
418 s->interpolate(
s, out_line,
419 prev_line, next_line,
420 prev2_line, next2_line,
421 prev3_line, next3_line,
422 x,
width, rslope, redge, depth, &k);
423 }
424
425 out_line += 2 * dst_linesize;
426 }
427 }
428
429 return 0;
430 }
431
433 {
438
446
449 FFMIN(
s->planeheight[1] / 2,
s->nb_threads));
450
452 s->field = !
s->field;
453
455 }
456
458 {
463
466
468 s->planeheight[0] =
s->planeheight[3] =
inlink->h;
470 s->planewidth[0] =
s->planewidth[3] =
inlink->w;
471
475 }
476
479 s->depth =
desc->comp[0].depth;
480 s->interpolate =
s->depth <= 8 ? interpolate_8 : interpolate_16;
481 s->mid_8[0] = mid2_8;
482 s->mid_8[1] = mid4_8;
483 s->mid_8[2] = mid6_8;
484 s->mid_16[0] = mid2_16;
485 s->mid_16[1] = mid4_16;
486 s->mid_16[2] = mid6_16;
487 s->max = (1 << (
s->depth)) - 1;
488
489 return 0;
490 }
492 {
496
499 return 0;
500 }
501
504 s->prev->duration *= 2;
508 }
509
511 s->prev->duration * (
s->mode ? 1 : 2));
512 if (ret < 0 || s->
mode == 0) {
516 }
517
522 }
523
525 {
530
533
535
538
539 if (!next)
541
543 ctx->outputs[0]->time_base);
546 }
else if (
ret < 0) {
548 }
549
551 }
552
554 {
556
558 }
559
561 {
566 },
567 };
568
570 {
575 },
576 };
577
581 .p.priv_class = &estdif_class,
589 };