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
ff_add_format
(&pix_fmts, fmt);
108
}
109
110
ff_set_common_formats
(ctx, pix_fmts);
111
return
0;
112
}
113
114
static
int
config_input
(
AVFilterLink
*inlink)
115
{
116
TelecineContext
*
tc
= inlink->
dst
->
priv
;
117
const
AVPixFmtDescriptor
*desc =
av_pix_fmt_desc_get
(inlink->
format
);
118
int
i,
ret
;
119
120
tc->
temp
=
ff_get_video_buffer
(inlink, inlink->
w
, inlink->
h
);
121
if
(!tc->
temp
)
122
return
AVERROR
(ENOMEM);
123
for
(i = 0; i < tc->
out_cnt
; i++) {
124
tc->
frame
[i] =
ff_get_video_buffer
(inlink, inlink->
w
, inlink->
h
);
125
if
(!tc->
frame
[i])
126
return
AVERROR
(ENOMEM);
127
}
128
129
if
((ret =
av_image_fill_linesizes
(tc->
stride
, inlink->
format
, inlink->
w
)) < 0)
130
return
ret
;
131
132
tc->
planeheight
[1] = tc->
planeheight
[2] =
FF_CEIL_RSHIFT
(inlink->
h
, desc->
log2_chroma_h
);
133
tc->
planeheight
[0] = tc->
planeheight
[3] = inlink->
h
;
134
135
tc->
nb_planes
=
av_pix_fmt_count_planes
(inlink->
format
);
136
137
return
0;
138
}
139
140
static
int
config_output
(
AVFilterLink
*outlink)
141
{
142
AVFilterContext
*ctx = outlink->
src
;
143
TelecineContext
*
tc
= ctx->
priv
;
144
const
AVFilterLink
*inlink = ctx->
inputs
[0];
145
AVRational
fps = inlink->
frame_rate
;
146
147
if
(!fps.
num
|| !fps.
den
) {
148
av_log
(ctx,
AV_LOG_ERROR
,
"The input needs a constant frame rate; "
149
"current rate of %d/%d is invalid\n"
, fps.
num
, fps.
den
);
150
return
AVERROR
(EINVAL);
151
}
152
fps =
av_mul_q
(fps,
av_inv_q
(tc->
pts
));
153
av_log
(ctx,
AV_LOG_VERBOSE
,
"FPS: %d/%d -> %d/%d\n"
,
154
inlink->
frame_rate
.
num
, inlink->
frame_rate
.
den
, fps.
num
, fps.
den
);
155
156
outlink->
flags
|=
FF_LINK_FLAG_REQUEST_LOOP
;
157
outlink->
frame_rate
= fps;
158
outlink->
time_base
=
av_mul_q
(inlink->
time_base
, tc->
pts
);
159
av_log
(ctx,
AV_LOG_VERBOSE
,
"TB: %d/%d -> %d/%d\n"
,
160
inlink->
time_base
.
num
, inlink->
time_base
.
den
, outlink->
time_base
.
num
, outlink->
time_base
.
den
);
161
162
tc->
ts_unit
=
av_q2d
(
av_inv_q
(
av_mul_q
(fps, outlink->
time_base
)));
163
164
return
0;
165
}
166
167
static
int
filter_frame
(
AVFilterLink
*inlink,
AVFrame
*inpicref)
168
{
169
AVFilterContext
*ctx = inlink->
dst
;
170
AVFilterLink
*outlink = ctx->
outputs
[0];
171
TelecineContext
*
tc
= ctx->
priv
;
172
int
i,
len
,
ret
= 0, nout = 0;
173
174
len = tc->
pattern
[tc->
pattern_pos
] -
'0'
;
175
176
tc->
pattern_pos
++;
177
if
(!tc->
pattern
[tc->
pattern_pos
])
178
tc->
pattern_pos
= 0;
179
180
if
(!len) {
// do not output any field from this frame
181
av_frame_free
(&inpicref);
182
return
0;
183
}
184
185
if
(tc->
occupied
) {
186
for
(i = 0; i < tc->
nb_planes
; i++) {
187
// fill in the EARLIER field from the buffered pic
188
av_image_copy_plane
(tc->
frame
[nout]->
data
[i] + tc->
frame
[nout]->
linesize
[i] * tc->
first_field
,
189
tc->
frame
[nout]->
linesize
[i] * 2,
190
tc->
temp
->
data
[i] + tc->
temp
->
linesize
[i] * tc->
first_field
,
191
tc->
temp
->
linesize
[i] * 2,
192
tc->
stride
[i],
193
(tc->
planeheight
[i] - tc->
first_field
+ 1) / 2);
194
// fill in the LATER field from the new pic
195
av_image_copy_plane
(tc->
frame
[nout]->
data
[i] + tc->
frame
[nout]->
linesize
[i] * !tc->
first_field
,
196
tc->
frame
[nout]->
linesize
[i] * 2,
197
inpicref->
data
[i] + inpicref->
linesize
[i] * !tc->
first_field
,
198
inpicref->
linesize
[i] * 2,
199
tc->
stride
[i],
200
(tc->
planeheight
[i] - !tc->
first_field
+ 1) / 2);
201
}
202
nout++;
203
len--;
204
tc->
occupied
= 0;
205
}
206
207
while
(len >= 2) {
208
// output THIS image as-is
209
for
(i = 0; i < tc->
nb_planes
; i++)
210
av_image_copy_plane
(tc->
frame
[nout]->
data
[i], tc->
frame
[nout]->
linesize
[i],
211
inpicref->
data
[i], inpicref->
linesize
[i],
212
tc->
stride
[i],
213
tc->
planeheight
[i]);
214
nout++;
215
len -= 2;
216
}
217
218
if
(len >= 1) {
219
// copy THIS image to the buffer, we need it later
220
for
(i = 0; i < tc->
nb_planes
; i++)
221
av_image_copy_plane
(tc->
temp
->
data
[i], tc->
temp
->
linesize
[i],
222
inpicref->
data
[i], inpicref->
linesize
[i],
223
tc->
stride
[i],
224
tc->
planeheight
[i]);
225
tc->
occupied
= 1;
226
}
227
228
for
(i = 0; i < nout; i++) {
229
AVFrame
*
frame
=
av_frame_clone
(tc->
frame
[i]);
230
231
if
(!frame) {
232
av_frame_free
(&inpicref);
233
return
AVERROR
(ENOMEM);
234
}
235
236
av_frame_copy_props
(frame, inpicref);
237
frame->
pts
= outlink->
frame_count
* tc->
ts_unit
;
238
ret =
ff_filter_frame
(outlink, frame);
239
}
240
av_frame_free
(&inpicref);
241
242
return
ret
;
243
}
244
245
static
av_cold
void
uninit
(
AVFilterContext
*ctx)
246
{
247
TelecineContext
*
tc
= ctx->
priv
;
248
int
i;
249
250
av_frame_free
(&tc->
temp
);
251
for
(i = 0; i < tc->
out_cnt
; i++)
252
av_frame_free
(&tc->
frame
[i]);
253
}
254
255
static
const
AVFilterPad
telecine_inputs
[] = {
256
{
257
.
name
=
"default"
,
258
.type =
AVMEDIA_TYPE_VIDEO
,
259
.filter_frame =
filter_frame
,
260
.config_props =
config_input
,
261
},
262
{ NULL }
263
};
264
265
static
const
AVFilterPad
telecine_outputs
[] = {
266
{
267
.
name
=
"default"
,
268
.type =
AVMEDIA_TYPE_VIDEO
,
269
.config_props =
config_output
,
270
},
271
{ NULL }
272
};
273
274
AVFilter
avfilter_vf_telecine
= {
275
.
name
=
"telecine"
,
276
.description =
NULL_IF_CONFIG_SMALL
(
"Apply a telecine pattern."
),
277
.priv_size =
sizeof
(
TelecineContext
),
278
.priv_class = &telecine_class,
279
.
init
=
init
,
280
.
uninit
=
uninit
,
281
.
query_formats
=
query_formats
,
282
.
inputs
= telecine_inputs,
283
.
outputs
= telecine_outputs,
284
};
Generated on Wed Jul 10 2013 23:48:11 for FFmpeg by
1.8.2