00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00026
00027
00028 #include <stdio.h>
00029 #include <string.h>
00030
00031 #include "libavutil/imgutils.h"
00032 #include "libavutil/internal.h"
00033 #include "libavutil/pixdesc.h"
00034 #include "avfilter.h"
00035 #include "formats.h"
00036 #include "internal.h"
00037 #include "video.h"
00038
00039 typedef struct
00040 {
00041 unsigned int dst_tff;
00042 int line_size[4];
00043 } FieldOrderContext;
00044
00045 static av_cold int init(AVFilterContext *ctx, const char *args)
00046 {
00047 FieldOrderContext *fieldorder = ctx->priv;
00048
00049 const char *tff = "tff";
00050 const char *bff = "bff";
00051
00052 if (!args) {
00053 fieldorder->dst_tff = 1;
00054 } else if (sscanf(args, "%u", &fieldorder->dst_tff) == 1) {
00055 fieldorder->dst_tff = !!fieldorder->dst_tff;
00056 } else if (!strcmp(tff, args)) {
00057 fieldorder->dst_tff = 1;
00058 } else if (!strcmp(bff, args)) {
00059 fieldorder->dst_tff = 0;
00060 } else {
00061 av_log(ctx, AV_LOG_ERROR, "Invalid argument '%s'.\n", args);
00062 return AVERROR(EINVAL);
00063 }
00064
00065 av_log(ctx, AV_LOG_VERBOSE, "output field order: %s\n",
00066 fieldorder->dst_tff ? tff : bff);
00067
00068 return 0;
00069 }
00070
00071 static int query_formats(AVFilterContext *ctx)
00072 {
00073 AVFilterFormats *formats;
00074 enum AVPixelFormat pix_fmt;
00075 int ret;
00076
00079 if (ctx->inputs[0]) {
00080 formats = NULL;
00081 for (pix_fmt = 0; pix_fmt < AV_PIX_FMT_NB; pix_fmt++) {
00082 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
00083 if (!(desc->flags & PIX_FMT_HWACCEL ||
00084 desc->flags & PIX_FMT_BITSTREAM) &&
00085 desc->nb_components && !desc->log2_chroma_h &&
00086 (ret = ff_add_format(&formats, pix_fmt)) < 0) {
00087 ff_formats_unref(&formats);
00088 return ret;
00089 }
00090 }
00091 ff_formats_ref(formats, &ctx->inputs[0]->out_formats);
00092 ff_formats_ref(formats, &ctx->outputs[0]->in_formats);
00093 }
00094
00095 return 0;
00096 }
00097
00098 static int config_input(AVFilterLink *inlink)
00099 {
00100 AVFilterContext *ctx = inlink->dst;
00101 FieldOrderContext *fieldorder = ctx->priv;
00102 int plane;
00103
00106 for (plane = 0; plane < 4; plane++) {
00107 fieldorder->line_size[plane] = av_image_get_linesize(
00108 inlink->format,
00109 inlink->w,
00110 plane);
00111 }
00112
00113 return 0;
00114 }
00115
00116 static AVFilterBufferRef *get_video_buffer(AVFilterLink *inlink, int perms, int w, int h)
00117 {
00118 AVFilterContext *ctx = inlink->dst;
00119 AVFilterLink *outlink = ctx->outputs[0];
00120
00121 return ff_get_video_buffer(outlink, perms, w, h);
00122 }
00123
00124 static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
00125 {
00126 AVFilterContext *ctx = inlink->dst;
00127 FieldOrderContext *s = ctx->priv;
00128 AVFilterLink *outlink = ctx->outputs[0];
00129 int h, plane, line_step, line_size, line;
00130 uint8_t *data;
00131
00132 if (!frame->video->interlaced ||
00133 frame->video->top_field_first == s->dst_tff)
00134 return ff_filter_frame(outlink, frame);
00135
00136 av_dlog(ctx,
00137 "picture will move %s one line\n",
00138 s->dst_tff ? "up" : "down");
00139 h = frame->video->h;
00140 for (plane = 0; plane < 4 && frame->data[plane]; plane++) {
00141 line_step = frame->linesize[plane];
00142 line_size = s->line_size[plane];
00143 data = frame->data[plane];
00144 if (s->dst_tff) {
00150 for (line = 0; line < h; line++) {
00151 if (1 + line < frame->video->h) {
00152 memcpy(data, data + line_step, line_size);
00153 } else {
00154 memcpy(data, data - line_step - line_step, line_size);
00155 }
00156 data += line_step;
00157 }
00158 } else {
00164 data += (h - 1) * line_step;
00165 for (line = h - 1; line >= 0 ; line--) {
00166 if (line > 0) {
00167 memcpy(data, data - line_step, line_size);
00168 } else {
00169 memcpy(data, data + line_step + line_step, line_size);
00170 }
00171 data -= line_step;
00172 }
00173 }
00174 }
00175 frame->video->top_field_first = s->dst_tff;
00176
00177 return ff_filter_frame(outlink, frame);
00178 }
00179
00180 static const AVFilterPad avfilter_vf_fieldorder_inputs[] = {
00181 {
00182 .name = "default",
00183 .type = AVMEDIA_TYPE_VIDEO,
00184 .config_props = config_input,
00185 .get_video_buffer = get_video_buffer,
00186 .filter_frame = filter_frame,
00187 .min_perms = AV_PERM_READ | AV_PERM_WRITE,
00188 },
00189 { NULL }
00190 };
00191
00192 static const AVFilterPad avfilter_vf_fieldorder_outputs[] = {
00193 {
00194 .name = "default",
00195 .type = AVMEDIA_TYPE_VIDEO,
00196 },
00197 { NULL }
00198 };
00199
00200 AVFilter avfilter_vf_fieldorder = {
00201 .name = "fieldorder",
00202 .description = NULL_IF_CONFIG_SMALL("Set the field order."),
00203 .init = init,
00204 .priv_size = sizeof(FieldOrderContext),
00205 .query_formats = query_formats,
00206 .inputs = avfilter_vf_fieldorder_inputs,
00207 .outputs = avfilter_vf_fieldorder_outputs,
00208 };