FFmpeg
Main Page
Related Pages
Modules
Data Structures
Files
Examples
File List
Globals
All
Data Structures
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
libavfilter
vf_fps.c
Go to the documentation of this file.
1
/*
2
* Copyright 2007 Bobby Bingham
3
* Copyright 2012 Robert Nagy <ronag89 gmail com>
4
* Copyright 2012 Anton Khirnov <anton khirnov net>
5
*
6
* This file is part of FFmpeg.
7
*
8
* FFmpeg is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU Lesser General Public
10
* License as published by the Free Software Foundation; either
11
* version 2.1 of the License, or (at your option) any later version.
12
*
13
* FFmpeg is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* Lesser General Public License for more details.
17
*
18
* You should have received a copy of the GNU Lesser General Public
19
* License along with FFmpeg; if not, write to the Free Software
20
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
*/
22
23
/**
24
* @file
25
* a filter enforcing given constant framerate
26
*/
27
28
#include "
libavutil/common.h
"
29
#include "
libavutil/fifo.h
"
30
#include "
libavutil/mathematics.h
"
31
#include "
libavutil/opt.h
"
32
#include "
libavutil/parseutils.h
"
33
34
#include "
avfilter.h
"
35
#include "
internal.h
"
36
#include "
video.h
"
37
38
typedef
struct
FPSContext
{
39
const
AVClass
*
class
;
40
41
AVFifoBuffer
*
fifo
;
///< store frames until we get two successive timestamps
42
43
/* timestamps in input timebase */
44
int64_t
first_pts
;
///< pts of the first frame that arrived on this filter
45
int64_t
pts
;
///< pts of the first frame currently in the fifo
46
47
AVRational
framerate
;
///< target framerate
48
char
*
fps
;
///< a string describing target framerate
49
int
rounding
;
///< AVRounding method for timestamps
50
51
/* statistics */
52
int
frames_in
;
///< number of frames on input
53
int
frames_out
;
///< number of frames on output
54
int
dup
;
///< number of frames duplicated
55
int
drop
;
///< number of framed dropped
56
}
FPSContext
;
57
58
#define OFFSET(x) offsetof(FPSContext, x)
59
#define V AV_OPT_FLAG_VIDEO_PARAM
60
#define F AV_OPT_FLAG_FILTERING_PARAM
61
static
const
AVOption
fps_options
[] = {
62
{
"fps"
,
"A string describing desired output framerate"
,
OFFSET
(fps),
AV_OPT_TYPE_STRING
, { .str =
"25"
}, .flags =
V
|
F
},
63
{
"round"
,
"set rounding method for timestamps"
,
OFFSET
(rounding),
AV_OPT_TYPE_INT
, { .i64 =
AV_ROUND_NEAR_INF
}, 0, 5,
V
|
F
,
"round"
},
64
{
"zero"
,
"round towards 0"
,
OFFSET
(rounding),
AV_OPT_TYPE_CONST
, { .i64 =
AV_ROUND_ZERO
}, 0, 5,
V
|
F
,
"round"
},
65
{
"inf"
,
"round away from 0"
,
OFFSET
(rounding),
AV_OPT_TYPE_CONST
, { .i64 =
AV_ROUND_INF
}, 0, 5,
V
|
F
,
"round"
},
66
{
"down"
,
"round towards -infty"
,
OFFSET
(rounding),
AV_OPT_TYPE_CONST
, { .i64 =
AV_ROUND_DOWN
}, 0, 5,
V
|
F
,
"round"
},
67
{
"up"
,
"round towards +infty"
,
OFFSET
(rounding),
AV_OPT_TYPE_CONST
, { .i64 =
AV_ROUND_UP
}, 0, 5,
V
|
F
,
"round"
},
68
{
"near"
,
"round to nearest"
,
OFFSET
(rounding),
AV_OPT_TYPE_CONST
, { .i64 =
AV_ROUND_NEAR_INF
}, 0, 5,
V
|
F
,
"round"
},
69
{
NULL
},
70
};
71
72
AVFILTER_DEFINE_CLASS
(fps);
73
74
static
av_cold
int
init
(
AVFilterContext
*ctx,
const
char
*args)
75
{
76
FPSContext
*s = ctx->
priv
;
77
const
char
*shorthand[] = {
"fps"
,
"round"
,
NULL
};
78
int
ret;
79
80
s->
class
= &fps_class;
81
av_opt_set_defaults
(s);
82
83
if
((ret =
av_opt_set_from_string
(s, args, shorthand,
"="
,
":"
)) < 0)
84
return
ret;
85
86
if
((ret =
av_parse_video_rate
(&s->
framerate
, s->
fps
)) < 0) {
87
av_log
(ctx,
AV_LOG_ERROR
,
"Error parsing framerate %s.\n"
, s->
fps
);
88
return
ret;
89
}
90
av_opt_free
(s);
91
92
if
(!(s->
fifo
=
av_fifo_alloc
(2*
sizeof
(
AVFilterBufferRef
*))))
93
return
AVERROR
(ENOMEM);
94
95
av_log
(ctx,
AV_LOG_VERBOSE
,
"fps=%d/%d\n"
, s->
framerate
.
num
, s->
framerate
.
den
);
96
return
0;
97
}
98
99
static
void
flush_fifo
(
AVFifoBuffer
*fifo)
100
{
101
while
(
av_fifo_size
(fifo)) {
102
AVFilterBufferRef
*tmp;
103
av_fifo_generic_read
(fifo, &tmp,
sizeof
(tmp),
NULL
);
104
avfilter_unref_buffer
(tmp);
105
}
106
}
107
108
static
av_cold
void
uninit
(
AVFilterContext
*ctx)
109
{
110
FPSContext
*s = ctx->
priv
;
111
if
(s->
fifo
) {
112
s->
drop
+=
av_fifo_size
(s->
fifo
) /
sizeof
(
AVFilterBufferRef
*);
113
flush_fifo
(s->
fifo
);
114
av_fifo_free
(s->
fifo
);
115
}
116
117
av_log
(ctx,
AV_LOG_VERBOSE
,
"%d frames in, %d frames out; %d frames dropped, "
118
"%d frames duplicated.\n"
, s->
frames_in
, s->
frames_out
, s->
drop
, s->
dup
);
119
}
120
121
static
int
config_props
(
AVFilterLink
* link)
122
{
123
FPSContext
*s = link->
src
->
priv
;
124
125
link->
time_base
=
av_inv_q
(s->
framerate
);
126
link->
frame_rate
= s->
framerate
;
127
link->
w
= link->
src
->
inputs
[0]->
w
;
128
link->
h
= link->
src
->
inputs
[0]->
h
;
129
s->
pts
=
AV_NOPTS_VALUE
;
130
131
return
0;
132
}
133
134
static
int
request_frame
(
AVFilterLink
*outlink)
135
{
136
AVFilterContext
*ctx = outlink->
src
;
137
FPSContext
*s = ctx->
priv
;
138
int
frames_out = s->
frames_out
;
139
int
ret = 0;
140
141
while
(ret >= 0 && s->
frames_out
== frames_out)
142
ret =
ff_request_frame
(ctx->
inputs
[0]);
143
144
/* flush the fifo */
145
if
(ret ==
AVERROR_EOF
&&
av_fifo_size
(s->
fifo
)) {
146
int
i;
147
for
(i = 0;
av_fifo_size
(s->
fifo
); i++) {
148
AVFilterBufferRef
*buf;
149
150
av_fifo_generic_read
(s->
fifo
, &buf,
sizeof
(buf),
NULL
);
151
buf->
pts
=
av_rescale_q
(s->
first_pts
, ctx->
inputs
[0]->
time_base
,
152
outlink->
time_base
) + s->
frames_out
;
153
154
if
((ret =
ff_filter_frame
(outlink, buf)) < 0)
155
return
ret;
156
157
s->
frames_out
++;
158
}
159
return
0;
160
}
161
162
return
ret;
163
}
164
165
static
int
write_to_fifo
(
AVFifoBuffer
*fifo,
AVFilterBufferRef
*buf)
166
{
167
int
ret;
168
169
if
(!
av_fifo_space
(fifo) &&
170
(ret =
av_fifo_realloc2
(fifo, 2*
av_fifo_size
(fifo)))) {
171
avfilter_unref_bufferp
(&buf);
172
return
ret;
173
}
174
175
av_fifo_generic_write
(fifo, &buf,
sizeof
(buf),
NULL
);
176
return
0;
177
}
178
179
static
int
filter_frame
(
AVFilterLink
*inlink,
AVFilterBufferRef
*buf)
180
{
181
AVFilterContext
*ctx = inlink->
dst
;
182
FPSContext
*s = ctx->
priv
;
183
AVFilterLink
*outlink = ctx->
outputs
[0];
184
int64_t
delta
;
185
int
i, ret;
186
187
s->
frames_in
++;
188
/* discard frames until we get the first timestamp */
189
if
(s->
pts
==
AV_NOPTS_VALUE
) {
190
if
(buf->
pts
!=
AV_NOPTS_VALUE
) {
191
ret =
write_to_fifo
(s->
fifo
, buf);
192
if
(ret < 0)
193
return
ret;
194
195
s->
first_pts
= s->
pts
= buf->
pts
;
196
}
else
{
197
av_log
(ctx,
AV_LOG_WARNING
,
"Discarding initial frame(s) with no "
198
"timestamp.\n"
);
199
avfilter_unref_buffer
(buf);
200
s->
drop
++;
201
}
202
return
0;
203
}
204
205
/* now wait for the next timestamp */
206
if
(buf->
pts
==
AV_NOPTS_VALUE
) {
207
return
write_to_fifo
(s->
fifo
, buf);
208
}
209
210
/* number of output frames */
211
delta =
av_rescale_q_rnd
(buf->
pts
- s->
pts
, inlink->
time_base
,
212
outlink->
time_base
, s->
rounding
);
213
214
if
(delta < 1) {
215
/* drop the frame and everything buffered except the first */
216
AVFilterBufferRef
*tmp;
217
int
drop =
av_fifo_size
(s->
fifo
)/
sizeof
(
AVFilterBufferRef
*);
218
219
av_log
(ctx,
AV_LOG_DEBUG
,
"Dropping %d frame(s).\n"
, drop);
220
s->
drop
+= drop;
221
222
av_fifo_generic_read
(s->
fifo
, &tmp,
sizeof
(tmp),
NULL
);
223
flush_fifo
(s->
fifo
);
224
ret =
write_to_fifo
(s->
fifo
, tmp);
225
226
avfilter_unref_buffer
(buf);
227
return
ret;
228
}
229
230
/* can output >= 1 frames */
231
for
(i = 0; i <
delta
; i++) {
232
AVFilterBufferRef
*buf_out;
233
av_fifo_generic_read
(s->
fifo
, &buf_out,
sizeof
(buf_out),
NULL
);
234
235
/* duplicate the frame if needed */
236
if
(!
av_fifo_size
(s->
fifo
) && i < delta - 1) {
237
AVFilterBufferRef
*dup =
avfilter_ref_buffer
(buf_out, ~0);
238
239
av_log
(ctx,
AV_LOG_DEBUG
,
"Duplicating frame.\n"
);
240
if
(dup)
241
ret =
write_to_fifo
(s->
fifo
, dup);
242
else
243
ret =
AVERROR
(ENOMEM);
244
245
if
(ret < 0) {
246
avfilter_unref_bufferp
(&buf_out);
247
avfilter_unref_bufferp
(&buf);
248
return
ret;
249
}
250
251
s->
dup
++;
252
}
253
254
buf_out->
pts
=
av_rescale_q
(s->
first_pts
, inlink->
time_base
,
255
outlink->
time_base
) + s->
frames_out
;
256
257
if
((ret =
ff_filter_frame
(outlink, buf_out)) < 0) {
258
avfilter_unref_bufferp
(&buf);
259
return
ret;
260
}
261
262
s->
frames_out
++;
263
}
264
flush_fifo
(s->
fifo
);
265
266
ret =
write_to_fifo
(s->
fifo
, buf);
267
s->
pts
= s->
first_pts
+
av_rescale_q
(s->
frames_out
, outlink->
time_base
, inlink->
time_base
);
268
269
return
ret;
270
}
271
272
static
const
AVFilterPad
avfilter_vf_fps_inputs
[] = {
273
{
274
.
name
=
"default"
,
275
.type =
AVMEDIA_TYPE_VIDEO
,
276
.min_perms =
AV_PERM_READ
|
AV_PERM_PRESERVE
,
277
.filter_frame =
filter_frame
,
278
},
279
{
NULL
}
280
};
281
282
static
const
AVFilterPad
avfilter_vf_fps_outputs
[] = {
283
{
284
.
name
=
"default"
,
285
.type =
AVMEDIA_TYPE_VIDEO
,
286
.rej_perms =
AV_PERM_WRITE
,
287
.request_frame =
request_frame
,
288
.config_props =
config_props
289
},
290
{
NULL
}
291
};
292
293
AVFilter
avfilter_vf_fps
= {
294
.
name
=
"fps"
,
295
.description =
NULL_IF_CONFIG_SMALL
(
"Force constant framerate"
),
296
297
.init =
init
,
298
.uninit =
uninit
,
299
300
.priv_size =
sizeof
(
FPSContext
),
301
302
.
inputs
= avfilter_vf_fps_inputs,
303
.
outputs
= avfilter_vf_fps_outputs,
304
.priv_class = &fps_class,
305
};
Generated on Sat May 25 2013 04:01:15 for FFmpeg by
1.8.2