History

lavfi: add fieldorder filter

Mark Himsley committed 15 years ago

Commit 2f84bb41 parent 68e23c06 files · +272 −1Browse files

Unified · Split

6 files
  1. Changelog +1 −0
  2. doc/filters.texi +33 −0
  3. libavfilter/Makefile +1 −0
  4. libavfilter/allfilters.c +1 −0
  5. libavfilter/avfilter.h +1 −1
  6. libavfilter/vf_fieldorder.c +235 −0
Changelog+1−0
@@ -90,6 +90,7 @@ version 0.7_beta1: · 89 unmodified lines
90- AAC encoding via libvo-aacenc90- AAC encoding via libvo-aacenc
91- AMR-WB encoding via libvo-amrwbenc91- AMR-WB encoding via libvo-amrwbenc
92- xWMA demuxer92- xWMA demuxer
93- fieldorder video filter added
93 94
94 95
95version 0.6:96version 0.6:
doc/filters.texi+33−0
@@ -386,6 +386,39 @@ fade=in:0:25, fade=out:975:25 · 385 unmodified lines
386fade=in:5:20386fade=in:5:20
387@end example387@end example
388 388
389@section fieldorder
390
391Transform the field order of the input video.
392
393It accepts one parameter which specifies the required field order that
394the input interlaced video will be transformed to. The parameter can
395assume one of the following values:
396
397@table @option
398@item 0 or bff
399output bottom field first
400@item 1 or tff
401output top field first
402@end table
403
404Default value is "tff".
405
406Transformation is achieved by shifting the picture content up or down
407by one line, and filling the remaining line with appropriate picture content.
408This method is consistent with most broadcast field order converters.
409
410If the input video is not flagged as being interlaced, or it is already
411flagged as being of the required output field order then this filter does
412not alter the incoming video.
413
414This filter is very useful when converting to or from PAL DV material,
415which is bottom field first.
416
417For example:
418@example
419./ffmpeg -i in.vob -vf "fieldorder=bff" out.dv
420@end example
421
389@section fifo422@section fifo
390 423
391Buffer input images and send them when they are requested.424Buffer input images and send them when they are requested.
libavfilter/Makefile+1−0
@@ -27,6 +27,7 @@ OBJS-$(CONFIG_CROP_FILTER) += vf_crop.o · 26 unmodified lines
27OBJS-$(CONFIG_CROPDETECT_FILTER) += vf_cropdetect.o27OBJS-$(CONFIG_CROPDETECT_FILTER) += vf_cropdetect.o
28OBJS-$(CONFIG_DRAWBOX_FILTER) += vf_drawbox.o28OBJS-$(CONFIG_DRAWBOX_FILTER) += vf_drawbox.o
29OBJS-$(CONFIG_FADE_FILTER) += vf_fade.o29OBJS-$(CONFIG_FADE_FILTER) += vf_fade.o
30OBJS-$(CONFIG_FIELDORDER_FILTER) += vf_fieldorder.o
30OBJS-$(CONFIG_FIFO_FILTER) += vf_fifo.o31OBJS-$(CONFIG_FIFO_FILTER) += vf_fifo.o
31OBJS-$(CONFIG_FORMAT_FILTER) += vf_format.o32OBJS-$(CONFIG_FORMAT_FILTER) += vf_format.o
32OBJS-$(CONFIG_FREI0R_FILTER) += vf_frei0r.o33OBJS-$(CONFIG_FREI0R_FILTER) += vf_frei0r.o
libavfilter/allfilters.c+1−0
@@ -46,6 +46,7 @@ void avfilter_register_all(void) · 45 unmodified lines
46 REGISTER_FILTER (CROPDETECT, cropdetect, vf);46 REGISTER_FILTER (CROPDETECT, cropdetect, vf);
47 REGISTER_FILTER (DRAWBOX, drawbox, vf);47 REGISTER_FILTER (DRAWBOX, drawbox, vf);
48 REGISTER_FILTER (FADE, fade, vf);48 REGISTER_FILTER (FADE, fade, vf);
49 REGISTER_FILTER (FIELDORDER, fieldorder, vf);
49 REGISTER_FILTER (FIFO, fifo, vf);50 REGISTER_FILTER (FIFO, fifo, vf);
50 REGISTER_FILTER (FORMAT, format, vf);51 REGISTER_FILTER (FORMAT, format, vf);
51 REGISTER_FILTER (FREI0R, frei0r, vf);52 REGISTER_FILTER (FREI0R, frei0r, vf);
libavfilter/avfilter.h+1−1
@@ -26,7 +26,7 @@ · 25 unmodified lines
26#include "libavutil/samplefmt.h"26#include "libavutil/samplefmt.h"
27 27
28#define LIBAVFILTER_VERSION_MAJOR 228#define LIBAVFILTER_VERSION_MAJOR 2
29#define LIBAVFILTER_VERSION_MINOR 029#define LIBAVFILTER_VERSION_MINOR 1
30#define LIBAVFILTER_VERSION_MICRO 030#define LIBAVFILTER_VERSION_MICRO 0
31 31
32#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \32#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
libavfilter/vf_fieldorder.c+235−0
@@ -0,0 +1,235 @@
1/*
2 * Copyright (c) 2011 Mark Himsley
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21/**
22 * @file
23 * video field order filter, heavily influenced by vf_pad.c
24 */
25
26/* #define DEBUG */
27
28#include "libavutil/imgutils.h"
29#include "libavutil/pixdesc.h"
30#include "avfilter.h"
31
32typedef struct
33{
34 unsigned int dst_tff; ///< output bff/tff
35 int line_size[4]; ///< bytes of pixel data per line for each plane
36} FieldOrderContext;
37
38static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
39{
40 FieldOrderContext *fieldorder = ctx->priv;
41
42 const char *tff = "tff";
43 const char *bff = "bff";
44
45 if (!args) {
46 fieldorder->dst_tff = 1;
47 } else if (sscanf(args, "%u", &fieldorder->dst_tff) == 1) {
48 fieldorder->dst_tff = !!fieldorder->dst_tff;
49 } else if (!strcmp(tff, args)) {
50 fieldorder->dst_tff = 1;
51 } else if (!strcmp(bff, args)) {
52 fieldorder->dst_tff = 0;
53 } else {
54 av_log(ctx, AV_LOG_ERROR, "Invalid argument '%s'.\n", args);
55 return AVERROR(EINVAL);
56 }
57
58 av_log(ctx, AV_LOG_INFO, "output field order: %s\n",
59 fieldorder->dst_tff ? tff : bff);
60
61 return 0;
62}
63
64static int query_formats(AVFilterContext *ctx)
65{
66 AVFilterFormats *formats;
67 enum PixelFormat pix_fmt;
68 int ret;
69
70 /** accept any input pixel format that is not hardware accelerated, not
71 * a bitstream format, and does not have vertically sub-sampled chroma */
72 if (ctx->inputs[0]) {
73 formats = NULL;
74 for (pix_fmt = 0; pix_fmt < PIX_FMT_NB; pix_fmt++)
75 if (!( av_pix_fmt_descriptors[pix_fmt].flags & PIX_FMT_HWACCEL
76 || av_pix_fmt_descriptors[pix_fmt].flags & PIX_FMT_BITSTREAM)
77 && av_pix_fmt_descriptors[pix_fmt].nb_components
78 && !av_pix_fmt_descriptors[pix_fmt].log2_chroma_h
79 && (ret = avfilter_add_format(&formats, pix_fmt)) < 0) {
80 avfilter_formats_unref(&formats);
81 return ret;
82 }
83 avfilter_formats_ref(formats, &ctx->inputs[0]->out_formats);
84 avfilter_formats_ref(formats, &ctx->outputs[0]->in_formats);
85 }
86
87 return 0;
88}
89
90static int config_input(AVFilterLink *inlink)
91{
92 AVFilterContext *ctx = inlink->dst;
93 FieldOrderContext *fieldorder = ctx->priv;
94 int plane;
95
96 /** full an array with the number of bytes that the video
97 * data occupies per line for each plane of the input video */
98 for (plane = 0; plane < 4; plane++) {
99 fieldorder->line_size[plane] = av_image_get_linesize(
100 inlink->format,
101 inlink->w,
102 plane);
103 }
104
105 return 0;
106}
107
108static AVFilterBufferRef *get_video_buffer(AVFilterLink *inlink, int perms, int w, int h)
109{
110 AVFilterContext *ctx = inlink->dst;
111 AVFilterLink *outlink = ctx->outputs[0];
112
113 return avfilter_get_video_buffer(outlink, perms, w, h);
114}
115
116static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
117{
118 AVFilterContext *ctx = inlink->dst;
119 AVFilterLink *outlink = ctx->outputs[0];
120
121 AVFilterBufferRef *outpicref;
122
123 outpicref = avfilter_ref_buffer(inpicref, ~0);
124 outlink->out_buf = outpicref;
125
126 avfilter_start_frame(outlink, outpicref);
127}
128
129static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
130{
131 AVFilterContext *ctx = inlink->dst;
132 FieldOrderContext *fieldorder = ctx->priv;
133 AVFilterLink *outlink = ctx->outputs[0];
134
135 AVFilterBufferRef *inpicref = inlink->cur_buf;
136
137 /** can only currently do slices if this filter is doing nothing
138 * because this filter is moving picture content, the output
139 * slice will contain different video lines than the input slice
140 * and that complexity will be added later */
141 if ( !inpicref->video->interlaced
142 || inpicref->video->top_field_first == fieldorder->dst_tff) {
143 avfilter_draw_slice(outlink, y, h, slice_dir);
144 }
145}
146
147static void end_frame(AVFilterLink *inlink)
148{
149 AVFilterContext *ctx = inlink->dst;
150 FieldOrderContext *fieldorder = ctx->priv;
151 AVFilterLink *outlink = ctx->outputs[0];
152
153 AVFilterBufferRef *inpicref = inlink->cur_buf;
154 AVFilterBufferRef *outpicref = outlink->out_buf;
155
156 int h, w, plane, line_step, line_size, line;
157 uint8_t *cpy_src, *cpy_dst;
158
159 if ( inpicref->video->interlaced
160 && inpicref->video->top_field_first != fieldorder->dst_tff) {
161 av_dlog(ctx,
162 "picture will move %s one line\n",
163 fieldorder->dst_tff ? "up" : "down");
164 h = inpicref->video->h;
165 w = inpicref->video->w;
166 for (plane = 0; plane < 4 && inpicref->data[plane]; plane++) {
167 line_step = inpicref->linesize[plane];
168 line_size = fieldorder->line_size[plane];
169 cpy_src = inpicref->data[plane];
170 cpy_dst = outpicref->data[plane];
171 if (fieldorder->dst_tff) {
172 /** Move every line up one line, working from
173 * the top to the bottom of the frame.
174 * The original top line is lost.
175 * The new last line is created as a copy of the
176 * penultimate line from that field. */
177 for (line = 0; line < h; line++) {
178 if (1 + line < outpicref->video->h) {
179 memcpy(cpy_dst, cpy_src + line_step, line_size);
180 } else {
181 memcpy(cpy_dst, cpy_src - line_step - line_step, line_size);
182 }
183 cpy_src += line_step;
184 cpy_dst += line_step;
185 }
186 } else {
187 /** Move every line down one line, working from
188 * the bottom to the top of the frame.
189 * The original bottom line is lost.
190 * The new first line is created as a copy of the
191 * second line from that field. */
192 cpy_src += (h - 1) * line_step;
193 cpy_dst += (h - 1) * line_step;
194 for (line = h - 1; line >= 0 ; line--) {
195 if (line > 0) {
196 memcpy(cpy_dst, cpy_src - line_step, line_size);
197 } else {
198 memcpy(cpy_dst, cpy_src + line_step + line_step, line_size);
199 }
200 cpy_src -= line_step;
201 cpy_dst -= line_step;
202 }
203 }
204 }
205 outpicref->video->top_field_first = fieldorder->dst_tff;
206 avfilter_draw_slice(outlink, 0, h, 1);
207 } else {
208 av_dlog(ctx,
209 "not interlaced or field order already correct\n");
210 }
211
212 avfilter_end_frame(outlink);
213 avfilter_unref_buffer(inpicref);
214}
215
216AVFilter avfilter_vf_fieldorder = {
217 .name = "fieldorder",
218 .description = NULL_IF_CONFIG_SMALL("Set the field order."),
219 .init = init,
220 .priv_size = sizeof(FieldOrderContext),
221 .query_formats = query_formats,
222 .inputs = (AVFilterPad[]) {{ .name = "default",
223 .type = AVMEDIA_TYPE_VIDEO,
224 .config_props = config_input,
225 .start_frame = start_frame,
226 .get_video_buffer = get_video_buffer,
227 .draw_slice = draw_slice,
228 .end_frame = end_frame,
229 .min_perms = AV_PERM_READ,
230 .rej_perms = AV_PERM_REUSE2|AV_PERM_PRESERVE,},
231 { .name = NULL}},
232 .outputs = (AVFilterPad[]) {{ .name = "default",
233 .type = AVMEDIA_TYPE_VIDEO, },
234 { .name = NULL}},
235};

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t