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