FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
vf_pullup.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2003 Rich Felker
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 General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 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
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include "libavutil/avassert.h"
22 #include "libavutil/imgutils.h"
23 #include "libavutil/opt.h"
24 #include "libavutil/pixdesc.h"
25 #include "avfilter.h"
26 #include "formats.h"
27 #include "internal.h"
28 #include "video.h"
29 #include "vf_pullup.h"
30 
31 #define F_HAVE_BREAKS 1
32 #define F_HAVE_AFFINITY 2
33 
34 #define BREAK_LEFT 1
35 #define BREAK_RIGHT 2
36 
37 #define OFFSET(x) offsetof(PullupContext, x)
38 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
39 
40 static const AVOption pullup_options[] = {
41  { "jl", "set left junk size", OFFSET(junk_left), AV_OPT_TYPE_INT, {.i64=1}, 0, INT_MAX, FLAGS },
42  { "jr", "set right junk size", OFFSET(junk_right), AV_OPT_TYPE_INT, {.i64=1}, 0, INT_MAX, FLAGS },
43  { "jt", "set top junk size", OFFSET(junk_top), AV_OPT_TYPE_INT, {.i64=4}, 1, INT_MAX, FLAGS },
44  { "jb", "set bottom junk size", OFFSET(junk_bottom), AV_OPT_TYPE_INT, {.i64=4}, 1, INT_MAX, FLAGS },
45  { "sb", "set strict breaks", OFFSET(strict_breaks), AV_OPT_TYPE_INT, {.i64=0},-1, 1, FLAGS },
46  { "mp", "set metric plane", OFFSET(metric_plane), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, FLAGS, "mp" },
47  { "y", "luma", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mp" },
48  { "u", "chroma blue", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "mp" },
49  { "v", "chroma red", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "mp" },
50  { NULL }
51 };
52 
53 AVFILTER_DEFINE_CLASS(pullup);
54 
56 {
57  static const enum AVPixelFormat pix_fmts[] = {
65  };
67  return 0;
68 }
69 
70 #define ABS(a) (((a) ^ ((a) >> 31)) - ((a) >> 31))
71 
72 static int diff_c(const uint8_t *a, const uint8_t *b, int s)
73 {
74  int i, j, diff = 0;
75 
76  for (i = 0; i < 4; i++) {
77  for (j = 0; j < 8; j++)
78  diff += ABS(a[j] - b[j]);
79  a += s;
80  b += s;
81  }
82 
83  return diff;
84 }
85 
86 static int comb_c(const uint8_t *a, const uint8_t *b, int s)
87 {
88  int i, j, comb = 0;
89 
90  for (i = 0; i < 4; i++) {
91  for (j = 0; j < 8; j++)
92  comb += ABS((a[j] << 1) - b[j - s] - b[j ]) +
93  ABS((b[j] << 1) - a[j ] - a[j + s]);
94  a += s;
95  b += s;
96  }
97 
98  return comb;
99 }
100 
101 static int var_c(const uint8_t *a, const uint8_t *b, int s)
102 {
103  int i, j, var = 0;
104 
105  for (i = 0; i < 3; i++) {
106  for (j = 0; j < 8; j++)
107  var += ABS(a[j] - a[j + s]);
108  a += s;
109  }
110 
111  return 4 * var; /* match comb scaling */
112 }
113 
115 {
116  f->diffs = av_calloc(FFALIGN(s->metric_length, 16), sizeof(*f->diffs));
117  f->combs = av_calloc(FFALIGN(s->metric_length, 16), sizeof(*f->combs));
118  f->vars = av_calloc(FFALIGN(s->metric_length, 16), sizeof(*f->vars));
119 
120  if (!f->diffs || !f->combs || !f->vars) {
121  av_freep(&f->diffs);
122  av_freep(&f->combs);
123  av_freep(&f->vars);
124  return AVERROR(ENOMEM);
125  }
126  return 0;
127 }
128 
130 {
131  PullupField *head, *f;
132 
133  f = head = av_mallocz(sizeof(*head));
134  if (!f)
135  return NULL;
136 
137  if (alloc_metrics(s, f) < 0) {
138  av_free(f);
139  return NULL;
140  }
141 
142  for (; len > 0; len--) {
143  f->next = av_mallocz(sizeof(*f->next));
144  if (!f->next)
145  return NULL;
146 
147  f->next->prev = f;
148  f = f->next;
149  if (alloc_metrics(s, f) < 0)
150  return NULL;
151  }
152 
153  f->next = head;
154  head->prev = f;
155 
156  return head;
157 }
158 
159 static int config_input(AVFilterLink *inlink)
160 {
161  AVFilterContext *ctx = inlink->dst;
162  PullupContext *s = ctx->priv;
163  const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
164  int mp = s->metric_plane;
165 
167 
168  if (mp + 1 > s->nb_planes) {
169  av_log(ctx, AV_LOG_ERROR, "input format does not have such plane\n");
170  return AVERROR(EINVAL);
171  }
172 
173  s->planeheight[1] = s->planeheight[2] = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
174  s->planeheight[0] = s->planeheight[3] = inlink->h;
175  s->planewidth[1] = s->planewidth[2] = FF_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
176  s->planewidth[0] = s->planewidth[3] = inlink->w;
177 
178  s->metric_w = (s->planewidth[mp] - ((s->junk_left + s->junk_right) << 3)) >> 3;
179  s->metric_h = (s->planeheight[mp] - ((s->junk_top + s->junk_bottom) << 1)) >> 3;
180  s->metric_offset = (s->junk_left << 3) + (s->junk_top << 1) * s->planewidth[mp];
181  s->metric_length = s->metric_w * s->metric_h;
182 
183  av_log(ctx, AV_LOG_DEBUG, "w: %d h: %d\n", s->metric_w, s->metric_h);
184  av_log(ctx, AV_LOG_DEBUG, "offset: %d length: %d\n", s->metric_offset, s->metric_length);
185 
186  s->head = make_field_queue(s, 8);
187  if (!s->head)
188  return AVERROR(ENOMEM);
189 
190  s->diff = diff_c;
191  s->comb = comb_c;
192  s->var = var_c;
193 
194  if (ARCH_X86)
196  return 0;
197 }
198 
199 static int config_output(AVFilterLink *outlink)
200 {
201  outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
202  return 0;
203 }
204 
206 {
207  if (!b)
208  return NULL;
209 
210  if ((parity + 1) & 1)
211  b->lock[0]++;
212  if ((parity + 1) & 2)
213  b->lock[1]++;
214 
215  return b;
216 }
217 
219 {
220  if (!b)
221  return;
222 
223  if ((parity + 1) & 1)
224  b->lock[0]--;
225  if ((parity + 1) & 2)
226  b->lock[1]--;
227 }
228 
230 {
231  int i;
232 
233  if (b->planes[0])
234  return 0;
235  for (i = 0; i < s->nb_planes; i++) {
236  b->planes[i] = av_malloc(s->planeheight[i] * s->planewidth[i]);
237  }
238 
239  return 0;
240 }
241 
243 {
244  int i;
245 
246  /* Try first to get the sister buffer for the previous field */
247  if (parity < 2 && s->last && parity != s->last->parity
248  && !s->last->buffer->lock[parity]) {
249  alloc_buffer(s, s->last->buffer);
250  return pullup_lock_buffer(s->last->buffer, parity);
251  }
252 
253  /* Prefer a buffer with both fields open */
254  for (i = 0; i < FF_ARRAY_ELEMS(s->buffers); i++) {
255  if (s->buffers[i].lock[0])
256  continue;
257  if (s->buffers[i].lock[1])
258  continue;
259  alloc_buffer(s, &s->buffers[i]);
260  return pullup_lock_buffer(&s->buffers[i], parity);
261  }
262 
263  if (parity == 2)
264  return 0;
265 
266  /* Search for any half-free buffer */
267  for (i = 0; i < FF_ARRAY_ELEMS(s->buffers); i++) {
268  if (((parity + 1) & 1) && s->buffers[i].lock[0])
269  continue;
270  if (((parity + 1) & 2) && s->buffers[i].lock[1])
271  continue;
272  alloc_buffer(s, &s->buffers[i]);
273  return pullup_lock_buffer(&s->buffers[i], parity);
274  }
275 
276  return NULL;
277 }
278 
280 {
281  PullupField *f;
282  int count = 1;
283 
284  if (!begin || !end)
285  return 0;
286 
287  for (f = begin; f != end; f = f->next)
288  count++;
289 
290  return count;
291 }
292 
293 static int find_first_break(PullupField *f, int max)
294 {
295  int i;
296 
297  for (i = 0; i < max; i++) {
298  if (f->breaks & BREAK_RIGHT || f->next->breaks & BREAK_LEFT)
299  return i + 1;
300  f = f->next;
301  }
302 
303  return 0;
304 }
305 
307 {
308  PullupField *f1 = f0->next;
309  PullupField *f2 = f1->next;
310  PullupField *f3 = f2->next;
311  int i, l, max_l = 0, max_r = 0;
312 
313  if (f0->flags & F_HAVE_BREAKS)
314  return;
315 
316  f0->flags |= F_HAVE_BREAKS;
317 
318  /* Special case when fields are 100% identical */
319  if (f0->buffer == f2->buffer && f1->buffer != f3->buffer) {
320  f2->breaks |= BREAK_RIGHT;
321  return;
322  }
323 
324  if (f0->buffer != f2->buffer && f1->buffer == f3->buffer) {
325  f1->breaks |= BREAK_LEFT;
326  return;
327  }
328 
329  for (i = 0; i < s->metric_length; i++) {
330  l = f2->diffs[i] - f3->diffs[i];
331 
332  if ( l > max_l)
333  max_l = l;
334  if (-l > max_r)
335  max_r = -l;
336  }
337 
338  /* Don't get tripped up when differences are mostly quant error */
339  if (max_l + max_r < 128)
340  return;
341  if (max_l > 4 * max_r)
342  f1->breaks |= BREAK_LEFT;
343  if (max_r > 4 * max_l)
344  f2->breaks |= BREAK_RIGHT;
345 }
346 
348 {
349  int i, max_l = 0, max_r = 0, l;
350 
351  if (f->flags & F_HAVE_AFFINITY)
352  return;
353 
354  f->flags |= F_HAVE_AFFINITY;
355 
356  if (f->buffer == f->next->next->buffer) {
357  f->affinity = 1;
358  f->next->affinity = 0;
359  f->next->next->affinity = -1;
360  f->next->flags |= F_HAVE_AFFINITY;
361  f->next->next->flags |= F_HAVE_AFFINITY;
362  return;
363  }
364 
365  for (i = 0; i < s->metric_length; i++) {
366  int v = f->vars[i];
367  int lv = f->prev->vars[i];
368  int rv = f->next->vars[i];
369  int lc = f->combs[i] - (v + lv) + ABS(v - lv);
370  int rc = f->next->combs[i] - (v + rv) + ABS(v - rv);
371 
372  lc = FFMAX(lc, 0);
373  rc = FFMAX(rc, 0);
374  l = lc - rc;
375 
376  if ( l > max_l)
377  max_l = l;
378  if (-l > max_r)
379  max_r = -l;
380  }
381 
382  if (max_l + max_r < 64)
383  return;
384 
385  if (max_r > 6 * max_l)
386  f->affinity = -1;
387  else if (max_l > 6 * max_r)
388  f->affinity = 1;
389 }
390 
392 {
393  PullupField *f0 = s->first;
394  PullupField *f1 = f0->next;
395  PullupField *f2 = f1->next;
396  PullupField *f;
397  int i, l, n;
398 
399  if (queue_length(s->first, s->last) < 4)
400  return 0;
401 
402  f = s->first;
403  n = queue_length(f, s->last);
404  for (i = 0; i < n - 1; i++) {
405  if (i < n - 3)
406  compute_breaks(s, f);
407 
408  compute_affinity(s, f);
409 
410  f = f->next;
411  }
412 
413  if (f0->affinity == -1)
414  return 1;
415 
416  l = find_first_break(f0, 3);
417 
418  if (l == 1 && s->strict_breaks < 0)
419  l = 0;
420 
421  switch (l) {
422  case 1:
423  return 1 + (s->strict_breaks < 1 && f0->affinity == 1 && f1->affinity == -1);
424  case 2:
425  /* FIXME: strictly speaking, f0->prev is no longer valid... :) */
426  if (s->strict_pairs
427  && (f0->prev->breaks & BREAK_RIGHT) && (f2->breaks & BREAK_LEFT)
428  && (f0->affinity != 1 || f1->affinity != -1) )
429  return 1;
430  return 1 + (f1->affinity != 1);
431  case 3:
432  return 2 + (f2->affinity != 1);
433  default:
434  /* 9 possibilities covered before switch */
435  if (f1->affinity == 1)
436  return 1; /* covers 6 */
437  else if (f1->affinity == -1)
438  return 2; /* covers 6 */
439  else if (f2->affinity == -1) { /* covers 2 */
440  return (f0->affinity == 1) ? 3 : 1;
441  } else {
442  return 2; /* the remaining 6 */
443  }
444  }
445 }
446 
448 {
449  PullupFrame *fr = &s->frame;
450  int i, n = decide_frame_length(s);
451  int aff = s->first->next->affinity;
452 
454  if (!n || fr->lock)
455  return NULL;
456 
457  fr->lock++;
458  fr->length = n;
459  fr->parity = s->first->parity;
460  fr->buffer = 0;
461 
462  for (i = 0; i < n; i++) {
463  /* We cheat and steal the buffer without release+relock */
464  fr->ifields[i] = s->first->buffer;
465  s->first->buffer = 0;
466  s->first = s->first->next;
467  }
468 
469  if (n == 1) {
470  fr->ofields[fr->parity ] = fr->ifields[0];
471  fr->ofields[fr->parity ^ 1] = 0;
472  } else if (n == 2) {
473  fr->ofields[fr->parity ] = fr->ifields[0];
474  fr->ofields[fr->parity ^ 1] = fr->ifields[1];
475  } else if (n == 3) {
476  if (!aff)
477  aff = (fr->ifields[0] == fr->ifields[1]) ? -1 : 1;
478  fr->ofields[fr->parity ] = fr->ifields[1 + aff];
479  fr->ofields[fr->parity ^ 1] = fr->ifields[1 ];
480  }
481 
482  pullup_lock_buffer(fr->ofields[0], 0);
483  pullup_lock_buffer(fr->ofields[1], 1);
484 
485  if (fr->ofields[0] == fr->ofields[1]) {
486  fr->buffer = fr->ofields[0];
487  pullup_lock_buffer(fr->buffer, 2);
488  return fr;
489  }
490 
491  return fr;
492 }
493 
495 {
496  int i;
497 
498  for (i = 0; i < f->length; i++)
499  pullup_release_buffer(f->ifields[i], f->parity ^ (i & 1));
500 
501  pullup_release_buffer(f->ofields[0], 0);
502  pullup_release_buffer(f->ofields[1], 1);
503 
504  if (f->buffer)
506  f->lock--;
507 }
508 
509 static void compute_metric(PullupContext *s, int *dest,
510  PullupField *fa, int pa, PullupField *fb, int pb,
511  int (*func)(const uint8_t *, const uint8_t *, int))
512 {
513  int mp = s->metric_plane;
514  int xstep = 8;
515  int ystep = s->planewidth[mp] << 3;
516  int stride = s->planewidth[mp] << 1; /* field stride */
517  int w = s->metric_w * xstep;
518  uint8_t *a, *b;
519  int x, y;
520 
521  if (!fa->buffer || !fb->buffer)
522  return;
523 
524  /* Shortcut for duplicate fields (e.g. from RFF flag) */
525  if (fa->buffer == fb->buffer && pa == pb) {
526  memset(dest, 0, s->metric_length * sizeof(*dest));
527  return;
528  }
529 
530  a = fa->buffer->planes[mp] + pa * s->planewidth[mp] + s->metric_offset;
531  b = fb->buffer->planes[mp] + pb * s->planewidth[mp] + s->metric_offset;
532 
533  for (y = 0; y < s->metric_h; y++) {
534  for (x = 0; x < w; x += xstep)
535  *dest++ = func(a + x, b + x, stride);
536  a += ystep; b += ystep;
537  }
538 }
539 
541 {
542  int ret;
543 
544  if (s->head->next == s->first) {
545  PullupField *f = av_mallocz(sizeof(*f));
546 
547  if (!f)
548  return AVERROR(ENOMEM);
549 
550  if ((ret = alloc_metrics(s, f)) < 0) {
551  av_free(f);
552  return ret;
553  }
554 
555  f->prev = s->head;
556  f->next = s->first;
557  s->head->next = f;
558  s->first->prev = f;
559  }
560 
561  return 0;
562 }
563 
565 {
566  PullupField *f;
567 
568  /* Grow the circular list if needed */
569  if (check_field_queue(s) < 0)
570  return;
571 
572  /* Cannot have two fields of same parity in a row; drop the new one */
573  if (s->last && s->last->parity == parity)
574  return;
575 
576  f = s->head;
577  f->parity = parity;
578  f->buffer = pullup_lock_buffer(b, parity);
579  f->flags = 0;
580  f->breaks = 0;
581  f->affinity = 0;
582 
583  compute_metric(s, f->diffs, f, parity, f->prev->prev, parity, s->diff);
584  compute_metric(s, f->combs, parity ? f->prev : f, 0, parity ? f : f->prev, 1, s->comb);
585  compute_metric(s, f->vars, f, parity, f, -1, s->var);
586  emms_c();
587 
588  /* Advance the circular list */
589  if (!s->first)
590  s->first = s->head;
591 
592  s->last = s->head;
593  s->head = s->head->next;
594 }
595 
596 static void copy_field(PullupContext *s,
597  PullupBuffer *dst, PullupBuffer *src, int parity)
598 {
599  uint8_t *dd, *ss;
600  int i;
601 
602  for (i = 0; i < s->nb_planes; i++) {
603  ss = src->planes[i] + parity * s->planewidth[i];
604  dd = dst->planes[i] + parity * s->planewidth[i];
605 
606  av_image_copy_plane(dd, s->planewidth[i] << 1,
607  ss, s->planewidth[i] << 1,
608  s->planewidth[i], s->planeheight[i] >> 1);
609  }
610 }
611 
613 {
614  int i;
615 
616  if (fr->buffer)
617  return;
618 
619  if (fr->length < 2)
620  return; /* FIXME: deal with this */
621 
622  for (i = 0; i < 2; i++) {
623  if (fr->ofields[i]->lock[i^1])
624  continue;
625 
626  fr->buffer = fr->ofields[i];
627  pullup_lock_buffer(fr->buffer, 2);
628  copy_field(s, fr->buffer, fr->ofields[i^1], i^1);
629  return;
630  }
631 
632  fr->buffer = pullup_get_buffer(s, 2);
633 
634  copy_field(s, fr->buffer, fr->ofields[0], 0);
635  copy_field(s, fr->buffer, fr->ofields[1], 1);
636 }
637 
638 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
639 {
640  AVFilterContext *ctx = inlink->dst;
641  AVFilterLink *outlink = ctx->outputs[0];
642  PullupContext *s = ctx->priv;
643  PullupBuffer *b;
644  PullupFrame *f;
645  AVFrame *out;
646  int p, ret = 0;
647 
648  b = pullup_get_buffer(s, 2);
649  if (!b) {
650  av_log(ctx, AV_LOG_WARNING, "Could not get buffer!\n");
651  f = pullup_get_frame(s);
653  goto end;
654  }
655 
657  (const uint8_t**)in->data, in->linesize,
658  inlink->format, inlink->w, inlink->h);
659 
660  p = in->interlaced_frame ? !in->top_field_first : 0;
661  pullup_submit_field(s, b, p );
662  pullup_submit_field(s, b, p^1);
663 
664  if (in->repeat_pict)
665  pullup_submit_field(s, b, p);
666 
667  pullup_release_buffer(b, 2);
668 
669  f = pullup_get_frame(s);
670  if (!f)
671  goto end;
672 
673  if (f->length < 2) {
675  f = pullup_get_frame(s);
676  if (!f)
677  goto end;
678  if (f->length < 2) {
680  if (!in->repeat_pict)
681  goto end;
682  f = pullup_get_frame(s);
683  if (!f)
684  goto end;
685  if (f->length < 2) {
687  goto end;
688  }
689  }
690  }
691 
692  /* If the frame isn't already exportable... */
693  if (!f->buffer)
694  pullup_pack_frame(s, f);
695 
696  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
697  if (!out) {
698  ret = AVERROR(ENOMEM);
699  goto end;
700  }
701  av_frame_copy_props(out, in);
702 
703  av_image_copy(out->data, out->linesize,
704  (const uint8_t**)f->buffer->planes, s->planewidth,
705  inlink->format, inlink->w, inlink->h);
706 
707  ret = ff_filter_frame(outlink, out);
709 end:
710  av_frame_free(&in);
711  return ret;
712 }
713 
714 static av_cold void uninit(AVFilterContext *ctx)
715 {
716  PullupContext *s = ctx->priv;
717  PullupField *f;
718  int i;
719 
720  f = s->head;
721  while (f) {
722  av_free(f->diffs);
723  av_free(f->combs);
724  av_free(f->vars);
725  if (f == s->last) {
726  av_freep(&s->last);
727  break;
728  }
729  f = f->next;
730  av_freep(&f->prev);
731  };
732 
733  for (i = 0; i < FF_ARRAY_ELEMS(s->buffers); i++) {
734  av_freep(&s->buffers[i].planes[0]);
735  av_freep(&s->buffers[i].planes[1]);
736  av_freep(&s->buffers[i].planes[2]);
737  }
738 }
739 
740 static const AVFilterPad pullup_inputs[] = {
741  {
742  .name = "default",
743  .type = AVMEDIA_TYPE_VIDEO,
744  .filter_frame = filter_frame,
745  .config_props = config_input,
746  },
747  { NULL }
748 };
749 
750 static const AVFilterPad pullup_outputs[] = {
751  {
752  .name = "default",
753  .type = AVMEDIA_TYPE_VIDEO,
754  .config_props = config_output,
755  },
756  { NULL }
757 };
758 
760  .name = "pullup",
761  .description = NULL_IF_CONFIG_SMALL("Pullup from field sequence to frames."),
762  .priv_size = sizeof(PullupContext),
763  .priv_class = &pullup_class,
764  .uninit = uninit,
766  .inputs = pullup_inputs,
767  .outputs = pullup_outputs,
768 };