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"
28 } SeparateFieldsContext
;
30 static int config_props_output(AVFilterLink
*outlink
)
32 AVFilterContext
*ctx
= outlink
->src
;
33 SeparateFieldsContext
*sf
= ctx
->priv
;
34 AVFilterLink
*inlink
= ctx
->inputs
[0];
36 sf
->nb_planes
= av_pix_fmt_count_planes(inlink
->format
);
39 av_log(ctx
, AV_LOG_ERROR
, "height must be even\n");
40 return AVERROR_INVALIDDATA
;
43 outlink
->time_base
.num
= inlink
->time_base
.num
;
44 outlink
->time_base
.den
= inlink
->time_base
.den
* 2;
45 outlink
->frame_rate
.num
= inlink
->frame_rate
.num
* 2;
46 outlink
->frame_rate
.den
= inlink
->frame_rate
.den
;
47 outlink
->w
= inlink
->w
;
48 outlink
->h
= inlink
->h
/ 2;
53 static void extract_field(AVFrame
*frame
, int nb_planes
, int type
)
57 for (i
= 0; i
< nb_planes
; i
++) {
59 frame
->data
[i
] = frame
->data
[i
] + frame
->linesize
[i
];
60 frame
->linesize
[i
] *= 2;
64 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*inpicref
)
66 AVFilterContext
*ctx
= inlink
->dst
;
67 SeparateFieldsContext
*sf
= ctx
->priv
;
68 AVFilterLink
*outlink
= ctx
->outputs
[0];
71 inpicref
->height
= outlink
->h
;
72 inpicref
->interlaced_frame
= 0;
77 AVFrame
*second
= sf
->second
;
79 extract_field(second
, sf
->nb_planes
, second
->top_field_first
);
81 if (second
->pts
!= AV_NOPTS_VALUE
&&
82 inpicref
->pts
!= AV_NOPTS_VALUE
)
83 second
->pts
+= inpicref
->pts
;
85 second
->pts
= AV_NOPTS_VALUE
;
87 ret
= ff_filter_frame(outlink
, second
);
91 sf
->second
= av_frame_clone(inpicref
);
93 return AVERROR(ENOMEM
);
96 extract_field(inpicref
, sf
->nb_planes
, !inpicref
->top_field_first
);
98 if (inpicref
->pts
!= AV_NOPTS_VALUE
)
101 return ff_filter_frame(outlink
, inpicref
);
104 static int request_frame(AVFilterLink
*outlink
)
106 AVFilterContext
*ctx
= outlink
->src
;
107 SeparateFieldsContext
*sf
= ctx
->priv
;
110 ret
= ff_request_frame(ctx
->inputs
[0]);
111 if (ret
== AVERROR_EOF
&& sf
->second
) {
112 sf
->second
->pts
*= 2;
113 extract_field(sf
->second
, sf
->nb_planes
, sf
->second
->top_field_first
);
114 ret
= ff_filter_frame(outlink
, sf
->second
);
121 static const AVFilterPad separatefields_inputs
[] = {
124 .type
= AVMEDIA_TYPE_VIDEO
,
125 .filter_frame
= filter_frame
,
130 static const AVFilterPad separatefields_outputs
[] = {
133 .type
= AVMEDIA_TYPE_VIDEO
,
134 .config_props
= config_props_output
,
135 .request_frame
= request_frame
,
140 AVFilter ff_vf_separatefields
= {
141 .name
= "separatefields",
142 .description
= NULL_IF_CONFIG_SMALL("Split input video frames into fields."),
143 .priv_size
= sizeof(SeparateFieldsContext
),
144 .inputs
= separatefields_inputs
,
145 .outputs
= separatefields_outputs
,