annotate ffmpeg/libavfilter/vf_tinterlace.c @ 13:844d341cf643 tip

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