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