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