2 * Copyright (c) 2011 Mark Himsley
4 * This file is part of Libav.
6 * Libav 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.
11 * Libav 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.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with Libav; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * video field order filter, heavily influenced by vf_pad.c
31 #include "libavutil/imgutils.h"
32 #include "libavutil/internal.h"
33 #include "libavutil/pixdesc.h"
41 unsigned int dst_tff
; ///< output bff/tff
42 int line_size
[4]; ///< bytes of pixel data per line for each plane
45 static av_cold
int init(AVFilterContext
*ctx
, const char *args
)
47 FieldOrderContext
*fieldorder
= ctx
->priv
;
49 const char *tff
= "tff";
50 const char *bff
= "bff";
53 fieldorder
->dst_tff
= 1;
54 } else if (sscanf(args
, "%u", &fieldorder
->dst_tff
) == 1) {
55 fieldorder
->dst_tff
= !!fieldorder
->dst_tff
;
56 } else if (!strcmp(tff
, args
)) {
57 fieldorder
->dst_tff
= 1;
58 } else if (!strcmp(bff
, args
)) {
59 fieldorder
->dst_tff
= 0;
61 av_log(ctx
, AV_LOG_ERROR
, "Invalid argument '%s'.\n", args
);
62 return AVERROR(EINVAL
);
65 av_log(ctx
, AV_LOG_VERBOSE
, "output field order: %s\n",
66 fieldorder
->dst_tff
? tff
: bff
);
71 static int query_formats(AVFilterContext
*ctx
)
73 AVFilterFormats
*formats
;
74 enum AVPixelFormat pix_fmt
;
77 /** accept any input pixel format that is not hardware accelerated, not
78 * a bitstream format, and does not have vertically sub-sampled chroma */
81 for (pix_fmt
= 0; pix_fmt
< AV_PIX_FMT_NB
; pix_fmt
++) {
82 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(pix_fmt
);
83 if (!(desc
->flags
& PIX_FMT_HWACCEL
||
84 desc
->flags
& PIX_FMT_BITSTREAM
) &&
85 desc
->nb_components
&& !desc
->log2_chroma_h
&&
86 (ret
= ff_add_format(&formats
, pix_fmt
)) < 0) {
87 ff_formats_unref(&formats
);
91 ff_formats_ref(formats
, &ctx
->inputs
[0]->out_formats
);
92 ff_formats_ref(formats
, &ctx
->outputs
[0]->in_formats
);
98 static int config_input(AVFilterLink
*inlink
)
100 AVFilterContext
*ctx
= inlink
->dst
;
101 FieldOrderContext
*fieldorder
= ctx
->priv
;
104 /** full an array with the number of bytes that the video
105 * data occupies per line for each plane of the input video */
106 for (plane
= 0; plane
< 4; plane
++) {
107 fieldorder
->line_size
[plane
] = av_image_get_linesize(
116 static AVFrame
*get_video_buffer(AVFilterLink
*inlink
, int w
, int h
)
118 AVFilterContext
*ctx
= inlink
->dst
;
119 AVFilterLink
*outlink
= ctx
->outputs
[0];
121 return ff_get_video_buffer(outlink
, w
, h
);
124 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*frame
)
126 AVFilterContext
*ctx
= inlink
->dst
;
127 FieldOrderContext
*s
= ctx
->priv
;
128 AVFilterLink
*outlink
= ctx
->outputs
[0];
129 int h
, plane
, line_step
, line_size
, line
;
132 if (!frame
->interlaced_frame
||
133 frame
->top_field_first
== s
->dst_tff
)
134 return ff_filter_frame(outlink
, frame
);
137 "picture will move %s one line\n",
138 s
->dst_tff
? "up" : "down");
140 for (plane
= 0; plane
< 4 && frame
->data
[plane
]; plane
++) {
141 line_step
= frame
->linesize
[plane
];
142 line_size
= s
->line_size
[plane
];
143 data
= frame
->data
[plane
];
145 /** Move every line up one line, working from
146 * the top to the bottom of the frame.
147 * The original top line is lost.
148 * The new last line is created as a copy of the
149 * penultimate line from that field. */
150 for (line
= 0; line
< h
; line
++) {
151 if (1 + line
< frame
->height
) {
152 memcpy(data
, data
+ line_step
, line_size
);
154 memcpy(data
, data
- line_step
- line_step
, line_size
);
159 /** Move every line down one line, working from
160 * the bottom to the top of the frame.
161 * The original bottom line is lost.
162 * The new first line is created as a copy of the
163 * second line from that field. */
164 data
+= (h
- 1) * line_step
;
165 for (line
= h
- 1; line
>= 0 ; line
--) {
167 memcpy(data
, data
- line_step
, line_size
);
169 memcpy(data
, data
+ line_step
+ line_step
, line_size
);
175 frame
->top_field_first
= s
->dst_tff
;
177 return ff_filter_frame(outlink
, frame
);
180 static const AVFilterPad avfilter_vf_fieldorder_inputs
[] = {
183 .type
= AVMEDIA_TYPE_VIDEO
,
184 .config_props
= config_input
,
185 .get_video_buffer
= get_video_buffer
,
186 .filter_frame
= filter_frame
,
192 static const AVFilterPad avfilter_vf_fieldorder_outputs
[] = {
195 .type
= AVMEDIA_TYPE_VIDEO
,
200 AVFilter avfilter_vf_fieldorder
= {
201 .name
= "fieldorder",
202 .description
= NULL_IF_CONFIG_SMALL("Set the field order."),
204 .priv_size
= sizeof(FieldOrderContext
),
205 .query_formats
= query_formats
,
206 .inputs
= avfilter_vf_fieldorder_inputs
,
207 .outputs
= avfilter_vf_fieldorder_outputs
,