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 PixelFormat pix_fmt;
00075 int ret;
00076
00079 if (ctx->inputs[0]) {
00080 formats = NULL;
00081 for (pix_fmt = 0; pix_fmt < PIX_FMT_NB; pix_fmt++)
00082 if (!( av_pix_fmt_descriptors[pix_fmt].flags & PIX_FMT_HWACCEL
00083 || av_pix_fmt_descriptors[pix_fmt].flags & PIX_FMT_BITSTREAM)
00084 && av_pix_fmt_descriptors[pix_fmt].nb_components
00085 && !av_pix_fmt_descriptors[pix_fmt].log2_chroma_h
00086 && (ret = ff_add_format(&formats, pix_fmt)) < 0) {
00087 ff_formats_unref(&formats);
00088 return ret;
00089 }
00090 ff_formats_ref(formats, &ctx->inputs[0]->out_formats);
00091 ff_formats_ref(formats, &ctx->outputs[0]->in_formats);
00092 }
00093
00094 return 0;
00095 }
00096
00097 static int config_input(AVFilterLink *inlink)
00098 {
00099 AVFilterContext *ctx = inlink->dst;
00100 FieldOrderContext *fieldorder = ctx->priv;
00101 int plane;
00102
00105 for (plane = 0; plane < 4; plane++) {
00106 fieldorder->line_size[plane] = av_image_get_linesize(
00107 inlink->format,
00108 inlink->w,
00109 plane);
00110 }
00111
00112 return 0;
00113 }
00114
00115 static AVFilterBufferRef *get_video_buffer(AVFilterLink *inlink, int perms, int w, int h)
00116 {
00117 AVFilterContext *ctx = inlink->dst;
00118 AVFilterLink *outlink = ctx->outputs[0];
00119
00120 return ff_get_video_buffer(outlink, perms, w, h);
00121 }
00122
00123 static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
00124 {
00125 AVFilterContext *ctx = inlink->dst;
00126 AVFilterLink *outlink = ctx->outputs[0];
00127
00128 AVFilterBufferRef *outpicref, *for_next_filter;
00129 int ret = 0;
00130
00131 outpicref = avfilter_ref_buffer(inpicref, ~0);
00132 if (!outpicref)
00133 return AVERROR(ENOMEM);
00134
00135 for_next_filter = avfilter_ref_buffer(outpicref, ~0);
00136 if (!for_next_filter) {
00137 avfilter_unref_bufferp(&outpicref);
00138 return AVERROR(ENOMEM);
00139 }
00140
00141 ret = ff_start_frame(outlink, for_next_filter);
00142 if (ret < 0) {
00143 avfilter_unref_bufferp(&outpicref);
00144 return ret;
00145 }
00146
00147 outlink->out_buf = outpicref;
00148 return 0;
00149 }
00150
00151 static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
00152 {
00153 AVFilterContext *ctx = inlink->dst;
00154 FieldOrderContext *fieldorder = ctx->priv;
00155 AVFilterLink *outlink = ctx->outputs[0];
00156
00157 AVFilterBufferRef *inpicref = inlink->cur_buf;
00158
00163 if ( !inpicref->video->interlaced
00164 || inpicref->video->top_field_first == fieldorder->dst_tff) {
00165 return ff_draw_slice(outlink, y, h, slice_dir);
00166 }
00167 return 0;
00168 }
00169
00170 static int end_frame(AVFilterLink *inlink)
00171 {
00172 AVFilterContext *ctx = inlink->dst;
00173 FieldOrderContext *fieldorder = ctx->priv;
00174 AVFilterLink *outlink = ctx->outputs[0];
00175
00176 AVFilterBufferRef *inpicref = inlink->cur_buf;
00177 AVFilterBufferRef *outpicref = outlink->out_buf;
00178
00179 int h, plane, line_step, line_size, line;
00180 uint8_t *cpy_src, *cpy_dst;
00181
00182 if ( inpicref->video->interlaced
00183 && inpicref->video->top_field_first != fieldorder->dst_tff) {
00184 av_dlog(ctx,
00185 "picture will move %s one line\n",
00186 fieldorder->dst_tff ? "up" : "down");
00187 h = inpicref->video->h;
00188 for (plane = 0; plane < 4 && inpicref->data[plane]; plane++) {
00189 line_step = inpicref->linesize[plane];
00190 line_size = fieldorder->line_size[plane];
00191 cpy_src = inpicref->data[plane];
00192 cpy_dst = outpicref->data[plane];
00193 if (fieldorder->dst_tff) {
00199 for (line = 0; line < h; line++) {
00200 if (1 + line < outpicref->video->h) {
00201 memcpy(cpy_dst, cpy_src + line_step, line_size);
00202 } else {
00203 memcpy(cpy_dst, cpy_src - line_step - line_step, line_size);
00204 }
00205 cpy_src += line_step;
00206 cpy_dst += line_step;
00207 }
00208 } else {
00214 cpy_src += (h - 1) * line_step;
00215 cpy_dst += (h - 1) * line_step;
00216 for (line = h - 1; line >= 0 ; line--) {
00217 if (line > 0) {
00218 memcpy(cpy_dst, cpy_src - line_step, line_size);
00219 } else {
00220 memcpy(cpy_dst, cpy_src + line_step + line_step, line_size);
00221 }
00222 cpy_src -= line_step;
00223 cpy_dst -= line_step;
00224 }
00225 }
00226 }
00227 outpicref->video->top_field_first = fieldorder->dst_tff;
00228 ff_draw_slice(outlink, 0, h, 1);
00229 } else {
00230 av_dlog(ctx,
00231 "not interlaced or field order already correct\n");
00232 }
00233
00234 return ff_end_frame(outlink);
00235 }
00236
00237 AVFilter avfilter_vf_fieldorder = {
00238 .name = "fieldorder",
00239 .description = NULL_IF_CONFIG_SMALL("Set the field order."),
00240 .init = init,
00241 .priv_size = sizeof(FieldOrderContext),
00242 .query_formats = query_formats,
00243 .inputs = (const AVFilterPad[]) {{ .name = "default",
00244 .type = AVMEDIA_TYPE_VIDEO,
00245 .config_props = config_input,
00246 .start_frame = start_frame,
00247 .get_video_buffer = get_video_buffer,
00248 .draw_slice = draw_slice,
00249 .end_frame = end_frame,
00250 .min_perms = AV_PERM_READ | AV_PERM_PRESERVE },
00251 { .name = NULL}},
00252 .outputs = (const AVFilterPad[]) {{ .name = "default",
00253 .type = AVMEDIA_TYPE_VIDEO, },
00254 { .name = NULL}},
00255 };