FFmpeg
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
Examples
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
libavfilter
vf_telecine.c
Go to the documentation of this file.
1
/*
2
* Copyright (c) 2012 Rudolf Polzer
3
* Copyright (c) 2013 Paul B Mahol
4
*
5
* This file is part of FFmpeg.
6
*
7
* FFmpeg is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Lesser General Public
9
* License as published by the Free Software Foundation; either
10
* version 2.1 of the License, or (at your option) any later version.
11
*
12
* FFmpeg is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
16
*
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with FFmpeg; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
*/
21
22
/**
23
* @file telecine filter, heavily based from mpv-player:TOOLS/vf_dlopen/telecine.c by
24
* Rudolf Polzer.
25
*/
26
27
#include "
libavutil/avstring.h
"
28
#include "
libavutil/imgutils.h
"
29
#include "
libavutil/opt.h
"
30
#include "
libavutil/pixdesc.h
"
31
#include "
avfilter.h
"
32
#include "
formats.h
"
33
#include "
internal.h
"
34
#include "
video.h
"
35
36
typedef
struct
{
37
const
AVClass
*
class
;
38
int
first_field
;
39
char
*
pattern
;
40
unsigned
int
pattern_pos
;
41
42
AVRational
pts
;
43
double
ts_unit
;
44
int
out_cnt
;
45
int
occupied
;
46
47
int
nb_planes
;
48
int
planeheight[4];
49
int
stride
[4];
50
51
AVFrame
*
frame
[5];
52
AVFrame
*
temp
;
53
}
TelecineContext
;
54
55
#define OFFSET(x) offsetof(TelecineContext, x)
56
#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
57
58
static
const
AVOption
telecine_options
[] = {
59
{
"first_field"
,
"select first field"
,
OFFSET
(
first_field
),
AV_OPT_TYPE_INT
, {.i64=0}, 0, 1,
FLAGS
,
"field"
},
60
{
"top"
,
"select top field first"
, 0,
AV_OPT_TYPE_CONST
, {.i64=0}, 0, 0,
FLAGS
,
"field"
},
61
{
"t"
,
"select top field first"
, 0,
AV_OPT_TYPE_CONST
, {.i64=0}, 0, 0,
FLAGS
,
"field"
},
62
{
"bottom"
,
"select bottom field first"
, 0,
AV_OPT_TYPE_CONST
, {.i64=1}, 0, 0,
FLAGS
,
"field"
},
63
{
"b"
,
"select bottom field first"
, 0,
AV_OPT_TYPE_CONST
, {.i64=1}, 0, 0,
FLAGS
,
"field"
},
64
{
"pattern"
,
"pattern that describe for how many fields a frame is to be displayed"
,
OFFSET
(pattern),
AV_OPT_TYPE_STRING
, {.str=
"23"
}, 0, 0,
FLAGS
},
65
{NULL}
66
};
67
68
AVFILTER_DEFINE_CLASS
(telecine);
69
70
static
av_cold
int
init
(
AVFilterContext
*ctx)
71
{
72
TelecineContext
*
tc
= ctx->
priv
;
73
const
char
*p;
74
int
max = 0;
75
76
if
(!strlen(tc->
pattern
)) {
77
av_log
(ctx,
AV_LOG_ERROR
,
"No pattern provided.\n"
);
78
return
AVERROR_INVALIDDATA
;
79
}
80
81
for
(p = tc->
pattern
; *p; p++) {
82
if
(!
av_isdigit
(*p)) {
83
av_log
(ctx,
AV_LOG_ERROR
,
"Provided pattern includes non-numeric characters.\n"
);
84
return
AVERROR_INVALIDDATA
;
85
}
86
87
max =
FFMAX
(*p -
'0'
, max);
88
tc->
pts
.
num
+= 2;
89
tc->
pts
.
den
+= *p -
'0'
;
90
}
91
92
tc->
out_cnt
= (max + 1) / 2;
93
av_log
(ctx,
AV_LOG_INFO
,
"Telecine pattern %s yields up to %d frames per frame, pts advance factor: %d/%d\n"
,
94
tc->
pattern
, tc->
out_cnt
, tc->
pts
.
num
, tc->
pts
.
den
);
95
96
return
0;
97
}
98
99
static
int
query_formats
(
AVFilterContext
*ctx)
100
{
101
AVFilterFormats
*pix_fmts = NULL;
102
int
fmt
;
103
104
for
(fmt = 0; fmt <
AV_PIX_FMT_NB
; fmt++) {
105
const
AVPixFmtDescriptor
*desc =
av_pix_fmt_desc_get
(fmt);
106
if
(!(desc->
flags
&
AV_PIX_FMT_FLAG_HWACCEL
||
107
desc->
flags
&
AV_PIX_FMT_FLAG_PAL
||
108
desc->
flags
&
AV_PIX_FMT_FLAG_BITSTREAM
))
109
ff_add_format
(&pix_fmts, fmt);
110
}
111
112
ff_set_common_formats
(ctx, pix_fmts);
113
return
0;
114
}
115
116
static
int
config_input
(
AVFilterLink
*inlink)
117
{
118
TelecineContext
*
tc
= inlink->
dst
->
priv
;
119
const
AVPixFmtDescriptor
*desc =
av_pix_fmt_desc_get
(inlink->
format
);
120
int
i,
ret
;
121
122
tc->
temp
=
ff_get_video_buffer
(inlink, inlink->
w
, inlink->
h
);
123
if
(!tc->
temp
)
124
return
AVERROR
(ENOMEM);
125
for
(i = 0; i < tc->
out_cnt
; i++) {
126
tc->
frame
[i] =
ff_get_video_buffer
(inlink, inlink->
w
, inlink->
h
);
127
if
(!tc->
frame
[i])
128
return
AVERROR
(ENOMEM);
129
}
130
131
if
((ret =
av_image_fill_linesizes
(tc->
stride
, inlink->
format
, inlink->
w
)) < 0)
132
return
ret
;
133
134
tc->
planeheight
[1] = tc->
planeheight
[2] =
FF_CEIL_RSHIFT
(inlink->
h
, desc->
log2_chroma_h
);
135
tc->
planeheight
[0] = tc->
planeheight
[3] = inlink->
h
;
136
137
tc->
nb_planes
=
av_pix_fmt_count_planes
(inlink->
format
);
138
139
return
0;
140
}
141
142
static
int
config_output
(
AVFilterLink
*outlink)
143
{
144
AVFilterContext
*ctx = outlink->
src
;
145
TelecineContext
*
tc
= ctx->
priv
;
146
const
AVFilterLink
*inlink = ctx->
inputs
[0];
147
AVRational
fps = inlink->
frame_rate
;
148
149
if
(!fps.
num
|| !fps.
den
) {
150
av_log
(ctx,
AV_LOG_ERROR
,
"The input needs a constant frame rate; "
151
"current rate of %d/%d is invalid\n"
, fps.
num
, fps.
den
);
152
return
AVERROR
(EINVAL);
153
}
154
fps =
av_mul_q
(fps,
av_inv_q
(tc->
pts
));
155
av_log
(ctx,
AV_LOG_VERBOSE
,
"FPS: %d/%d -> %d/%d\n"
,
156
inlink->
frame_rate
.
num
, inlink->
frame_rate
.
den
, fps.
num
, fps.
den
);
157
158
outlink->
flags
|=
FF_LINK_FLAG_REQUEST_LOOP
;
159
outlink->
frame_rate
= fps;
160
outlink->
time_base
=
av_mul_q
(inlink->
time_base
, tc->
pts
);
161
av_log
(ctx,
AV_LOG_VERBOSE
,
"TB: %d/%d -> %d/%d\n"
,
162
inlink->
time_base
.
num
, inlink->
time_base
.
den
, outlink->
time_base
.
num
, outlink->
time_base
.
den
);
163
164
tc->
ts_unit
=
av_q2d
(
av_inv_q
(
av_mul_q
(fps, outlink->
time_base
)));
165
166
return
0;
167
}
168
169
static
int
filter_frame
(
AVFilterLink
*inlink,
AVFrame
*inpicref)
170
{
171
AVFilterContext
*ctx = inlink->
dst
;
172
AVFilterLink
*outlink = ctx->
outputs
[0];
173
TelecineContext
*
tc
= ctx->
priv
;
174
int
i,
len
,
ret
= 0, nout = 0;
175
176
len = tc->
pattern
[tc->
pattern_pos
] -
'0'
;
177
178
tc->
pattern_pos
++;
179
if
(!tc->
pattern
[tc->
pattern_pos
])
180
tc->
pattern_pos
= 0;
181
182
if
(!len) {
// do not output any field from this frame
183
av_frame_free
(&inpicref);
184
return
0;
185
}
186
187
if
(tc->
occupied
) {
188
for
(i = 0; i < tc->
nb_planes
; i++) {
189
// fill in the EARLIER field from the buffered pic
190
av_image_copy_plane
(tc->
frame
[nout]->
data
[i] + tc->
frame
[nout]->
linesize
[i] * tc->
first_field
,
191
tc->
frame
[nout]->
linesize
[i] * 2,
192
tc->
temp
->
data
[i] + tc->
temp
->
linesize
[i] * tc->
first_field
,
193
tc->
temp
->
linesize
[i] * 2,
194
tc->
stride
[i],
195
(tc->
planeheight
[i] - tc->
first_field
+ 1) / 2);
196
// fill in the LATER field from the new pic
197
av_image_copy_plane
(tc->
frame
[nout]->
data
[i] + tc->
frame
[nout]->
linesize
[i] * !tc->
first_field
,
198
tc->
frame
[nout]->
linesize
[i] * 2,
199
inpicref->
data
[i] + inpicref->
linesize
[i] * !tc->
first_field
,
200
inpicref->
linesize
[i] * 2,
201
tc->
stride
[i],
202
(tc->
planeheight
[i] - !tc->
first_field
+ 1) / 2);
203
}
204
nout++;
205
len--;
206
tc->
occupied
= 0;
207
}
208
209
while
(len >= 2) {
210
// output THIS image as-is
211
for
(i = 0; i < tc->
nb_planes
; i++)
212
av_image_copy_plane
(tc->
frame
[nout]->
data
[i], tc->
frame
[nout]->
linesize
[i],
213
inpicref->
data
[i], inpicref->
linesize
[i],
214
tc->
stride
[i],
215
tc->
planeheight
[i]);
216
nout++;
217
len -= 2;
218
}
219
220
if
(len >= 1) {
221
// copy THIS image to the buffer, we need it later
222
for
(i = 0; i < tc->
nb_planes
; i++)
223
av_image_copy_plane
(tc->
temp
->
data
[i], tc->
temp
->
linesize
[i],
224
inpicref->
data
[i], inpicref->
linesize
[i],
225
tc->
stride
[i],
226
tc->
planeheight
[i]);
227
tc->
occupied
= 1;
228
}
229
230
for
(i = 0; i < nout; i++) {
231
AVFrame
*
frame
=
av_frame_clone
(tc->
frame
[i]);
232
233
if
(!frame) {
234
av_frame_free
(&inpicref);
235
return
AVERROR
(ENOMEM);
236
}
237
238
frame->
pts
= outlink->
frame_count
* tc->
ts_unit
;
239
ret =
ff_filter_frame
(outlink, frame);
240
}
241
av_frame_free
(&inpicref);
242
243
return
ret
;
244
}
245
246
static
av_cold
void
uninit
(
AVFilterContext
*ctx)
247
{
248
TelecineContext
*
tc
= ctx->
priv
;
249
int
i;
250
251
av_frame_free
(&tc->
temp
);
252
for
(i = 0; i < tc->
out_cnt
; i++)
253
av_frame_free
(&tc->
frame
[i]);
254
}
255
256
static
const
AVFilterPad
telecine_inputs
[] = {
257
{
258
.
name
=
"default"
,
259
.type =
AVMEDIA_TYPE_VIDEO
,
260
.filter_frame =
filter_frame
,
261
.config_props =
config_input
,
262
},
263
{ NULL }
264
};
265
266
static
const
AVFilterPad
telecine_outputs
[] = {
267
{
268
.
name
=
"default"
,
269
.type =
AVMEDIA_TYPE_VIDEO
,
270
.config_props =
config_output
,
271
},
272
{ NULL }
273
};
274
275
AVFilter
ff_vf_telecine
= {
276
.
name
=
"telecine"
,
277
.description =
NULL_IF_CONFIG_SMALL
(
"Apply a telecine pattern."
),
278
.priv_size =
sizeof
(
TelecineContext
),
279
.priv_class = &telecine_class,
280
.
init
=
init
,
281
.
uninit
=
uninit
,
282
.
query_formats
=
query_formats
,
283
.
inputs
= telecine_inputs,
284
.
outputs
= telecine_outputs,
285
};
Generated on Sun Mar 23 2014 23:50:09 for FFmpeg by
1.8.2