2 * Copyright (c) 2003 Rich Felker
4 * This file is part of FFmpeg.
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.
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.
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
21 #include "libavutil/avassert.h"
22 #include "libavutil/imgutils.h"
23 #include "libavutil/opt.h"
24 #include "libavutil/pixdesc.h"
29 #include "vf_pullup.h"
31 #define F_HAVE_BREAKS 1
32 #define F_HAVE_AFFINITY 2
37 #define OFFSET(x) offsetof(PullupContext, x)
38 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
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" },
53 AVFILTER_DEFINE_CLASS(pullup
);
55 static int query_formats(AVFilterContext
*ctx
)
57 static const enum AVPixelFormat pix_fmts
[] = {
58 AV_PIX_FMT_YUVJ444P
, AV_PIX_FMT_YUVJ440P
,
59 AV_PIX_FMT_YUVJ422P
, AV_PIX_FMT_YUVJ420P
,
60 AV_PIX_FMT_YUV444P
, AV_PIX_FMT_YUV440P
,
61 AV_PIX_FMT_YUV422P
, AV_PIX_FMT_YUV420P
,
62 AV_PIX_FMT_YUV411P
, AV_PIX_FMT_YUV410P
,
63 AV_PIX_FMT_YUVJ411P
, AV_PIX_FMT_GRAY8
,
66 ff_set_common_formats(ctx
, ff_make_format_list(pix_fmts
));
70 #define ABS(a) (((a) ^ ((a) >> 31)) - ((a) >> 31))
72 static int diff_c(const uint8_t *a
, const uint8_t *b
, ptrdiff_t s
)
76 for (i
= 0; i
< 4; i
++) {
77 for (j
= 0; j
< 8; j
++)
78 diff
+= ABS(a
[j
] - b
[j
]);
86 static int comb_c(const uint8_t *a
, const uint8_t *b
, ptrdiff_t s
)
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
]);
101 static int var_c(const uint8_t *a
, const uint8_t *b
, ptrdiff_t s
)
105 for (i
= 0; i
< 3; i
++) {
106 for (j
= 0; j
< 8; j
++)
107 var
+= ABS(a
[j
] - a
[j
+ s
]);
111 return 4 * var
; /* match comb scaling */
114 static int alloc_metrics(PullupContext
*s
, PullupField
*f
)
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
));
120 if (!f
->diffs
|| !f
->combs
|| !f
->vars
) {
124 return AVERROR(ENOMEM
);
129 static void free_field_queue(PullupField
*head
)
131 PullupField
*f
= head
;
140 memset(f
, 0, sizeof(*f
)); // clear all pointers to avoid stale ones
146 static PullupField
*make_field_queue(PullupContext
*s
, int len
)
148 PullupField
*head
, *f
;
150 f
= head
= av_mallocz(sizeof(*head
));
154 if (alloc_metrics(s
, f
) < 0) {
159 for (; len
> 0; len
--) {
160 f
->next
= av_mallocz(sizeof(*f
->next
));
162 free_field_queue(head
);
168 if (alloc_metrics(s
, f
) < 0) {
169 free_field_queue(head
);
180 static int config_input(AVFilterLink
*inlink
)
182 AVFilterContext
*ctx
= inlink
->dst
;
183 PullupContext
*s
= ctx
->priv
;
184 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(inlink
->format
);
185 int mp
= s
->metric_plane
;
187 s
->nb_planes
= av_pix_fmt_count_planes(inlink
->format
);
189 if (mp
+ 1 > s
->nb_planes
) {
190 av_log(ctx
, AV_LOG_ERROR
, "input format does not have such plane\n");
191 return AVERROR(EINVAL
);
194 s
->planeheight
[1] = s
->planeheight
[2] = FF_CEIL_RSHIFT(inlink
->h
, desc
->log2_chroma_h
);
195 s
->planeheight
[0] = s
->planeheight
[3] = inlink
->h
;
196 s
->planewidth
[1] = s
->planewidth
[2] = FF_CEIL_RSHIFT(inlink
->w
, desc
->log2_chroma_w
);
197 s
->planewidth
[0] = s
->planewidth
[3] = inlink
->w
;
199 s
->metric_w
= (s
->planewidth
[mp
] - ((s
->junk_left
+ s
->junk_right
) << 3)) >> 3;
200 s
->metric_h
= (s
->planeheight
[mp
] - ((s
->junk_top
+ s
->junk_bottom
) << 1)) >> 3;
201 s
->metric_offset
= (s
->junk_left
<< 3) + (s
->junk_top
<< 1) * s
->planewidth
[mp
];
202 s
->metric_length
= s
->metric_w
* s
->metric_h
;
204 av_log(ctx
, AV_LOG_DEBUG
, "w: %d h: %d\n", s
->metric_w
, s
->metric_h
);
205 av_log(ctx
, AV_LOG_DEBUG
, "offset: %d length: %d\n", s
->metric_offset
, s
->metric_length
);
207 s
->head
= make_field_queue(s
, 8);
209 return AVERROR(ENOMEM
);
216 ff_pullup_init_x86(s
);
220 static int config_output(AVFilterLink
*outlink
)
222 outlink
->flags
|= FF_LINK_FLAG_REQUEST_LOOP
;
226 static PullupBuffer
*pullup_lock_buffer(PullupBuffer
*b
, int parity
)
231 if ((parity
+ 1) & 1)
233 if ((parity
+ 1) & 2)
239 static void pullup_release_buffer(PullupBuffer
*b
, int parity
)
244 if ((parity
+ 1) & 1)
246 if ((parity
+ 1) & 2)
250 static int alloc_buffer(PullupContext
*s
, PullupBuffer
*b
)
256 for (i
= 0; i
< s
->nb_planes
; i
++) {
257 b
->planes
[i
] = av_malloc(s
->planeheight
[i
] * s
->planewidth
[i
]);
259 if (s
->nb_planes
== 1)
260 b
->planes
[1] = av_malloc(4*256);
265 static PullupBuffer
*pullup_get_buffer(PullupContext
*s
, int parity
)
269 /* Try first to get the sister buffer for the previous field */
270 if (parity
< 2 && s
->last
&& parity
!= s
->last
->parity
271 && !s
->last
->buffer
->lock
[parity
]) {
272 alloc_buffer(s
, s
->last
->buffer
);
273 return pullup_lock_buffer(s
->last
->buffer
, parity
);
276 /* Prefer a buffer with both fields open */
277 for (i
= 0; i
< FF_ARRAY_ELEMS(s
->buffers
); i
++) {
278 if (s
->buffers
[i
].lock
[0])
280 if (s
->buffers
[i
].lock
[1])
282 alloc_buffer(s
, &s
->buffers
[i
]);
283 return pullup_lock_buffer(&s
->buffers
[i
], parity
);
289 /* Search for any half-free buffer */
290 for (i
= 0; i
< FF_ARRAY_ELEMS(s
->buffers
); i
++) {
291 if (((parity
+ 1) & 1) && s
->buffers
[i
].lock
[0])
293 if (((parity
+ 1) & 2) && s
->buffers
[i
].lock
[1])
295 alloc_buffer(s
, &s
->buffers
[i
]);
296 return pullup_lock_buffer(&s
->buffers
[i
], parity
);
302 static int queue_length(PullupField
*begin
, PullupField
*end
)
310 for (f
= begin
; f
!= end
; f
= f
->next
)
316 static int find_first_break(PullupField
*f
, int max
)
320 for (i
= 0; i
< max
; i
++) {
321 if (f
->breaks
& BREAK_RIGHT
|| f
->next
->breaks
& BREAK_LEFT
)
329 static void compute_breaks(PullupContext
*s
, PullupField
*f0
)
331 PullupField
*f1
= f0
->next
;
332 PullupField
*f2
= f1
->next
;
333 PullupField
*f3
= f2
->next
;
334 int i
, l
, max_l
= 0, max_r
= 0;
336 if (f0
->flags
& F_HAVE_BREAKS
)
339 f0
->flags
|= F_HAVE_BREAKS
;
341 /* Special case when fields are 100% identical */
342 if (f0
->buffer
== f2
->buffer
&& f1
->buffer
!= f3
->buffer
) {
343 f2
->breaks
|= BREAK_RIGHT
;
347 if (f0
->buffer
!= f2
->buffer
&& f1
->buffer
== f3
->buffer
) {
348 f1
->breaks
|= BREAK_LEFT
;
352 for (i
= 0; i
< s
->metric_length
; i
++) {
353 l
= f2
->diffs
[i
] - f3
->diffs
[i
];
361 /* Don't get tripped up when differences are mostly quant error */
362 if (max_l
+ max_r
< 128)
364 if (max_l
> 4 * max_r
)
365 f1
->breaks
|= BREAK_LEFT
;
366 if (max_r
> 4 * max_l
)
367 f2
->breaks
|= BREAK_RIGHT
;
370 static void compute_affinity(PullupContext
*s
, PullupField
*f
)
372 int i
, max_l
= 0, max_r
= 0, l
;
374 if (f
->flags
& F_HAVE_AFFINITY
)
377 f
->flags
|= F_HAVE_AFFINITY
;
379 if (f
->buffer
== f
->next
->next
->buffer
) {
381 f
->next
->affinity
= 0;
382 f
->next
->next
->affinity
= -1;
383 f
->next
->flags
|= F_HAVE_AFFINITY
;
384 f
->next
->next
->flags
|= F_HAVE_AFFINITY
;
388 for (i
= 0; i
< s
->metric_length
; i
++) {
390 int lv
= f
->prev
->vars
[i
];
391 int rv
= f
->next
->vars
[i
];
392 int lc
= f
-> combs
[i
] - 2*(v
< lv
? v
: lv
);
393 int rc
= f
->next
->combs
[i
] - 2*(v
< rv
? v
: rv
);
405 if (max_l
+ max_r
< 64)
408 if (max_r
> 6 * max_l
)
410 else if (max_l
> 6 * max_r
)
414 static int decide_frame_length(PullupContext
*s
)
416 PullupField
*f0
= s
->first
;
417 PullupField
*f1
= f0
->next
;
418 PullupField
*f2
= f1
->next
;
422 if (queue_length(s
->first
, s
->last
) < 4)
426 n
= queue_length(f
, s
->last
);
427 for (i
= 0; i
< n
- 1; i
++) {
429 compute_breaks(s
, f
);
431 compute_affinity(s
, f
);
436 if (f0
->affinity
== -1)
439 l
= find_first_break(f0
, 3);
441 if (l
== 1 && s
->strict_breaks
< 0)
446 return 1 + (s
->strict_breaks
< 1 && f0
->affinity
== 1 && f1
->affinity
== -1);
448 /* FIXME: strictly speaking, f0->prev is no longer valid... :) */
450 && (f0
->prev
->breaks
& BREAK_RIGHT
) && (f2
->breaks
& BREAK_LEFT
)
451 && (f0
->affinity
!= 1 || f1
->affinity
!= -1) )
453 return 1 + (f1
->affinity
!= 1);
455 return 2 + (f2
->affinity
!= 1);
457 /* 9 possibilities covered before switch */
458 if (f1
->affinity
== 1)
459 return 1; /* covers 6 */
460 else if (f1
->affinity
== -1)
461 return 2; /* covers 6 */
462 else if (f2
->affinity
== -1) { /* covers 2 */
463 return (f0
->affinity
== 1) ? 3 : 1;
465 return 2; /* the remaining 6 */
470 static PullupFrame
*pullup_get_frame(PullupContext
*s
)
472 PullupFrame
*fr
= &s
->frame
;
473 int i
, n
= decide_frame_length(s
);
474 int aff
= s
->first
->next
->affinity
;
476 av_assert1(n
< FF_ARRAY_ELEMS(fr
->ifields
));
482 fr
->parity
= s
->first
->parity
;
485 for (i
= 0; i
< n
; i
++) {
486 /* We cheat and steal the buffer without release+relock */
487 fr
->ifields
[i
] = s
->first
->buffer
;
488 s
->first
->buffer
= 0;
489 s
->first
= s
->first
->next
;
493 fr
->ofields
[fr
->parity
] = fr
->ifields
[0];
494 fr
->ofields
[fr
->parity
^ 1] = 0;
496 fr
->ofields
[fr
->parity
] = fr
->ifields
[0];
497 fr
->ofields
[fr
->parity
^ 1] = fr
->ifields
[1];
500 aff
= (fr
->ifields
[0] == fr
->ifields
[1]) ? -1 : 1;
501 fr
->ofields
[fr
->parity
] = fr
->ifields
[1 + aff
];
502 fr
->ofields
[fr
->parity
^ 1] = fr
->ifields
[1 ];
505 pullup_lock_buffer(fr
->ofields
[0], 0);
506 pullup_lock_buffer(fr
->ofields
[1], 1);
508 if (fr
->ofields
[0] == fr
->ofields
[1]) {
509 fr
->buffer
= fr
->ofields
[0];
510 pullup_lock_buffer(fr
->buffer
, 2);
517 static void pullup_release_frame(PullupFrame
*f
)
521 for (i
= 0; i
< f
->length
; i
++)
522 pullup_release_buffer(f
->ifields
[i
], f
->parity
^ (i
& 1));
524 pullup_release_buffer(f
->ofields
[0], 0);
525 pullup_release_buffer(f
->ofields
[1], 1);
528 pullup_release_buffer(f
->buffer
, 2);
532 static void compute_metric(PullupContext
*s
, int *dest
,
533 PullupField
*fa
, int pa
, PullupField
*fb
, int pb
,
534 int (*func
)(const uint8_t *, const uint8_t *, ptrdiff_t))
536 int mp
= s
->metric_plane
;
538 int ystep
= s
->planewidth
[mp
] << 3;
539 int stride
= s
->planewidth
[mp
] << 1; /* field stride */
540 int w
= s
->metric_w
* xstep
;
544 if (!fa
->buffer
|| !fb
->buffer
)
547 /* Shortcut for duplicate fields (e.g. from RFF flag) */
548 if (fa
->buffer
== fb
->buffer
&& pa
== pb
) {
549 memset(dest
, 0, s
->metric_length
* sizeof(*dest
));
553 a
= fa
->buffer
->planes
[mp
] + pa
* s
->planewidth
[mp
] + s
->metric_offset
;
554 b
= fb
->buffer
->planes
[mp
] + pb
* s
->planewidth
[mp
] + s
->metric_offset
;
556 for (y
= 0; y
< s
->metric_h
; y
++) {
557 for (x
= 0; x
< w
; x
+= xstep
)
558 *dest
++ = func(a
+ x
, b
+ x
, stride
);
559 a
+= ystep
; b
+= ystep
;
563 static int check_field_queue(PullupContext
*s
)
567 if (s
->head
->next
== s
->first
) {
568 PullupField
*f
= av_mallocz(sizeof(*f
));
571 return AVERROR(ENOMEM
);
573 if ((ret
= alloc_metrics(s
, f
)) < 0) {
587 static void pullup_submit_field(PullupContext
*s
, PullupBuffer
*b
, int parity
)
591 /* Grow the circular list if needed */
592 if (check_field_queue(s
) < 0)
595 /* Cannot have two fields of same parity in a row; drop the new one */
596 if (s
->last
&& s
->last
->parity
== parity
)
601 f
->buffer
= pullup_lock_buffer(b
, parity
);
606 compute_metric(s
, f
->diffs
, f
, parity
, f
->prev
->prev
, parity
, s
->diff
);
607 compute_metric(s
, f
->combs
, parity
? f
->prev
: f
, 0, parity
? f
: f
->prev
, 1, s
->comb
);
608 compute_metric(s
, f
->vars
, f
, parity
, f
, -1, s
->var
);
611 /* Advance the circular list */
616 s
->head
= s
->head
->next
;
619 static void copy_field(PullupContext
*s
,
620 PullupBuffer
*dst
, PullupBuffer
*src
, int parity
)
625 for (i
= 0; i
< s
->nb_planes
; i
++) {
626 ss
= src
->planes
[i
] + parity
* s
->planewidth
[i
];
627 dd
= dst
->planes
[i
] + parity
* s
->planewidth
[i
];
629 av_image_copy_plane(dd
, s
->planewidth
[i
] << 1,
630 ss
, s
->planewidth
[i
] << 1,
631 s
->planewidth
[i
], s
->planeheight
[i
] >> 1);
635 static void pullup_pack_frame(PullupContext
*s
, PullupFrame
*fr
)
643 return; /* FIXME: deal with this */
645 for (i
= 0; i
< 2; i
++) {
646 if (fr
->ofields
[i
]->lock
[i
^1])
649 fr
->buffer
= fr
->ofields
[i
];
650 pullup_lock_buffer(fr
->buffer
, 2);
651 copy_field(s
, fr
->buffer
, fr
->ofields
[i
^1], i
^1);
655 fr
->buffer
= pullup_get_buffer(s
, 2);
657 copy_field(s
, fr
->buffer
, fr
->ofields
[0], 0);
658 copy_field(s
, fr
->buffer
, fr
->ofields
[1], 1);
661 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*in
)
663 AVFilterContext
*ctx
= inlink
->dst
;
664 AVFilterLink
*outlink
= ctx
->outputs
[0];
665 PullupContext
*s
= ctx
->priv
;
671 b
= pullup_get_buffer(s
, 2);
673 av_log(ctx
, AV_LOG_WARNING
, "Could not get buffer!\n");
674 f
= pullup_get_frame(s
);
675 pullup_release_frame(f
);
679 av_image_copy(b
->planes
, s
->planewidth
,
680 (const uint8_t**)in
->data
, in
->linesize
,
681 inlink
->format
, inlink
->w
, inlink
->h
);
683 p
= in
->interlaced_frame
? !in
->top_field_first
: 0;
684 pullup_submit_field(s
, b
, p
);
685 pullup_submit_field(s
, b
, p
^1);
688 pullup_submit_field(s
, b
, p
);
690 pullup_release_buffer(b
, 2);
692 f
= pullup_get_frame(s
);
697 pullup_release_frame(f
);
698 f
= pullup_get_frame(s
);
702 pullup_release_frame(f
);
703 if (!in
->repeat_pict
)
705 f
= pullup_get_frame(s
);
709 pullup_release_frame(f
);
715 /* If the frame isn't already exportable... */
717 pullup_pack_frame(s
, f
);
719 out
= ff_get_video_buffer(outlink
, outlink
->w
, outlink
->h
);
721 ret
= AVERROR(ENOMEM
);
724 av_frame_copy_props(out
, in
);
726 av_image_copy(out
->data
, out
->linesize
,
727 (const uint8_t**)f
->buffer
->planes
, s
->planewidth
,
728 inlink
->format
, inlink
->w
, inlink
->h
);
730 ret
= ff_filter_frame(outlink
, out
);
731 pullup_release_frame(f
);
737 static av_cold
void uninit(AVFilterContext
*ctx
)
739 PullupContext
*s
= ctx
->priv
;
742 free_field_queue(s
->head
);
745 for (i
= 0; i
< FF_ARRAY_ELEMS(s
->buffers
); i
++) {
746 av_freep(&s
->buffers
[i
].planes
[0]);
747 av_freep(&s
->buffers
[i
].planes
[1]);
748 av_freep(&s
->buffers
[i
].planes
[2]);
752 static const AVFilterPad pullup_inputs
[] = {
755 .type
= AVMEDIA_TYPE_VIDEO
,
756 .filter_frame
= filter_frame
,
757 .config_props
= config_input
,
762 static const AVFilterPad pullup_outputs
[] = {
765 .type
= AVMEDIA_TYPE_VIDEO
,
766 .config_props
= config_output
,
771 AVFilter ff_vf_pullup
= {
773 .description
= NULL_IF_CONFIG_SMALL("Pullup from field sequence to frames."),
774 .priv_size
= sizeof(PullupContext
),
775 .priv_class
= &pullup_class
,
777 .query_formats
= query_formats
,
778 .inputs
= pullup_inputs
,
779 .outputs
= pullup_outputs
,