2 * Copyright (c) 2013 Paul B Mahol
4 * This file is part of FFmpeg.
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.
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.
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
21 #include "libavutil/pixdesc.h"
26 typedef struct SeparateFieldsContext
{
29 } SeparateFieldsContext
;
31 static int config_props_output(AVFilterLink
*outlink
)
33 AVFilterContext
*ctx
= outlink
->src
;
34 SeparateFieldsContext
*s
= ctx
->priv
;
35 AVFilterLink
*inlink
= ctx
->inputs
[0];
36 FilterLink
*il
= ff_filter_link(inlink
);
37 FilterLink
*ol
= ff_filter_link(outlink
);
39 s
->nb_planes
= av_pix_fmt_count_planes(inlink
->format
);
42 av_log(ctx
, AV_LOG_ERROR
, "height must be even\n");
43 return AVERROR_INVALIDDATA
;
46 outlink
->time_base
.num
= inlink
->time_base
.num
;
47 outlink
->time_base
.den
= inlink
->time_base
.den
* 2;
48 ol
->frame_rate
.num
= il
->frame_rate
.num
* 2;
49 ol
->frame_rate
.den
= il
->frame_rate
.den
;
50 outlink
->w
= inlink
->w
;
51 outlink
->h
= inlink
->h
/ 2;
56 static void extract_field(AVFrame
*frame
, int nb_planes
, int type
)
60 for (i
= 0; i
< nb_planes
; i
++) {
62 frame
->data
[i
] = frame
->data
[i
] + frame
->linesize
[i
];
63 frame
->linesize
[i
] *= 2;
67 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*inpicref
)
69 AVFilterContext
*ctx
= inlink
->dst
;
70 SeparateFieldsContext
*s
= ctx
->priv
;
71 AVFilterLink
*outlink
= ctx
->outputs
[0];
74 inpicref
->height
= outlink
->h
;
75 #if FF_API_INTERLACED_FRAME
76 FF_DISABLE_DEPRECATION_WARNINGS
77 inpicref
->interlaced_frame
= 0;
78 FF_ENABLE_DEPRECATION_WARNINGS
80 inpicref
->flags
&= ~AV_FRAME_FLAG_INTERLACED
;
85 AVFrame
*second
= s
->second
;
87 extract_field(second
, s
->nb_planes
, !!(second
->flags
& AV_FRAME_FLAG_TOP_FIELD_FIRST
));
89 if (second
->pts
!= AV_NOPTS_VALUE
&&
90 inpicref
->pts
!= AV_NOPTS_VALUE
)
91 second
->pts
+= inpicref
->pts
;
93 second
->pts
= AV_NOPTS_VALUE
;
95 ret
= ff_filter_frame(outlink
, second
);
99 s
->second
= av_frame_clone(inpicref
);
101 return AVERROR(ENOMEM
);
104 extract_field(inpicref
, s
->nb_planes
, !(inpicref
->flags
& AV_FRAME_FLAG_TOP_FIELD_FIRST
));
106 if (inpicref
->pts
!= AV_NOPTS_VALUE
)
109 return ff_filter_frame(outlink
, inpicref
);
112 static int flush_frame(AVFilterLink
*outlink
, int64_t pts
, int64_t *out_pts
)
114 AVFilterContext
*ctx
= outlink
->src
;
115 SeparateFieldsContext
*s
= ctx
->priv
;
119 *out_pts
= s
->second
->pts
+= pts
;
120 extract_field(s
->second
, s
->nb_planes
, !!(s
->second
->flags
& AV_FRAME_FLAG_TOP_FIELD_FIRST
));
121 ret
= ff_filter_frame(outlink
, s
->second
);
128 static int activate(AVFilterContext
*ctx
)
130 AVFilterLink
*inlink
= ctx
->inputs
[0];
131 AVFilterLink
*outlink
= ctx
->outputs
[0];
136 FF_FILTER_FORWARD_STATUS_BACK(outlink
, inlink
);
138 ret
= ff_inlink_consume_frame(inlink
, &in
);
142 return filter_frame(inlink
, in
);
144 if (ff_inlink_acknowledge_status(inlink
, &status
, &pts
)) {
145 if (status
== AVERROR_EOF
) {
146 int64_t out_pts
= pts
;
148 ret
= flush_frame(outlink
, pts
, &out_pts
);
149 ff_outlink_set_status(outlink
, status
, out_pts
);
154 FF_FILTER_FORWARD_WANTED(outlink
, inlink
);
156 return FFERROR_NOT_READY
;
159 static av_cold
void uninit(AVFilterContext
*ctx
)
161 SeparateFieldsContext
*s
= ctx
->priv
;
163 av_frame_free(&s
->second
);
166 static const AVFilterPad separatefields_outputs
[] = {
169 .type
= AVMEDIA_TYPE_VIDEO
,
170 .config_props
= config_props_output
,
174 const FFFilter ff_vf_separatefields
= {
175 .p
.name
= "separatefields",
176 .p
.description
= NULL_IF_CONFIG_SMALL("Split input video frames into fields."),
177 .priv_size
= sizeof(SeparateFieldsContext
),
178 .activate
= activate
,
180 FILTER_INPUTS(ff_video_default_filterpad
),
181 FILTER_OUTPUTS(separatefields_outputs
),