| Line | Branch | Exec | Source |
|---|---|---|---|
| 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/mem.h" | ||
| 30 | #include "libavutil/opt.h" | ||
| 31 | #include "libavutil/imgutils.h" | ||
| 32 | #include "libavutil/avassert.h" | ||
| 33 | #include "avfilter.h" | ||
| 34 | #include "filters.h" | ||
| 35 | #include "tinterlace.h" | ||
| 36 | #include "video.h" | ||
| 37 | |||
| 38 | #define OFFSET(x) offsetof(TInterlaceContext, x) | ||
| 39 | #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM | ||
| 40 | |||
| 41 | static const AVOption tinterlace_options[] = { | ||
| 42 | {"mode", "select interlace mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_MERGE}, 0, MODE_NB-1, FLAGS, .unit = "mode"}, | ||
| 43 | {"merge", "merge fields", 0, AV_OPT_TYPE_CONST, {.i64=MODE_MERGE}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"}, | ||
| 44 | {"drop_even", "drop even fields", 0, AV_OPT_TYPE_CONST, {.i64=MODE_DROP_EVEN}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"}, | ||
| 45 | {"drop_odd", "drop odd fields", 0, AV_OPT_TYPE_CONST, {.i64=MODE_DROP_ODD}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"}, | ||
| 46 | {"pad", "pad alternate lines with black", 0, AV_OPT_TYPE_CONST, {.i64=MODE_PAD}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"}, | ||
| 47 | {"interleave_top", "interleave top and bottom fields", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_TOP}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"}, | ||
| 48 | {"interleave_bottom", "interleave bottom and top fields", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_BOTTOM}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"}, | ||
| 49 | {"interlacex2", "interlace fields from two consecutive frames", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLACEX2}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"}, | ||
| 50 | {"mergex2", "merge fields keeping same frame rate", 0, AV_OPT_TYPE_CONST, {.i64=MODE_MERGEX2}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"}, | ||
| 51 | |||
| 52 | {"flags", "set flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, 0, INT_MAX, 0, .unit = "flags" }, | ||
| 53 | {"low_pass_filter", "enable vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, .unit = "flags" }, | ||
| 54 | {"vlpf", "enable vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, .unit = "flags" }, | ||
| 55 | {"complex_filter", "enable complex vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, .unit = "flags" }, | ||
| 56 | {"cvlpf", "enable complex vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, .unit = "flags" }, | ||
| 57 | {"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, .unit = "flags" }, | ||
| 58 | {"bypass_il", "bypass already interlaced frames", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_BYPASS_IL}, INT_MIN, INT_MAX, FLAGS, .unit = "flags" }, | ||
| 59 | |||
| 60 | {NULL} | ||
| 61 | }; | ||
| 62 | |||
| 63 | AVFILTER_DEFINE_CLASS(tinterlace); | ||
| 64 | |||
| 65 | static const AVOption interlace_options[] = { | ||
| 66 | { "scan", "scanning mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64 = MODE_TFF}, 0, 1, FLAGS, .unit = "mode"}, | ||
| 67 | { "tff", "top field first", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_TFF}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"}, | ||
| 68 | { "bff", "bottom field first", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_BFF}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"}, | ||
| 69 | { "lowpass", "set vertical low-pass filter", OFFSET(lowpass), AV_OPT_TYPE_INT, {.i64 = VLPF_LIN}, 0, 2, FLAGS, .unit = "lowpass" }, | ||
| 70 | { "off", "disable vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = VLPF_OFF}, INT_MIN, INT_MAX, FLAGS, .unit = "lowpass" }, | ||
| 71 | { "linear", "linear vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = VLPF_LIN}, INT_MIN, INT_MAX, FLAGS, .unit = "lowpass" }, | ||
| 72 | { "complex", "complex vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = VLPF_CMP}, INT_MIN, INT_MAX, FLAGS, .unit = "lowpass" }, | ||
| 73 | |||
| 74 | { NULL } | ||
| 75 | }; | ||
| 76 | |||
| 77 | AVFILTER_DEFINE_CLASS(interlace); | ||
| 78 | |||
| 79 | #define FULL_SCALE_YUVJ_FORMATS \ | ||
| 80 | AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P | ||
| 81 | |||
| 82 | static const enum AVPixelFormat full_scale_yuvj_pix_fmts[] = { | ||
| 83 | FULL_SCALE_YUVJ_FORMATS, AV_PIX_FMT_NONE | ||
| 84 | }; | ||
| 85 | |||
| 86 | static const AVRational standard_tbs[] = { | ||
| 87 | {1, 25}, | ||
| 88 | {1, 30}, | ||
| 89 | {1001, 30000}, | ||
| 90 | }; | ||
| 91 | |||
| 92 | static const enum AVPixelFormat pix_fmts[] = { | ||
| 93 | AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, | ||
| 94 | AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, | ||
| 95 | AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, | ||
| 96 | AV_PIX_FMT_YUV420P10LE, AV_PIX_FMT_YUV422P10LE, | ||
| 97 | AV_PIX_FMT_YUV440P10LE, AV_PIX_FMT_YUV444P10LE, | ||
| 98 | AV_PIX_FMT_YUV420P12LE, AV_PIX_FMT_YUV422P12LE, | ||
| 99 | AV_PIX_FMT_YUV440P12LE, AV_PIX_FMT_YUV444P12LE, | ||
| 100 | AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P, | ||
| 101 | AV_PIX_FMT_YUVA420P10LE, AV_PIX_FMT_YUVA422P10LE, AV_PIX_FMT_YUVA444P10LE, | ||
| 102 | AV_PIX_FMT_GRAY8, FULL_SCALE_YUVJ_FORMATS, | ||
| 103 | AV_PIX_FMT_NONE | ||
| 104 | }; | ||
| 105 | |||
| 106 | 39312 | static void lowpass_line_c(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp, | |
| 107 | ptrdiff_t mref, ptrdiff_t pref, int clip_max) | ||
| 108 | { | ||
| 109 | 39312 | const uint8_t *srcp_above = srcp + mref; | |
| 110 | 39312 | const uint8_t *srcp_below = srcp + pref; | |
| 111 | int i; | ||
| 112 |
2/2✓ Branch 0 taken 10657152 times.
✓ Branch 1 taken 39312 times.
|
10696464 | for (i = 0; i < width; i++) { |
| 113 | // this calculation is an integer representation of | ||
| 114 | // '0.5 * current + 0.25 * above + 0.25 * below' | ||
| 115 | // '1 +' is for rounding. | ||
| 116 | 10657152 | dstp[i] = (1 + srcp[i] + srcp[i] + srcp_above[i] + srcp_below[i]) >> 2; | |
| 117 | } | ||
| 118 | 39312 | } | |
| 119 | |||
| 120 | 8928 | static void lowpass_line_c_16(uint8_t *dst8, ptrdiff_t width, const uint8_t *src8, | |
| 121 | ptrdiff_t mref, ptrdiff_t pref, int clip_max) | ||
| 122 | { | ||
| 123 | 8928 | uint16_t *dstp = (uint16_t *)dst8; | |
| 124 | 8928 | const uint16_t *srcp = (const uint16_t *)src8; | |
| 125 | 8928 | const uint16_t *srcp_above = srcp + mref / 2; | |
| 126 | 8928 | const uint16_t *srcp_below = srcp + pref / 2; | |
| 127 | int i, src_x; | ||
| 128 |
2/2✓ Branch 0 taken 2686464 times.
✓ Branch 1 taken 8928 times.
|
2695392 | for (i = 0; i < width; i++) { |
| 129 | // this calculation is an integer representation of | ||
| 130 | // '0.5 * current + 0.25 * above + 0.25 * below' | ||
| 131 | // '1 +' is for rounding. | ||
| 132 | 2686464 | src_x = av_le2ne16(srcp[i]) << 1; | |
| 133 | 2686464 | dstp[i] = av_le2ne16((1 + src_x + av_le2ne16(srcp_above[i]) | |
| 134 | + av_le2ne16(srcp_below[i])) >> 2); | ||
| 135 | } | ||
| 136 | 8928 | } | |
| 137 | |||
| 138 | 24912 | static void lowpass_line_complex_c(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp, | |
| 139 | ptrdiff_t mref, ptrdiff_t pref, int clip_max) | ||
| 140 | { | ||
| 141 | 24912 | const uint8_t *srcp_above = srcp + mref; | |
| 142 | 24912 | const uint8_t *srcp_below = srcp + pref; | |
| 143 | 24912 | const uint8_t *srcp_above2 = srcp + mref * 2; | |
| 144 | 24912 | const uint8_t *srcp_below2 = srcp + pref * 2; | |
| 145 | int i, src_x, src_ab; | ||
| 146 |
2/2✓ Branch 0 taken 6855552 times.
✓ Branch 1 taken 24912 times.
|
6880464 | for (i = 0; i < width; i++) { |
| 147 | // this calculation is an integer representation of | ||
| 148 | // '0.75 * current + 0.25 * above + 0.25 * below - 0.125 * above2 - 0.125 * below2' | ||
| 149 | // '4 +' is for rounding. | ||
| 150 | 6855552 | src_x = srcp[i] << 1; | |
| 151 | 6855552 | src_ab = srcp_above[i] + srcp_below[i]; | |
| 152 | 6855552 | dstp[i] = av_clip_uint8((4 + ((srcp[i] + src_x + src_ab) << 1) | |
| 153 | 6855552 | - srcp_above2[i] - srcp_below2[i]) >> 3); | |
| 154 | // Prevent over-sharpening: | ||
| 155 | // dst must not exceed src when the average of above and below | ||
| 156 | // is less than src. And the other way around. | ||
| 157 |
2/2✓ Branch 0 taken 2774613 times.
✓ Branch 1 taken 4080939 times.
|
6855552 | if (src_ab > src_x) { |
| 158 |
2/2✓ Branch 0 taken 384550 times.
✓ Branch 1 taken 2390063 times.
|
2774613 | if (dstp[i] < srcp[i]) |
| 159 | 384550 | dstp[i] = srcp[i]; | |
| 160 |
2/2✓ Branch 0 taken 487489 times.
✓ Branch 1 taken 3593450 times.
|
4080939 | } else if (dstp[i] > srcp[i]) |
| 161 | 487489 | dstp[i] = srcp[i]; | |
| 162 | } | ||
| 163 | 24912 | } | |
| 164 | |||
| 165 | 8928 | static void lowpass_line_complex_c_16(uint8_t *dst8, ptrdiff_t width, const uint8_t *src8, | |
| 166 | ptrdiff_t mref, ptrdiff_t pref, int clip_max) | ||
| 167 | { | ||
| 168 | 8928 | uint16_t *dstp = (uint16_t *)dst8; | |
| 169 | 8928 | const uint16_t *srcp = (const uint16_t *)src8; | |
| 170 | 8928 | const uint16_t *srcp_above = srcp + mref / 2; | |
| 171 | 8928 | const uint16_t *srcp_below = srcp + pref / 2; | |
| 172 | 8928 | const uint16_t *srcp_above2 = srcp + mref; | |
| 173 | 8928 | const uint16_t *srcp_below2 = srcp + pref; | |
| 174 | int i, dst_le, src_le, src_x, src_ab; | ||
| 175 |
2/2✓ Branch 0 taken 2686464 times.
✓ Branch 1 taken 8928 times.
|
2695392 | for (i = 0; i < width; i++) { |
| 176 | // this calculation is an integer representation of | ||
| 177 | // '0.75 * current + 0.25 * above + 0.25 * below - 0.125 * above2 - 0.125 * below2' | ||
| 178 | // '4 +' is for rounding. | ||
| 179 | 2686464 | src_le = av_le2ne16(srcp[i]); | |
| 180 | 2686464 | src_x = src_le << 1; | |
| 181 | 2686464 | src_ab = av_le2ne16(srcp_above[i]) + av_le2ne16(srcp_below[i]); | |
| 182 | 2686464 | dst_le = av_clip((4 + ((src_le + src_x + src_ab) << 1) | |
| 183 | 2686464 | - av_le2ne16(srcp_above2[i]) | |
| 184 | 2686464 | - av_le2ne16(srcp_below2[i])) >> 3, 0, clip_max); | |
| 185 | // Prevent over-sharpening: | ||
| 186 | // dst must not exceed src when the average of above and below | ||
| 187 | // is less than src. And the other way around. | ||
| 188 |
2/2✓ Branch 0 taken 1072111 times.
✓ Branch 1 taken 1614353 times.
|
2686464 | if (src_ab > src_x) { |
| 189 |
2/2✓ Branch 0 taken 270609 times.
✓ Branch 1 taken 801502 times.
|
1072111 | if (dst_le < src_le) |
| 190 | 270609 | dstp[i] = av_le2ne16(src_le); | |
| 191 | else | ||
| 192 | 801502 | dstp[i] = av_le2ne16(dst_le); | |
| 193 |
2/2✓ Branch 0 taken 306777 times.
✓ Branch 1 taken 1307576 times.
|
1614353 | } else if (dst_le > src_le) { |
| 194 | 306777 | dstp[i] = av_le2ne16(src_le); | |
| 195 | } else | ||
| 196 | 1307576 | dstp[i] = av_le2ne16(dst_le); | |
| 197 | } | ||
| 198 | 8928 | } | |
| 199 | |||
| 200 | 230 | static av_cold void uninit(AVFilterContext *ctx) | |
| 201 | { | ||
| 202 | 230 | TInterlaceContext *tinterlace = ctx->priv; | |
| 203 | |||
| 204 | 230 | av_frame_free(&tinterlace->cur ); | |
| 205 | 230 | av_frame_free(&tinterlace->next); | |
| 206 | 230 | av_freep(&tinterlace->black_data[0][0]); | |
| 207 | 230 | av_freep(&tinterlace->black_data[1][0]); | |
| 208 | 230 | ff_ccfifo_uninit(&tinterlace->cc_fifo); | |
| 209 | 230 | } | |
| 210 | |||
| 211 | 113 | static int config_out_props(AVFilterLink *outlink) | |
| 212 | { | ||
| 213 | 113 | AVFilterContext *ctx = outlink->src; | |
| 214 | 113 | AVFilterLink *inlink = outlink->src->inputs[0]; | |
| 215 | 113 | FilterLink *il = ff_filter_link(inlink); | |
| 216 | 113 | FilterLink *ol = ff_filter_link(outlink); | |
| 217 | 113 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format); | |
| 218 | 113 | TInterlaceContext *tinterlace = ctx->priv; | |
| 219 | int ret, i; | ||
| 220 | |||
| 221 | 113 | tinterlace->vsub = desc->log2_chroma_h; | |
| 222 | 113 | outlink->w = inlink->w; | |
| 223 |
3/4✓ Branch 0 taken 63 times.
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 63 times.
|
88 | outlink->h = tinterlace->mode == MODE_MERGE || tinterlace->mode == MODE_PAD || tinterlace->mode == MODE_MERGEX2? |
| 224 |
2/2✓ Branch 0 taken 88 times.
✓ Branch 1 taken 25 times.
|
201 | inlink->h*2 : inlink->h; |
| 225 |
5/6✓ Branch 0 taken 88 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 63 times.
✓ Branch 3 taken 25 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 63 times.
|
113 | if (tinterlace->mode == MODE_MERGE || tinterlace->mode == MODE_PAD || tinterlace->mode == MODE_MERGEX2) |
| 226 | 50 | outlink->sample_aspect_ratio = av_mul_q(inlink->sample_aspect_ratio, | |
| 227 | av_make_q(2, 1)); | ||
| 228 | |||
| 229 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 88 times.
|
113 | if (tinterlace->mode == MODE_PAD) { |
| 230 | 25 | uint8_t black[4] = { 0, 0, 0, 16 }; | |
| 231 | 25 | ret = ff_draw_init_from_link(&tinterlace->draw, outlink, 0); | |
| 232 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
|
25 | if (ret < 0) { |
| 233 | ✗ | av_log(ctx, AV_LOG_ERROR, "Failed to initialize FFDrawContext\n"); | |
| 234 | ✗ | return ret; | |
| 235 | } | ||
| 236 | 25 | ff_draw_color(&tinterlace->draw, &tinterlace->color, black); | |
| 237 | /* limited range */ | ||
| 238 |
2/2✓ Branch 1 taken 21 times.
✓ Branch 2 taken 4 times.
|
25 | if (!ff_pixfmt_is_in(outlink->format, full_scale_yuvj_pix_fmts)) { |
| 239 | 21 | ret = av_image_alloc(tinterlace->black_data[0], tinterlace->black_linesize, | |
| 240 | 21 | outlink->w, outlink->h, outlink->format, 16); | |
| 241 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (ret < 0) |
| 242 | ✗ | return ret; | |
| 243 | 21 | ff_fill_rectangle(&tinterlace->draw, &tinterlace->color, tinterlace->black_data[0], | |
| 244 | 21 | tinterlace->black_linesize, 0, 0, outlink->w, outlink->h); | |
| 245 | } | ||
| 246 | /* full range */ | ||
| 247 | 25 | tinterlace->color.comp[0].u8[0] = 0; | |
| 248 | 25 | ret = av_image_alloc(tinterlace->black_data[1], tinterlace->black_linesize, | |
| 249 | 25 | outlink->w, outlink->h, outlink->format, 16); | |
| 250 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
|
25 | if (ret < 0) |
| 251 | ✗ | return ret; | |
| 252 | 25 | ff_fill_rectangle(&tinterlace->draw, &tinterlace->color, tinterlace->black_data[1], | |
| 253 | 25 | tinterlace->black_linesize, 0, 0, outlink->w, outlink->h); | |
| 254 | } | ||
| 255 |
2/2✓ Branch 0 taken 53 times.
✓ Branch 1 taken 60 times.
|
113 | if (tinterlace->flags & (TINTERLACE_FLAG_VLPF | TINTERLACE_FLAG_CVLPF) |
| 256 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
|
53 | && !(tinterlace->mode == MODE_INTERLEAVE_TOP |
| 257 | ✗ | || tinterlace->mode == MODE_INTERLEAVE_BOTTOM)) { | |
| 258 | ✗ | av_log(ctx, AV_LOG_WARNING, "low_pass_filter flags ignored with mode %d\n", | |
| 259 | tinterlace->mode); | ||
| 260 | ✗ | tinterlace->flags &= ~(TINTERLACE_FLAG_VLPF | TINTERLACE_FLAG_CVLPF); | |
| 261 | } | ||
| 262 | 113 | tinterlace->preout_time_base = inlink->time_base; | |
| 263 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 113 times.
|
113 | if (tinterlace->mode == MODE_INTERLACEX2) { |
| 264 | ✗ | tinterlace->preout_time_base.den *= 2; | |
| 265 | ✗ | ol->frame_rate = av_mul_q(il->frame_rate, (AVRational){2,1}); | |
| 266 | ✗ | outlink->time_base = av_mul_q(inlink->time_base , (AVRational){1,2}); | |
| 267 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 113 times.
|
113 | } else if (tinterlace->mode == MODE_MERGEX2) { |
| 268 | ✗ | ol->frame_rate = il->frame_rate; | |
| 269 | ✗ | outlink->time_base = inlink->time_base; | |
| 270 |
2/2✓ Branch 0 taken 88 times.
✓ Branch 1 taken 25 times.
|
113 | } else if (tinterlace->mode != MODE_PAD) { |
| 271 | 88 | ol->frame_rate = av_mul_q(il->frame_rate, (AVRational){1,2}); | |
| 272 | 88 | outlink->time_base = av_mul_q(inlink->time_base , (AVRational){2,1}); | |
| 273 | } | ||
| 274 | |||
| 275 |
2/2✓ Branch 0 taken 339 times.
✓ Branch 1 taken 113 times.
|
452 | for (i = 0; i<FF_ARRAY_ELEMS(standard_tbs); i++){ |
| 276 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 339 times.
|
339 | if (!av_cmp_q(standard_tbs[i], outlink->time_base)) |
| 277 | ✗ | break; | |
| 278 | } | ||
| 279 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 113 times.
|
113 | if (i == FF_ARRAY_ELEMS(standard_tbs) || |
| 280 | ✗ | (tinterlace->flags & TINTERLACE_FLAG_EXACT_TB)) | |
| 281 | 113 | outlink->time_base = tinterlace->preout_time_base; | |
| 282 | |||
| 283 | 113 | tinterlace->csp = av_pix_fmt_desc_get(outlink->format); | |
| 284 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 87 times.
|
113 | if (tinterlace->flags & TINTERLACE_FLAG_CVLPF) { |
| 285 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 15 times.
|
26 | if (tinterlace->csp->comp[0].depth > 8) |
| 286 | 11 | tinterlace->lowpass_line = lowpass_line_complex_c_16; | |
| 287 | else | ||
| 288 | 15 | tinterlace->lowpass_line = lowpass_line_complex_c; | |
| 289 | #if ARCH_X86 && HAVE_X86ASM | ||
| 290 | 26 | ff_tinterlace_init_x86(tinterlace); | |
| 291 | #endif | ||
| 292 |
2/2✓ Branch 0 taken 27 times.
✓ Branch 1 taken 60 times.
|
87 | } else if (tinterlace->flags & TINTERLACE_FLAG_VLPF) { |
| 293 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 16 times.
|
27 | if (tinterlace->csp->comp[0].depth > 8) |
| 294 | 11 | tinterlace->lowpass_line = lowpass_line_c_16; | |
| 295 | else | ||
| 296 | 16 | tinterlace->lowpass_line = lowpass_line_c; | |
| 297 | #if ARCH_X86 && HAVE_X86ASM | ||
| 298 | 27 | ff_tinterlace_init_x86(tinterlace); | |
| 299 | #endif | ||
| 300 | } | ||
| 301 | |||
| 302 | 113 | ret = ff_ccfifo_init(&tinterlace->cc_fifo, ol->frame_rate, ctx); | |
| 303 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 113 times.
|
113 | if (ret < 0) { |
| 304 | ✗ | av_log(ctx, AV_LOG_ERROR, "Failure to setup CC FIFO queue\n"); | |
| 305 | ✗ | return ret; | |
| 306 | } | ||
| 307 | |||
| 308 | 113 | av_log(ctx, AV_LOG_VERBOSE, "mode:%d filter:%s h:%d -> h:%d\n", tinterlace->mode, | |
| 309 |
2/2✓ Branch 0 taken 87 times.
✓ Branch 1 taken 26 times.
|
113 | (tinterlace->flags & TINTERLACE_FLAG_CVLPF) ? "complex" : |
| 310 |
2/2✓ Branch 0 taken 27 times.
✓ Branch 1 taken 60 times.
|
87 | (tinterlace->flags & TINTERLACE_FLAG_VLPF) ? "linear" : "off", |
| 311 | inlink->h, outlink->h); | ||
| 312 | |||
| 313 | 113 | return 0; | |
| 314 | } | ||
| 315 | |||
| 316 | #define FIELD_UPPER 0 | ||
| 317 | #define FIELD_LOWER 1 | ||
| 318 | #define FIELD_UPPER_AND_LOWER 2 | ||
| 319 | |||
| 320 | /** | ||
| 321 | * Copy picture field from src to dst. | ||
| 322 | * | ||
| 323 | * @param src_field copy from upper, lower field or both | ||
| 324 | * @param interleave leave a padding line between each copied line | ||
| 325 | * @param dst_field copy to upper or lower field, | ||
| 326 | * only meaningful when interleave is selected | ||
| 327 | * @param flags context flags | ||
| 328 | */ | ||
| 329 | static inline | ||
| 330 | 420 | void copy_picture_field(TInterlaceContext *tinterlace, | |
| 331 | uint8_t *dst[4], int dst_linesize[4], | ||
| 332 | const uint8_t *src[4], int src_linesize[4], | ||
| 333 | enum AVPixelFormat format, int w, int src_h, | ||
| 334 | int src_field, int interleave, int dst_field, | ||
| 335 | int flags) | ||
| 336 | { | ||
| 337 | 420 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format); | |
| 338 | 420 | int hsub = desc->log2_chroma_w; | |
| 339 | 420 | int plane, vsub = desc->log2_chroma_h; | |
| 340 |
2/2✓ Branch 0 taken 150 times.
✓ Branch 1 taken 270 times.
|
420 | int k = src_field == FIELD_UPPER_AND_LOWER ? 1 : 2; |
| 341 | int h; | ||
| 342 | |||
| 343 |
2/2✓ Branch 0 taken 1300 times.
✓ Branch 1 taken 420 times.
|
1720 | for (plane = 0; plane < desc->nb_components; plane++) { |
| 344 |
4/4✓ Branch 0 taken 890 times.
✓ Branch 1 taken 410 times.
✓ Branch 2 taken 410 times.
✓ Branch 3 taken 480 times.
|
1300 | int lines = plane == 1 || plane == 2 ? AV_CEIL_RSHIFT(src_h, vsub) : src_h; |
| 345 |
4/4✓ Branch 0 taken 890 times.
✓ Branch 1 taken 410 times.
✓ Branch 2 taken 410 times.
✓ Branch 3 taken 480 times.
|
1300 | int cols = plane == 1 || plane == 2 ? AV_CEIL_RSHIFT( w, hsub) : w; |
| 346 | 1300 | uint8_t *dstp = dst[plane]; | |
| 347 | 1300 | const uint8_t *srcp = src[plane]; | |
| 348 | 1300 | int srcp_linesize = src_linesize[plane] * k; | |
| 349 |
1/2✓ Branch 0 taken 1300 times.
✗ Branch 1 not taken.
|
1300 | int dstp_linesize = dst_linesize[plane] * (interleave ? 2 : 1); |
| 350 | 1300 | int clip_max = (1 << tinterlace->csp->comp[plane].depth) - 1; | |
| 351 | |||
| 352 | 1300 | lines = (lines + (src_field == FIELD_UPPER)) / k; | |
| 353 |
2/2✓ Branch 0 taken 413 times.
✓ Branch 1 taken 887 times.
|
1300 | if (src_field == FIELD_LOWER) |
| 354 | 413 | srcp += src_linesize[plane]; | |
| 355 |
3/4✓ Branch 0 taken 1300 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 650 times.
✓ Branch 3 taken 650 times.
|
1300 | if (interleave && dst_field == FIELD_LOWER) |
| 356 | 650 | dstp += dst_linesize[plane]; | |
| 357 | // Low-pass filtering is required when creating an interlaced destination from | ||
| 358 | // a progressive source which contains high-frequency vertical detail. | ||
| 359 | // Filtering will reduce interlace 'twitter' and Moire patterning. | ||
| 360 |
2/2✓ Branch 0 taken 766 times.
✓ Branch 1 taken 534 times.
|
1300 | if (flags & (TINTERLACE_FLAG_VLPF | TINTERLACE_FLAG_CVLPF)) { |
| 361 | 766 | int x = !!(flags & TINTERLACE_FLAG_CVLPF); | |
| 362 |
2/2✓ Branch 0 taken 82080 times.
✓ Branch 1 taken 766 times.
|
82846 | for (h = lines; h > 0; h--) { |
| 363 | 82080 | ptrdiff_t pref = src_linesize[plane]; | |
| 364 | 82080 | ptrdiff_t mref = -pref; | |
| 365 |
2/2✓ Branch 0 taken 1074 times.
✓ Branch 1 taken 81006 times.
|
82080 | if (h >= (lines - x)) mref = 0; // there is no line above |
| 366 |
2/2✓ Branch 0 taken 1074 times.
✓ Branch 1 taken 79932 times.
|
81006 | else if (h <= (1 + x)) pref = 0; // there is no line below |
| 367 | |||
| 368 | 82080 | tinterlace->lowpass_line(dstp, cols, srcp, mref, pref, clip_max); | |
| 369 | 82080 | dstp += dstp_linesize; | |
| 370 | 82080 | srcp += srcp_linesize; | |
| 371 | } | ||
| 372 | } else { | ||
| 373 |
2/2✓ Branch 0 taken 216 times.
✓ Branch 1 taken 318 times.
|
534 | if (tinterlace->csp->comp[plane].depth > 8) |
| 374 | 216 | cols *= 2; | |
| 375 | 534 | av_image_copy_plane(dstp, dstp_linesize, srcp, srcp_linesize, cols, lines); | |
| 376 | } | ||
| 377 | } | ||
| 378 | 420 | } | |
| 379 | |||
| 380 | 480 | static int filter_frame(AVFilterLink *inlink, AVFrame *picref) | |
| 381 | { | ||
| 382 | 480 | FilterLink *inl = ff_filter_link(inlink); | |
| 383 | 480 | AVFilterContext *ctx = inlink->dst; | |
| 384 | 480 | AVFilterLink *outlink = ctx->outputs[0]; | |
| 385 | 480 | FilterLink *l = ff_filter_link(outlink); | |
| 386 | 480 | TInterlaceContext *tinterlace = ctx->priv; | |
| 387 | AVFrame *cur, *next, *out; | ||
| 388 | int field, tff, full, ret; | ||
| 389 | |||
| 390 | 480 | av_frame_free(&tinterlace->cur); | |
| 391 | 480 | tinterlace->cur = tinterlace->next; | |
| 392 | 480 | tinterlace->next = picref; | |
| 393 | |||
| 394 | 480 | ff_ccfifo_extract(&tinterlace->cc_fifo, picref); | |
| 395 | |||
| 396 | 480 | cur = tinterlace->cur; | |
| 397 | 480 | next = tinterlace->next; | |
| 398 | /* we need at least two frames */ | ||
| 399 |
2/2✓ Branch 0 taken 270 times.
✓ Branch 1 taken 210 times.
|
480 | if (!tinterlace->cur) |
| 400 | 270 | return 0; | |
| 401 | |||
| 402 |
3/6✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 135 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
210 | switch (tinterlace->mode) { |
| 403 | 25 | case MODE_MERGEX2: /* move the odd frame into the upper field of the new image, even into | |
| 404 | * the lower field, generating a double-height video at same framerate */ | ||
| 405 | case MODE_MERGE: /* move the odd frame into the upper field of the new image, even into | ||
| 406 | * the lower field, generating a double-height video at half framerate */ | ||
| 407 | 25 | out = ff_get_video_buffer(outlink, outlink->w, outlink->h); | |
| 408 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
|
25 | if (!out) |
| 409 | ✗ | return AVERROR(ENOMEM); | |
| 410 | 25 | av_frame_copy_props(out, cur); | |
| 411 | 25 | out->height = outlink->h; | |
| 412 | 25 | out->flags |= AV_FRAME_FLAG_INTERLACED | AV_FRAME_FLAG_TOP_FIELD_FIRST; | |
| 413 | 25 | out->sample_aspect_ratio = av_mul_q(cur->sample_aspect_ratio, av_make_q(2, 1)); | |
| 414 | |||
| 415 | /* write odd frame lines into the upper field of the new frame */ | ||
| 416 | 25 | copy_picture_field(tinterlace, out->data, out->linesize, | |
| 417 | 25 | (const uint8_t **)cur->data, cur->linesize, | |
| 418 | 25 | inlink->format, inlink->w, inlink->h, | |
| 419 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
|
25 | FIELD_UPPER_AND_LOWER, 1, tinterlace->mode == MODE_MERGEX2 ? (1 + inl->frame_count_out) & 1 ? FIELD_LOWER : FIELD_UPPER : FIELD_UPPER, tinterlace->flags); |
| 420 | /* write even frame lines into the lower field of the new frame */ | ||
| 421 | 25 | copy_picture_field(tinterlace, out->data, out->linesize, | |
| 422 | 25 | (const uint8_t **)next->data, next->linesize, | |
| 423 | 25 | inlink->format, inlink->w, inlink->h, | |
| 424 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
25 | FIELD_UPPER_AND_LOWER, 1, tinterlace->mode == MODE_MERGEX2 ? (1 + inl->frame_count_out) & 1 ? FIELD_UPPER : FIELD_LOWER : FIELD_LOWER, tinterlace->flags); |
| 425 |
1/2✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
|
25 | if (tinterlace->mode != MODE_MERGEX2) |
| 426 | 25 | av_frame_free(&tinterlace->next); | |
| 427 | 25 | break; | |
| 428 | |||
| 429 | ✗ | case MODE_DROP_ODD: /* only output even frames, odd frames are dropped; height unchanged, half framerate */ | |
| 430 | case MODE_DROP_EVEN: /* only output odd frames, even frames are dropped; height unchanged, half framerate */ | ||
| 431 | ✗ | out = av_frame_clone(tinterlace->mode == MODE_DROP_EVEN ? cur : next); | |
| 432 | ✗ | if (!out) | |
| 433 | ✗ | return AVERROR(ENOMEM); | |
| 434 | ✗ | av_frame_free(&tinterlace->next); | |
| 435 | ✗ | break; | |
| 436 | |||
| 437 | 50 | case MODE_PAD: /* expand each frame to double height, but pad alternate | |
| 438 | * lines with black; framerate unchanged */ | ||
| 439 | 50 | out = ff_get_video_buffer(outlink, outlink->w, outlink->h); | |
| 440 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
|
50 | if (!out) |
| 441 | ✗ | return AVERROR(ENOMEM); | |
| 442 | 50 | av_frame_copy_props(out, cur); | |
| 443 | 50 | out->height = outlink->h; | |
| 444 | 50 | out->sample_aspect_ratio = av_mul_q(cur->sample_aspect_ratio, av_make_q(2, 1)); | |
| 445 | |||
| 446 | 50 | field = (1 + l->frame_count_in) & 1 ? FIELD_UPPER : FIELD_LOWER; | |
| 447 |
3/4✓ Branch 0 taken 40 times.
✓ Branch 1 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 40 times.
|
50 | full = out->color_range == AVCOL_RANGE_JPEG || ff_pixfmt_is_in(out->format, full_scale_yuvj_pix_fmts); |
| 448 | /* copy upper and lower fields */ | ||
| 449 | 50 | copy_picture_field(tinterlace, out->data, out->linesize, | |
| 450 | 50 | (const uint8_t **)cur->data, cur->linesize, | |
| 451 | 50 | inlink->format, inlink->w, inlink->h, | |
| 452 | FIELD_UPPER_AND_LOWER, 1, field, tinterlace->flags); | ||
| 453 | /* pad with black the other field */ | ||
| 454 | 50 | copy_picture_field(tinterlace, out->data, out->linesize, | |
| 455 | 50 | (const uint8_t **)tinterlace->black_data[full], tinterlace->black_linesize, | |
| 456 | 50 | inlink->format, inlink->w, inlink->h, | |
| 457 | FIELD_UPPER_AND_LOWER, 1, !field, tinterlace->flags); | ||
| 458 | 50 | break; | |
| 459 | |||
| 460 | /* interleave upper/lower lines from odd frames with lower/upper lines from even frames, | ||
| 461 | * halving the frame rate and preserving image height */ | ||
| 462 | 135 | case MODE_INTERLEAVE_TOP: /* top field first */ | |
| 463 | case MODE_INTERLEAVE_BOTTOM: /* bottom field first */ | ||
| 464 |
3/4✓ Branch 0 taken 75 times.
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 75 times.
|
135 | if ((tinterlace->flags & TINTERLACE_FLAG_BYPASS_IL) && (cur->flags & AV_FRAME_FLAG_INTERLACED)) { |
| 465 | ✗ | av_log(ctx, AV_LOG_WARNING, | |
| 466 | "video is already interlaced, adjusting framerate only\n"); | ||
| 467 | ✗ | out = av_frame_clone(cur); | |
| 468 | ✗ | if (!out) | |
| 469 | ✗ | return AVERROR(ENOMEM); | |
| 470 | ✗ | out->pts /= 2; // adjust pts to new framerate | |
| 471 | ✗ | ff_ccfifo_inject(&tinterlace->cc_fifo, out); | |
| 472 | ✗ | ret = ff_filter_frame(outlink, out); | |
| 473 | ✗ | return ret; | |
| 474 | } | ||
| 475 | 135 | tff = tinterlace->mode == MODE_INTERLEAVE_TOP; | |
| 476 | 135 | out = ff_get_video_buffer(outlink, outlink->w, outlink->h); | |
| 477 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 135 times.
|
135 | if (!out) |
| 478 | ✗ | return AVERROR(ENOMEM); | |
| 479 | 135 | av_frame_copy_props(out, cur); | |
| 480 | 135 | out->flags |= AV_FRAME_FLAG_INTERLACED; | |
| 481 |
1/2✓ Branch 0 taken 135 times.
✗ Branch 1 not taken.
|
135 | if (tff) |
| 482 | 135 | out->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; | |
| 483 | else | ||
| 484 | ✗ | out->flags &= ~AV_FRAME_FLAG_TOP_FIELD_FIRST; | |
| 485 | |||
| 486 | /* copy upper/lower field from cur */ | ||
| 487 | 135 | copy_picture_field(tinterlace, out->data, out->linesize, | |
| 488 | 135 | (const uint8_t **)cur->data, cur->linesize, | |
| 489 | 135 | inlink->format, inlink->w, inlink->h, | |
| 490 | tff ? FIELD_UPPER : FIELD_LOWER, 1, tff ? FIELD_UPPER : FIELD_LOWER, | ||
| 491 | tinterlace->flags); | ||
| 492 | /* copy lower/upper field from next */ | ||
| 493 | 135 | copy_picture_field(tinterlace, out->data, out->linesize, | |
| 494 | 135 | (const uint8_t **)next->data, next->linesize, | |
| 495 | 135 | inlink->format, inlink->w, inlink->h, | |
| 496 | tff ? FIELD_LOWER : FIELD_UPPER, 1, tff ? FIELD_LOWER : FIELD_UPPER, | ||
| 497 | tinterlace->flags); | ||
| 498 | 135 | av_frame_free(&tinterlace->next); | |
| 499 | 135 | break; | |
| 500 | ✗ | case MODE_INTERLACEX2: /* re-interlace preserving image height, double frame rate */ | |
| 501 | /* output current frame first */ | ||
| 502 | ✗ | out = av_frame_clone(cur); | |
| 503 | ✗ | if (!out) | |
| 504 | ✗ | return AVERROR(ENOMEM); | |
| 505 | ✗ | out->flags |= AV_FRAME_FLAG_INTERLACED; | |
| 506 | ✗ | if (cur->pts != AV_NOPTS_VALUE) | |
| 507 | ✗ | out->pts = cur->pts*2; | |
| 508 | |||
| 509 | ✗ | out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base); | |
| 510 | ✗ | ff_ccfifo_inject(&tinterlace->cc_fifo, out); | |
| 511 | ✗ | if ((ret = ff_filter_frame(outlink, out)) < 0) | |
| 512 | ✗ | return ret; | |
| 513 | |||
| 514 | /* output mix of current and next frame */ | ||
| 515 | ✗ | tff = !!(next->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST); | |
| 516 | ✗ | out = ff_get_video_buffer(outlink, outlink->w, outlink->h); | |
| 517 | ✗ | if (!out) | |
| 518 | ✗ | return AVERROR(ENOMEM); | |
| 519 | ✗ | av_frame_copy_props(out, next); | |
| 520 | ✗ | out->flags |= AV_FRAME_FLAG_INTERLACED; | |
| 521 | ✗ | if (tff) | |
| 522 | ✗ | out->flags &= ~AV_FRAME_FLAG_TOP_FIELD_FIRST; | |
| 523 | else | ||
| 524 | ✗ | out->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; | |
| 525 | |||
| 526 | ✗ | if (next->pts != AV_NOPTS_VALUE && cur->pts != AV_NOPTS_VALUE) | |
| 527 | ✗ | out->pts = cur->pts + next->pts; | |
| 528 | else | ||
| 529 | ✗ | out->pts = AV_NOPTS_VALUE; | |
| 530 | /* write current frame second field lines into the second field of the new frame */ | ||
| 531 | ✗ | copy_picture_field(tinterlace, out->data, out->linesize, | |
| 532 | ✗ | (const uint8_t **)cur->data, cur->linesize, | |
| 533 | ✗ | inlink->format, inlink->w, inlink->h, | |
| 534 | tff ? FIELD_LOWER : FIELD_UPPER, 1, tff ? FIELD_LOWER : FIELD_UPPER, | ||
| 535 | tinterlace->flags); | ||
| 536 | /* write next frame first field lines into the first field of the new frame */ | ||
| 537 | ✗ | copy_picture_field(tinterlace, out->data, out->linesize, | |
| 538 | ✗ | (const uint8_t **)next->data, next->linesize, | |
| 539 | ✗ | inlink->format, inlink->w, inlink->h, | |
| 540 | tff ? FIELD_UPPER : FIELD_LOWER, 1, tff ? FIELD_UPPER : FIELD_LOWER, | ||
| 541 | tinterlace->flags); | ||
| 542 | ✗ | break; | |
| 543 | ✗ | default: | |
| 544 | ✗ | av_assert0(0); | |
| 545 | } | ||
| 546 | |||
| 547 | 210 | out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base); | |
| 548 | 210 | out->duration = av_rescale_q(1, av_inv_q(l->frame_rate), outlink->time_base); | |
| 549 | 210 | ff_ccfifo_inject(&tinterlace->cc_fifo, out); | |
| 550 | 210 | ret = ff_filter_frame(outlink, out); | |
| 551 | |||
| 552 | 210 | return ret; | |
| 553 | } | ||
| 554 | |||
| 555 | 6 | static int init_interlace(AVFilterContext *ctx) | |
| 556 | { | ||
| 557 | 6 | TInterlaceContext *tinterlace = ctx->priv; | |
| 558 | |||
| 559 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if (tinterlace->mode <= MODE_BFF) |
| 560 | 6 | tinterlace->mode += MODE_INTERLEAVE_TOP; | |
| 561 | |||
| 562 | 6 | tinterlace->flags |= TINTERLACE_FLAG_BYPASS_IL; | |
| 563 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
|
6 | if (tinterlace->lowpass == VLPF_LIN) |
| 564 | 4 | tinterlace->flags |= TINTERLACE_FLAG_VLPF; | |
| 565 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
|
6 | if (tinterlace->lowpass == VLPF_CMP) |
| 566 | 2 | tinterlace->flags |= TINTERLACE_FLAG_CVLPF; | |
| 567 | |||
| 568 | 6 | return 0; | |
| 569 | } | ||
| 570 | |||
| 571 | static const AVFilterPad tinterlace_inputs[] = { | ||
| 572 | { | ||
| 573 | .name = "default", | ||
| 574 | .type = AVMEDIA_TYPE_VIDEO, | ||
| 575 | .filter_frame = filter_frame, | ||
| 576 | }, | ||
| 577 | }; | ||
| 578 | |||
| 579 | static const AVFilterPad tinterlace_outputs[] = { | ||
| 580 | { | ||
| 581 | .name = "default", | ||
| 582 | .type = AVMEDIA_TYPE_VIDEO, | ||
| 583 | .config_props = config_out_props, | ||
| 584 | }, | ||
| 585 | }; | ||
| 586 | |||
| 587 | const FFFilter ff_vf_tinterlace = { | ||
| 588 | .p.name = "tinterlace", | ||
| 589 | .p.description = NULL_IF_CONFIG_SMALL("Perform temporal field interlacing."), | ||
| 590 | .p.priv_class = &tinterlace_class, | ||
| 591 | .priv_size = sizeof(TInterlaceContext), | ||
| 592 | .uninit = uninit, | ||
| 593 | FILTER_INPUTS(tinterlace_inputs), | ||
| 594 | FILTER_OUTPUTS(tinterlace_outputs), | ||
| 595 | FILTER_PIXFMTS_ARRAY(pix_fmts), | ||
| 596 | }; | ||
| 597 | |||
| 598 | |||
| 599 | const FFFilter ff_vf_interlace = { | ||
| 600 | .p.name = "interlace", | ||
| 601 | .p.description = NULL_IF_CONFIG_SMALL("Convert progressive video into interlaced."), | ||
| 602 | .p.priv_class = &interlace_class, | ||
| 603 | .priv_size = sizeof(TInterlaceContext), | ||
| 604 | .init = init_interlace, | ||
| 605 | .uninit = uninit, | ||
| 606 | FILTER_INPUTS(tinterlace_inputs), | ||
| 607 | FILTER_OUTPUTS(tinterlace_outputs), | ||
| 608 | FILTER_PIXFMTS_ARRAY(pix_fmts), | ||
| 609 | }; | ||
| 610 |