]> git.sesse.net Git - ffmpeg/blob - libavfilter/vf_tinterlace.c
Merge commit '549d0bdca53af7a6e0c612ab4b03baecf3a5878f'
[ffmpeg] / libavfilter / vf_tinterlace.c
1 /*
2  * Copyright (c) 2011 Stefano Sabatini
3  * Copyright (c) 2010 Baptiste Coudurier
4  * Copyright (c) 2003 Michael Zucchi <notzed@ximian.com>
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with FFmpeg if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 /**
24  * @file
25  * temporal field interlace filter, ported from MPlayer/libmpcodecs
26  */
27
28 #include "libavutil/opt.h"
29 #include "libavutil/imgutils.h"
30 #include "libavutil/avassert.h"
31 #include "avfilter.h"
32 #include "internal.h"
33 #include "tinterlace.h"
34
35 #define OFFSET(x) offsetof(TInterlaceContext, x)
36 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
37 #define TINTERLACE_FLAG_VLPF 01
38 #define TINTERLACE_FLAG_EXACT_TB 2
39
40 static const AVOption tinterlace_options[] = {
41     {"mode",              "select interlace mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_MERGE}, 0, MODE_NB-1, FLAGS, "mode"},
42     {"merge",             "merge fields",                                 0, AV_OPT_TYPE_CONST, {.i64=MODE_MERGE},             INT_MIN, INT_MAX, FLAGS, "mode"},
43     {"drop_even",         "drop even fields",                             0, AV_OPT_TYPE_CONST, {.i64=MODE_DROP_EVEN},         INT_MIN, INT_MAX, FLAGS, "mode"},
44     {"drop_odd",          "drop odd fields",                              0, AV_OPT_TYPE_CONST, {.i64=MODE_DROP_ODD},          INT_MIN, INT_MAX, FLAGS, "mode"},
45     {"pad",               "pad alternate lines with black",               0, AV_OPT_TYPE_CONST, {.i64=MODE_PAD},               INT_MIN, INT_MAX, FLAGS, "mode"},
46     {"interleave_top",    "interleave top and bottom fields",             0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_TOP},    INT_MIN, INT_MAX, FLAGS, "mode"},
47     {"interleave_bottom", "interleave bottom and top fields",             0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_BOTTOM}, INT_MIN, INT_MAX, FLAGS, "mode"},
48     {"interlacex2",       "interlace fields from two consecutive frames", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLACEX2},       INT_MIN, INT_MAX, FLAGS, "mode"},
49     {"mergex2",           "merge fields keeping same frame rate",         0, AV_OPT_TYPE_CONST, {.i64=MODE_MERGEX2},           INT_MIN, INT_MAX, FLAGS, "mode"},
50
51     {"flags",             "set flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, 0, INT_MAX, 0, "flags" },
52     {"low_pass_filter",   "enable vertical low-pass filter",              0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags" },
53     {"vlpf",              "enable vertical low-pass filter",              0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags" },
54     {"exact_tb",          "force a timebase which can represent timestamps exactly", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_EXACT_TB}, INT_MIN, INT_MAX, FLAGS, "flags" },
55
56     {NULL}
57 };
58
59 AVFILTER_DEFINE_CLASS(tinterlace);
60
61 #define FULL_SCALE_YUVJ_FORMATS \
62     AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P
63
64 static const enum AVPixelFormat full_scale_yuvj_pix_fmts[] = {
65     FULL_SCALE_YUVJ_FORMATS, AV_PIX_FMT_NONE
66 };
67
68 static const AVRational standard_tbs[] = {
69     {1, 25},
70     {1, 30},
71     {1001, 30000},
72 };
73
74 static int query_formats(AVFilterContext *ctx)
75 {
76     static const enum AVPixelFormat pix_fmts[] = {
77         AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,
78         AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P,
79         AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P,
80         AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P,
81         AV_PIX_FMT_GRAY8, FULL_SCALE_YUVJ_FORMATS,
82         AV_PIX_FMT_NONE
83     };
84
85     AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
86     if (!fmts_list)
87         return AVERROR(ENOMEM);
88     return ff_set_common_formats(ctx, fmts_list);
89 }
90
91 static void lowpass_line_c(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp,
92                            ptrdiff_t mref, ptrdiff_t pref)
93 {
94     const uint8_t *srcp_above = srcp + mref;
95     const uint8_t *srcp_below = srcp + pref;
96     int i;
97     for (i = 0; i < width; i++) {
98         // this calculation is an integer representation of
99         // '0.5 * current + 0.25 * above + 0.25 * below'
100         // '1 +' is for rounding.
101         dstp[i] = (1 + srcp[i] + srcp[i] + srcp_above[i] + srcp_below[i]) >> 2;
102     }
103 }
104
105 static av_cold void uninit(AVFilterContext *ctx)
106 {
107     TInterlaceContext *tinterlace = ctx->priv;
108
109     av_frame_free(&tinterlace->cur );
110     av_frame_free(&tinterlace->next);
111     av_freep(&tinterlace->black_data[0]);
112 }
113
114 static int config_out_props(AVFilterLink *outlink)
115 {
116     AVFilterContext *ctx = outlink->src;
117     AVFilterLink *inlink = outlink->src->inputs[0];
118     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format);
119     TInterlaceContext *tinterlace = ctx->priv;
120     int i;
121
122     tinterlace->vsub = desc->log2_chroma_h;
123     outlink->w = inlink->w;
124     outlink->h = tinterlace->mode == MODE_MERGE || tinterlace->mode == MODE_PAD || tinterlace->mode == MODE_MERGEX2?
125         inlink->h*2 : inlink->h;
126     if (tinterlace->mode == MODE_MERGE || tinterlace->mode == MODE_PAD || tinterlace->mode == MODE_MERGEX2)
127         outlink->sample_aspect_ratio = av_mul_q(inlink->sample_aspect_ratio,
128                                                 av_make_q(2, 1));
129
130     if (tinterlace->mode == MODE_PAD) {
131         uint8_t black[4] = { 16, 128, 128, 16 };
132         int i, ret;
133         if (ff_fmt_is_in(outlink->format, full_scale_yuvj_pix_fmts))
134             black[0] = black[3] = 0;
135         ret = av_image_alloc(tinterlace->black_data, tinterlace->black_linesize,
136                              outlink->w, outlink->h, outlink->format, 16);
137         if (ret < 0)
138             return ret;
139
140         /* fill black picture with black */
141         for (i = 0; i < 4 && tinterlace->black_data[i]; i++) {
142             int h = i == 1 || i == 2 ? AV_CEIL_RSHIFT(outlink->h, desc->log2_chroma_h) : outlink->h;
143             memset(tinterlace->black_data[i], black[i],
144                    tinterlace->black_linesize[i] * h);
145         }
146     }
147     if ((tinterlace->flags & TINTERLACE_FLAG_VLPF)
148             && !(tinterlace->mode == MODE_INTERLEAVE_TOP
149               || tinterlace->mode == MODE_INTERLEAVE_BOTTOM)) {
150         av_log(ctx, AV_LOG_WARNING, "low_pass_filter flag ignored with mode %d\n",
151                 tinterlace->mode);
152         tinterlace->flags &= ~TINTERLACE_FLAG_VLPF;
153     }
154     tinterlace->preout_time_base = inlink->time_base;
155     if (tinterlace->mode == MODE_INTERLACEX2) {
156         tinterlace->preout_time_base.den *= 2;
157         outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){2,1});
158         outlink->time_base  = av_mul_q(inlink->time_base , (AVRational){1,2});
159     } else if (tinterlace->mode == MODE_MERGEX2) {
160         outlink->frame_rate = inlink->frame_rate;
161         outlink->time_base  = inlink->time_base;
162     } else if (tinterlace->mode != MODE_PAD) {
163         outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){1,2});
164         outlink->time_base  = av_mul_q(inlink->time_base , (AVRational){2,1});
165     }
166
167     for (i = 0; i<FF_ARRAY_ELEMS(standard_tbs); i++){
168         if (!av_cmp_q(standard_tbs[i], outlink->time_base))
169             break;
170     }
171     if (i == FF_ARRAY_ELEMS(standard_tbs) ||
172         (tinterlace->flags & TINTERLACE_FLAG_EXACT_TB))
173         outlink->time_base = tinterlace->preout_time_base;
174
175     if (tinterlace->flags & TINTERLACE_FLAG_VLPF) {
176         tinterlace->lowpass_line = lowpass_line_c;
177         if (ARCH_X86)
178             ff_tinterlace_init_x86(tinterlace);
179     }
180
181     av_log(ctx, AV_LOG_VERBOSE, "mode:%d filter:%s h:%d -> h:%d\n",
182            tinterlace->mode, (tinterlace->flags & TINTERLACE_FLAG_VLPF) ? "on" : "off",
183            inlink->h, outlink->h);
184
185     return 0;
186 }
187
188 #define FIELD_UPPER           0
189 #define FIELD_LOWER           1
190 #define FIELD_UPPER_AND_LOWER 2
191
192 /**
193  * Copy picture field from src to dst.
194  *
195  * @param src_field copy from upper, lower field or both
196  * @param interleave leave a padding line between each copied line
197  * @param dst_field copy to upper or lower field,
198  *        only meaningful when interleave is selected
199  * @param flags context flags
200  */
201 static inline
202 void copy_picture_field(TInterlaceContext *tinterlace,
203                         uint8_t *dst[4], int dst_linesize[4],
204                         const uint8_t *src[4], int src_linesize[4],
205                         enum AVPixelFormat format, int w, int src_h,
206                         int src_field, int interleave, int dst_field,
207                         int flags)
208 {
209     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
210     int hsub = desc->log2_chroma_w;
211     int plane, vsub = desc->log2_chroma_h;
212     int k = src_field == FIELD_UPPER_AND_LOWER ? 1 : 2;
213     int h;
214
215     for (plane = 0; plane < desc->nb_components; plane++) {
216         int lines = plane == 1 || plane == 2 ? AV_CEIL_RSHIFT(src_h, vsub) : src_h;
217         int cols  = plane == 1 || plane == 2 ? AV_CEIL_RSHIFT(    w, hsub) : w;
218         uint8_t *dstp = dst[plane];
219         const uint8_t *srcp = src[plane];
220
221         lines = (lines + (src_field == FIELD_UPPER)) / k;
222         if (src_field == FIELD_LOWER)
223             srcp += src_linesize[plane];
224         if (interleave && dst_field == FIELD_LOWER)
225             dstp += dst_linesize[plane];
226         if (flags & TINTERLACE_FLAG_VLPF) {
227             // Low-pass filtering is required when creating an interlaced destination from
228             // a progressive source which contains high-frequency vertical detail.
229             // Filtering will reduce interlace 'twitter' and Moire patterning.
230             int srcp_linesize = src_linesize[plane] * k;
231             int dstp_linesize = dst_linesize[plane] * (interleave ? 2 : 1);
232             for (h = lines; h > 0; h--) {
233                 ptrdiff_t pref = src_linesize[plane];
234                 ptrdiff_t mref = -pref;
235                 if (h == lines)  mref = 0; // there is no line above
236                 else if (h == 1) pref = 0; // there is no line below
237
238                 tinterlace->lowpass_line(dstp, cols, srcp, mref, pref);
239                 dstp += dstp_linesize;
240                 srcp += srcp_linesize;
241             }
242         } else {
243             av_image_copy_plane(dstp, dst_linesize[plane] * (interleave ? 2 : 1),
244                                 srcp, src_linesize[plane]*k, cols, lines);
245         }
246     }
247 }
248
249 static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
250 {
251     AVFilterContext *ctx = inlink->dst;
252     AVFilterLink *outlink = ctx->outputs[0];
253     TInterlaceContext *tinterlace = ctx->priv;
254     AVFrame *cur, *next, *out;
255     int field, tff, ret;
256
257     av_frame_free(&tinterlace->cur);
258     tinterlace->cur  = tinterlace->next;
259     tinterlace->next = picref;
260
261     cur = tinterlace->cur;
262     next = tinterlace->next;
263     /* we need at least two frames */
264     if (!tinterlace->cur)
265         return 0;
266
267     switch (tinterlace->mode) {
268     case MODE_MERGEX2: /* move the odd frame into the upper field of the new image, even into
269                         * the lower field, generating a double-height video at same framerate */
270     case MODE_MERGE: /* move the odd frame into the upper field of the new image, even into
271              * the lower field, generating a double-height video at half framerate */
272         out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
273         if (!out)
274             return AVERROR(ENOMEM);
275         av_frame_copy_props(out, cur);
276         out->height = outlink->h;
277         out->interlaced_frame = 1;
278         out->top_field_first = 1;
279         out->sample_aspect_ratio = av_mul_q(cur->sample_aspect_ratio, av_make_q(2, 1));
280
281         /* write odd frame lines into the upper field of the new frame */
282         copy_picture_field(tinterlace, out->data, out->linesize,
283                            (const uint8_t **)cur->data, cur->linesize,
284                            inlink->format, inlink->w, inlink->h,
285                            FIELD_UPPER_AND_LOWER, 1, tinterlace->mode == MODE_MERGEX2 ? inlink->frame_count_out & 1 ? FIELD_LOWER : FIELD_UPPER : FIELD_UPPER, tinterlace->flags);
286         /* write even frame lines into the lower field of the new frame */
287         copy_picture_field(tinterlace, out->data, out->linesize,
288                            (const uint8_t **)next->data, next->linesize,
289                            inlink->format, inlink->w, inlink->h,
290                            FIELD_UPPER_AND_LOWER, 1, tinterlace->mode == MODE_MERGEX2 ? inlink->frame_count_out & 1 ? FIELD_UPPER : FIELD_LOWER : FIELD_LOWER, tinterlace->flags);
291         if (tinterlace->mode != MODE_MERGEX2)
292             av_frame_free(&tinterlace->next);
293         break;
294
295     case MODE_DROP_ODD:  /* only output even frames, odd  frames are dropped; height unchanged, half framerate */
296     case MODE_DROP_EVEN: /* only output odd  frames, even frames are dropped; height unchanged, half framerate */
297         out = av_frame_clone(tinterlace->mode == MODE_DROP_EVEN ? cur : next);
298         if (!out)
299             return AVERROR(ENOMEM);
300         av_frame_free(&tinterlace->next);
301         break;
302
303     case MODE_PAD: /* expand each frame to double height, but pad alternate
304                     * lines with black; framerate unchanged */
305         out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
306         if (!out)
307             return AVERROR(ENOMEM);
308         av_frame_copy_props(out, cur);
309         out->height = outlink->h;
310         out->sample_aspect_ratio = av_mul_q(cur->sample_aspect_ratio, av_make_q(2, 1));
311
312         field = (1 + tinterlace->frame) & 1 ? FIELD_UPPER : FIELD_LOWER;
313         /* copy upper and lower fields */
314         copy_picture_field(tinterlace, out->data, out->linesize,
315                            (const uint8_t **)cur->data, cur->linesize,
316                            inlink->format, inlink->w, inlink->h,
317                            FIELD_UPPER_AND_LOWER, 1, field, tinterlace->flags);
318         /* pad with black the other field */
319         copy_picture_field(tinterlace, out->data, out->linesize,
320                            (const uint8_t **)tinterlace->black_data, tinterlace->black_linesize,
321                            inlink->format, inlink->w, inlink->h,
322                            FIELD_UPPER_AND_LOWER, 1, !field, tinterlace->flags);
323         break;
324
325         /* interleave upper/lower lines from odd frames with lower/upper lines from even frames,
326          * halving the frame rate and preserving image height */
327     case MODE_INTERLEAVE_TOP:    /* top    field first */
328     case MODE_INTERLEAVE_BOTTOM: /* bottom field first */
329         tff = tinterlace->mode == MODE_INTERLEAVE_TOP;
330         out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
331         if (!out)
332             return AVERROR(ENOMEM);
333         av_frame_copy_props(out, cur);
334         out->interlaced_frame = 1;
335         out->top_field_first = tff;
336
337         /* copy upper/lower field from cur */
338         copy_picture_field(tinterlace, out->data, out->linesize,
339                            (const uint8_t **)cur->data, cur->linesize,
340                            inlink->format, inlink->w, inlink->h,
341                            tff ? FIELD_UPPER : FIELD_LOWER, 1, tff ? FIELD_UPPER : FIELD_LOWER,
342                            tinterlace->flags);
343         /* copy lower/upper field from next */
344         copy_picture_field(tinterlace, out->data, out->linesize,
345                            (const uint8_t **)next->data, next->linesize,
346                            inlink->format, inlink->w, inlink->h,
347                            tff ? FIELD_LOWER : FIELD_UPPER, 1, tff ? FIELD_LOWER : FIELD_UPPER,
348                            tinterlace->flags);
349         av_frame_free(&tinterlace->next);
350         break;
351     case MODE_INTERLACEX2: /* re-interlace preserving image height, double frame rate */
352         /* output current frame first */
353         out = av_frame_clone(cur);
354         if (!out)
355             return AVERROR(ENOMEM);
356         out->interlaced_frame = 1;
357         if (cur->pts != AV_NOPTS_VALUE)
358             out->pts = cur->pts*2;
359
360         out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base);
361         if ((ret = ff_filter_frame(outlink, out)) < 0)
362             return ret;
363
364         /* output mix of current and next frame */
365         tff = next->top_field_first;
366         out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
367         if (!out)
368             return AVERROR(ENOMEM);
369         av_frame_copy_props(out, next);
370         out->interlaced_frame = 1;
371         out->top_field_first = !tff;
372
373         if (next->pts != AV_NOPTS_VALUE && cur->pts != AV_NOPTS_VALUE)
374             out->pts = cur->pts + next->pts;
375         else
376             out->pts = AV_NOPTS_VALUE;
377         /* write current frame second field lines into the second field of the new frame */
378         copy_picture_field(tinterlace, out->data, out->linesize,
379                            (const uint8_t **)cur->data, cur->linesize,
380                            inlink->format, inlink->w, inlink->h,
381                            tff ? FIELD_LOWER : FIELD_UPPER, 1, tff ? FIELD_LOWER : FIELD_UPPER,
382                            tinterlace->flags);
383         /* write next frame first field lines into the first field of the new frame */
384         copy_picture_field(tinterlace, out->data, out->linesize,
385                            (const uint8_t **)next->data, next->linesize,
386                            inlink->format, inlink->w, inlink->h,
387                            tff ? FIELD_UPPER : FIELD_LOWER, 1, tff ? FIELD_UPPER : FIELD_LOWER,
388                            tinterlace->flags);
389         break;
390     default:
391         av_assert0(0);
392     }
393
394     out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base);
395     ret = ff_filter_frame(outlink, out);
396     tinterlace->frame++;
397
398     return ret;
399 }
400
401 static const AVFilterPad tinterlace_inputs[] = {
402     {
403         .name         = "default",
404         .type         = AVMEDIA_TYPE_VIDEO,
405         .filter_frame = filter_frame,
406     },
407     { NULL }
408 };
409
410 static const AVFilterPad tinterlace_outputs[] = {
411     {
412         .name         = "default",
413         .type         = AVMEDIA_TYPE_VIDEO,
414         .config_props = config_out_props,
415     },
416     { NULL }
417 };
418
419 AVFilter ff_vf_tinterlace = {
420     .name          = "tinterlace",
421     .description   = NULL_IF_CONFIG_SMALL("Perform temporal field interlacing."),
422     .priv_size     = sizeof(TInterlaceContext),
423     .uninit        = uninit,
424     .query_formats = query_formats,
425     .inputs        = tinterlace_inputs,
426     .outputs       = tinterlace_outputs,
427     .priv_class    = &tinterlace_class,
428 };