00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00027 #include "libavutil/opt.h"
00028 #include "libavutil/pixdesc.h"
00029 #include "avfilter.h"
00030 #include "internal.h"
00031
00032 enum FieldType { FIELD_TYPE_TOP = 0, FIELD_TYPE_BOTTOM };
00033
00034 typedef struct {
00035 const AVClass *class;
00036 enum FieldType type;
00037 int nb_planes;
00038 } FieldContext;
00039
00040 #define OFFSET(x) offsetof(FieldContext, x)
00041 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
00042
00043 static const AVOption field_options[] = {
00044 {"type", "set field type (top or bottom)", OFFSET(type), AV_OPT_TYPE_INT, {.i64=FIELD_TYPE_TOP}, 0, 1, FLAGS, "field_type" },
00045 {"top", "select top field", 0, AV_OPT_TYPE_CONST, {.i64=FIELD_TYPE_TOP}, INT_MIN, INT_MAX, FLAGS, "field_type"},
00046 {"bottom", "select bottom field", 0, AV_OPT_TYPE_CONST, {.i64=FIELD_TYPE_BOTTOM}, INT_MIN, INT_MAX, FLAGS, "field_type"},
00047
00048 {NULL}
00049 };
00050
00051 AVFILTER_DEFINE_CLASS(field);
00052
00053 static av_cold int init(AVFilterContext *ctx, const char *args)
00054 {
00055 FieldContext *field = ctx->priv;
00056 static const char *shorthand[] = { "type", NULL };
00057
00058 field->class = &field_class;
00059 av_opt_set_defaults(field);
00060
00061 return av_opt_set_from_string(field, args, shorthand, "=", ":");
00062 }
00063
00064 static int config_props_output(AVFilterLink *outlink)
00065 {
00066 AVFilterContext *ctx = outlink->src;
00067 FieldContext *field = ctx->priv;
00068 AVFilterLink *inlink = ctx->inputs[0];
00069 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
00070 int i;
00071
00072 for (i = 0; i < desc->nb_components; i++)
00073 field->nb_planes = FFMAX(field->nb_planes, desc->comp[i].plane);
00074 field->nb_planes++;
00075
00076 outlink->w = inlink->w;
00077 outlink->h = (inlink->h + (field->type == FIELD_TYPE_TOP)) / 2;
00078
00079 av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d type:%s -> w:%d h:%d\n",
00080 inlink->w, inlink->h, field->type == FIELD_TYPE_BOTTOM ? "bottom" : "top",
00081 outlink->w, outlink->h);
00082 return 0;
00083 }
00084
00085 static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
00086 {
00087 FieldContext *field = inlink->dst->priv;
00088 AVFilterLink *outlink = inlink->dst->outputs[0];
00089 int i;
00090
00091 inpicref->video->h = outlink->h;
00092 inpicref->video->interlaced = 0;
00093
00094 for (i = 0; i < field->nb_planes; i++) {
00095 if (field->type == FIELD_TYPE_BOTTOM)
00096 inpicref->data[i] = inpicref->data[i] + inpicref->linesize[i];
00097 inpicref->linesize[i] = 2 * inpicref->linesize[i];
00098 }
00099 return ff_filter_frame(outlink, inpicref);
00100 }
00101
00102 static const AVFilterPad field_inputs[] = {
00103 {
00104 .name = "default",
00105 .type = AVMEDIA_TYPE_VIDEO,
00106 .get_video_buffer = ff_null_get_video_buffer,
00107 .filter_frame = filter_frame,
00108 },
00109 { NULL }
00110 };
00111
00112 static const AVFilterPad field_outputs[] = {
00113 {
00114 .name = "default",
00115 .type = AVMEDIA_TYPE_VIDEO,
00116 .config_props = config_props_output,
00117 },
00118 { NULL }
00119 };
00120
00121 AVFilter avfilter_vf_field = {
00122 .name = "field",
00123 .description = NULL_IF_CONFIG_SMALL("Extract a field from the input video."),
00124
00125 .priv_size = sizeof(FieldContext),
00126 .init = init,
00127
00128 .inputs = field_inputs,
00129 .outputs = field_outputs,
00130 .priv_class = &field_class,
00131 };