00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00028 #include "libavutil/imgutils.h"
00029 #include "libavutil/avassert.h"
00030 #include "avfilter.h"
00031 #include "internal.h"
00032
00033 enum TInterlaceMode {
00034 MODE_MERGE = 0,
00035 MODE_DROP_EVEN,
00036 MODE_DROP_ODD,
00037 MODE_PAD,
00038 MODE_INTERLEAVE_TOP,
00039 MODE_INTERLEAVE_BOTTOM,
00040 MODE_INTERLACEX2,
00041 };
00042
00043 static const char *tinterlace_mode_str[] = {
00044 "merge",
00045 "drop_even",
00046 "drop_odd",
00047 "pad",
00048 "interleave_top",
00049 "interleave_bottom",
00050 "interlacex2",
00051 NULL
00052 };
00053
00054 typedef struct {
00055 enum TInterlaceMode mode;
00056 int frame;
00057 int vsub;
00058 AVFilterBufferRef *cur;
00059 AVFilterBufferRef *next;
00060 uint8_t *black_data[4];
00061 int black_linesize[4];
00062 } TInterlaceContext;
00063
00064 #define FULL_SCALE_YUVJ_FORMATS \
00065 PIX_FMT_YUVJ420P, PIX_FMT_YUVJ422P, PIX_FMT_YUVJ444P, PIX_FMT_YUVJ440P
00066
00067 static enum PixelFormat full_scale_yuvj_pix_fmts[] = {
00068 FULL_SCALE_YUVJ_FORMATS, PIX_FMT_NONE
00069 };
00070
00071 static int query_formats(AVFilterContext *ctx)
00072 {
00073 static const enum PixelFormat pix_fmts[] = {
00074 PIX_FMT_YUV420P, PIX_FMT_YUV422P, PIX_FMT_YUV444P,
00075 PIX_FMT_YUV444P, PIX_FMT_YUV410P, PIX_FMT_YUVA420P,
00076 PIX_FMT_GRAY8, FULL_SCALE_YUVJ_FORMATS,
00077 PIX_FMT_NONE
00078 };
00079
00080 ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
00081 return 0;
00082 }
00083
00084 static av_cold int init(AVFilterContext *ctx, const char *args)
00085 {
00086 TInterlaceContext *tinterlace = ctx->priv;
00087 int i;
00088 char c;
00089
00090 tinterlace->mode = MODE_MERGE;
00091
00092 if (args) {
00093 if (sscanf(args, "%d%c", (int *)&tinterlace->mode, &c) == 1) {
00094 if (tinterlace->mode > 6) {
00095 av_log(ctx, AV_LOG_ERROR,
00096 "Invalid mode '%s', use an integer between 0 and 6\n", args);
00097 return AVERROR(EINVAL);
00098 }
00099
00100 av_log(ctx, AV_LOG_WARNING,
00101 "Using numeric constant is deprecated, use symbolic values\n");
00102 } else {
00103 for (i = 0; tinterlace_mode_str[i]; i++) {
00104 if (!strcmp(tinterlace_mode_str[i], args)) {
00105 tinterlace->mode = i;
00106 break;
00107 }
00108 }
00109 if (!tinterlace_mode_str[i]) {
00110 av_log(ctx, AV_LOG_ERROR, "Invalid argument '%s'\n", args);
00111 return AVERROR(EINVAL);
00112 }
00113 }
00114 }
00115
00116 return 0;
00117 }
00118
00119 static av_cold void uninit(AVFilterContext *ctx)
00120 {
00121 TInterlaceContext *tinterlace = ctx->priv;
00122
00123 if (tinterlace->cur ) avfilter_unref_bufferp(&tinterlace->cur );
00124 if (tinterlace->next) avfilter_unref_bufferp(&tinterlace->next);
00125
00126 av_freep(&tinterlace->black_data[0]);
00127 }
00128
00129 static int config_out_props(AVFilterLink *outlink)
00130 {
00131 AVFilterContext *ctx = outlink->src;
00132 AVFilterLink *inlink = outlink->src->inputs[0];
00133 const AVPixFmtDescriptor *desc = &av_pix_fmt_descriptors[outlink->format];
00134 TInterlaceContext *tinterlace = ctx->priv;
00135
00136 tinterlace->vsub = desc->log2_chroma_h;
00137 outlink->w = inlink->w;
00138 outlink->h = tinterlace->mode == MODE_MERGE || tinterlace->mode == MODE_PAD ?
00139 inlink->h*2 : inlink->h;
00140
00141 if (tinterlace->mode == MODE_PAD) {
00142 uint8_t black[4] = { 16, 128, 128, 16 };
00143 int i, ret;
00144 if (ff_fmt_is_in(outlink->format, full_scale_yuvj_pix_fmts))
00145 black[0] = black[3] = 0;
00146 ret = av_image_alloc(tinterlace->black_data, tinterlace->black_linesize,
00147 outlink->w, outlink->h, outlink->format, 1);
00148 if (ret < 0)
00149 return ret;
00150
00151
00152 for (i = 0; i < 4 && tinterlace->black_data[i]; i++) {
00153 int h = i == 1 || i == 2 ? outlink->h >> desc->log2_chroma_h : outlink->h;
00154 memset(tinterlace->black_data[i], black[i],
00155 tinterlace->black_linesize[i] * h);
00156 }
00157 }
00158 av_log(ctx, AV_LOG_VERBOSE, "mode:%s h:%d -> h:%d\n",
00159 tinterlace_mode_str[tinterlace->mode], inlink->h, outlink->h);
00160
00161 return 0;
00162 }
00163
00164 #define FIELD_UPPER 0
00165 #define FIELD_LOWER 1
00166 #define FIELD_UPPER_AND_LOWER 2
00167
00176 static inline
00177 void copy_picture_field(uint8_t *dst[4], int dst_linesize[4],
00178 const uint8_t *src[4], int src_linesize[4],
00179 enum PixelFormat format, int w, int src_h,
00180 int src_field, int interleave, int dst_field)
00181 {
00182 const AVPixFmtDescriptor *desc = &av_pix_fmt_descriptors[format];
00183 int plane, vsub = desc->log2_chroma_h;
00184 int k = src_field == FIELD_UPPER_AND_LOWER ? 1 : 2;
00185
00186 for (plane = 0; plane < desc->nb_components; plane++) {
00187 int lines = plane == 1 || plane == 2 ? src_h >> vsub : src_h;
00188 int linesize = av_image_get_linesize(format, w, plane);
00189 uint8_t *dstp = dst[plane];
00190 const uint8_t *srcp = src[plane];
00191 lines /= k;
00192 if (src_field == FIELD_LOWER)
00193 srcp += src_linesize[plane];
00194 if (interleave && dst_field == FIELD_LOWER)
00195 dstp += dst_linesize[plane];
00196 av_image_copy_plane(dstp, dst_linesize[plane] * (interleave ? 2 : 1),
00197 srcp, src_linesize[plane]*k, linesize, lines);
00198 }
00199 }
00200
00201 static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
00202 {
00203 AVFilterContext *ctx = inlink->dst;
00204 TInterlaceContext *tinterlace = ctx->priv;
00205
00206 avfilter_unref_buffer(tinterlace->cur);
00207 tinterlace->cur = tinterlace->next;
00208 tinterlace->next = picref;
00209 inlink->cur_buf = NULL;
00210 return 0;
00211 }
00212
00213 static int end_frame(AVFilterLink *inlink)
00214 {
00215 AVFilterContext *ctx = inlink->dst;
00216 AVFilterLink *outlink = ctx->outputs[0];
00217 TInterlaceContext *tinterlace = ctx->priv;
00218 AVFilterBufferRef *cur = tinterlace->cur;
00219 AVFilterBufferRef *next = tinterlace->next;
00220 AVFilterBufferRef *out = NULL;
00221 int field, tff;
00222
00223
00224 if (!tinterlace->cur)
00225 return 0;
00226
00227 switch (tinterlace->mode) {
00228 case MODE_MERGE:
00229
00230 out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
00231 avfilter_copy_buffer_ref_props(out, cur);
00232 out->video->h = outlink->h;
00233 out->video->interlaced = 1;
00234 out->video->top_field_first = 1;
00235
00236
00237 copy_picture_field(out->data, out->linesize,
00238 (const uint8_t **)cur->data, cur->linesize,
00239 inlink->format, inlink->w, inlink->h,
00240 FIELD_UPPER_AND_LOWER, 1, FIELD_UPPER);
00241
00242 copy_picture_field(out->data, out->linesize,
00243 (const uint8_t **)next->data, next->linesize,
00244 inlink->format, inlink->w, inlink->h,
00245 FIELD_UPPER_AND_LOWER, 1, FIELD_LOWER);
00246 avfilter_unref_bufferp(&tinterlace->next);
00247 break;
00248
00249 case MODE_DROP_ODD:
00250 case MODE_DROP_EVEN:
00251 out = avfilter_ref_buffer(tinterlace->mode == MODE_DROP_EVEN ? cur : next, AV_PERM_READ);
00252 avfilter_unref_bufferp(&tinterlace->next);
00253 break;
00254
00255 case MODE_PAD:
00256
00257 out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
00258 avfilter_copy_buffer_ref_props(out, cur);
00259 out->video->h = outlink->h;
00260
00261 field = (1 + tinterlace->frame) & 1 ? FIELD_UPPER : FIELD_LOWER;
00262
00263 copy_picture_field(out->data, out->linesize,
00264 (const uint8_t **)cur->data, cur->linesize,
00265 inlink->format, inlink->w, inlink->h,
00266 FIELD_UPPER_AND_LOWER, 1, field);
00267
00268 copy_picture_field(out->data, out->linesize,
00269 (const uint8_t **)tinterlace->black_data, tinterlace->black_linesize,
00270 inlink->format, inlink->w, inlink->h,
00271 FIELD_UPPER_AND_LOWER, 1, !field);
00272 break;
00273
00274
00275
00276 case MODE_INTERLEAVE_TOP:
00277 case MODE_INTERLEAVE_BOTTOM:
00278 tff = tinterlace->mode == MODE_INTERLEAVE_TOP;
00279 out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
00280 avfilter_copy_buffer_ref_props(out, cur);
00281 out->video->interlaced = 1;
00282 out->video->top_field_first = tff;
00283
00284
00285 copy_picture_field(out->data, out->linesize,
00286 (const uint8_t **)cur->data, cur->linesize,
00287 inlink->format, inlink->w, inlink->h,
00288 tff ? FIELD_UPPER : FIELD_LOWER, 1, tff ? FIELD_UPPER : FIELD_LOWER);
00289
00290 copy_picture_field(out->data, out->linesize,
00291 (const uint8_t **)next->data, next->linesize,
00292 inlink->format, inlink->w, inlink->h,
00293 tff ? FIELD_LOWER : FIELD_UPPER, 1, tff ? FIELD_LOWER : FIELD_UPPER);
00294 avfilter_unref_bufferp(&tinterlace->next);
00295 break;
00296 case MODE_INTERLACEX2:
00297
00298 out = avfilter_ref_buffer(cur, ~AV_PERM_WRITE);
00299 out->video->interlaced = 1;
00300
00301 ff_start_frame(outlink, out);
00302 ff_draw_slice(outlink, 0, outlink->h, 1);
00303 ff_end_frame(outlink);
00304
00305
00306 tff = next->video->top_field_first;
00307 out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
00308 avfilter_copy_buffer_ref_props(out, next);
00309 out->video->interlaced = 1;
00310
00311
00312 copy_picture_field(out->data, out->linesize,
00313 (const uint8_t **)cur->data, cur->linesize,
00314 inlink->format, inlink->w, inlink->h,
00315 tff ? FIELD_LOWER : FIELD_UPPER, 1, tff ? FIELD_LOWER : FIELD_UPPER);
00316
00317 copy_picture_field(out->data, out->linesize,
00318 (const uint8_t **)next->data, next->linesize,
00319 inlink->format, inlink->w, inlink->h,
00320 tff ? FIELD_UPPER : FIELD_LOWER, 1, tff ? FIELD_UPPER : FIELD_LOWER);
00321 break;
00322 }
00323
00324 ff_start_frame(outlink, out);
00325 ff_draw_slice(outlink, 0, outlink->h, 1);
00326 ff_end_frame(outlink);
00327
00328 tinterlace->frame++;
00329
00330 return 0;
00331 }
00332
00333 static int poll_frame(AVFilterLink *outlink)
00334 {
00335 TInterlaceContext *tinterlace = outlink->src->priv;
00336 AVFilterLink *inlink = outlink->src->inputs[0];
00337 int ret, val;
00338
00339 val = ff_poll_frame(inlink);
00340
00341 if (val == 1 && !tinterlace->next) {
00342 if ((ret = ff_request_frame(inlink)) < 0)
00343 return ret;
00344 val = ff_poll_frame(inlink);
00345 }
00346 av_assert0(tinterlace->next);
00347
00348 return val;
00349 }
00350
00351 static int request_frame(AVFilterLink *outlink)
00352 {
00353 TInterlaceContext *tinterlace = outlink->src->priv;
00354 AVFilterLink *inlink = outlink->src->inputs[0];
00355
00356 do {
00357 int ret;
00358
00359 if ((ret = ff_request_frame(inlink)) < 0)
00360 return ret;
00361 } while (!tinterlace->cur);
00362
00363 return 0;
00364 }
00365
00366 static int null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) { return 0; }
00367
00368 AVFilter avfilter_vf_tinterlace = {
00369 .name = "tinterlace",
00370 .description = NULL_IF_CONFIG_SMALL("Perform temporal field interlacing."),
00371 .priv_size = sizeof(TInterlaceContext),
00372 .init = init,
00373 .uninit = uninit,
00374 .query_formats = query_formats,
00375
00376 .inputs = (const AVFilterPad[]) {
00377 { .name = "default",
00378 .type = AVMEDIA_TYPE_VIDEO,
00379 .start_frame = start_frame,
00380 .draw_slice = null_draw_slice,
00381 .end_frame = end_frame, },
00382 { .name = NULL}
00383 },
00384 .outputs = (const AVFilterPad[]) {
00385 { .name = "default",
00386 .type = AVMEDIA_TYPE_VIDEO,
00387 .config_props = config_out_props,
00388 .poll_frame = poll_frame,
00389 .request_frame = request_frame },
00390 { .name = NULL}
00391 },
00392 };