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
flush_fifo
(s->
fifo
);
113
av_fifo_free
(s->
fifo
);
114
}
115
116
av_log
(ctx,
AV_LOG_VERBOSE
,
"%d frames in, %d frames out; %d frames dropped, "
117
"%d frames duplicated.\n"
, s->
frames_in
, s->
frames_out
, s->
drop
, s->
dup
);
118
}
119
120
static
int
config_props
(
AVFilterLink
* link)
121
{
122
FPSContext
*s = link->
src
->
priv
;
123
124
link->
time_base
=
av_inv_q
(s->
framerate
);
125
link->
frame_rate
= s->
framerate
;
126
link->
w
= link->
src
->
inputs
[0]->
w
;
127
link->
h
= link->
src
->
inputs
[0]->
h
;
128
s->
pts
=
AV_NOPTS_VALUE
;
129
130
return
0;
131
}
132
133
static
int
request_frame
(
AVFilterLink
*outlink)
134
{
135
AVFilterContext
*ctx = outlink->
src
;
136
FPSContext
*s = ctx->
priv
;
137
int
frames_out = s->
frames_out
;
138
int
ret = 0;
139
140
while
(ret >= 0 && s->
frames_out
== frames_out)
141
ret =
ff_request_frame
(ctx->
inputs
[0]);
142
143
/* flush the fifo */
144
if
(ret ==
AVERROR_EOF
&&
av_fifo_size
(s->
fifo
)) {
145
int
i;
146
for
(i = 0;
av_fifo_size
(s->
fifo
); i++) {
147
AVFilterBufferRef
*buf;
148
149
av_fifo_generic_read
(s->
fifo
, &buf,
sizeof
(buf),
NULL
);
150
buf->
pts
=
av_rescale_q
(s->
first_pts
, ctx->
inputs
[0]->
time_base
,
151
outlink->
time_base
) + s->
frames_out
;
152
153
if
((ret =
ff_filter_frame
(outlink, buf)) < 0)
154
return
ret;
155
156
s->
frames_out
++;
157
}
158
return
0;
159
}
160
161
return
ret;
162
}
163
164
static
int
write_to_fifo
(
AVFifoBuffer
*fifo,
AVFilterBufferRef
*buf)
165
{
166
int
ret;
167
168
if
(!
av_fifo_space
(fifo) &&
169
(ret =
av_fifo_realloc2
(fifo, 2*
av_fifo_size
(fifo)))) {
170
avfilter_unref_bufferp
(&buf);
171
return
ret;
172
}
173
174
av_fifo_generic_write
(fifo, &buf,
sizeof
(buf),
NULL
);
175
return
0;
176
}
177
178
static
int
filter_frame
(
AVFilterLink
*inlink,
AVFilterBufferRef
*buf)
179
{
180
AVFilterContext
*ctx = inlink->
dst
;
181
FPSContext
*s = ctx->
priv
;
182
AVFilterLink
*outlink = ctx->
outputs
[0];
183
int64_t
delta
;
184
int
i, ret;
185
186
s->
frames_in
++;
187
/* discard frames until we get the first timestamp */
188
if
(s->
pts
==
AV_NOPTS_VALUE
) {
189
if
(buf->
pts
!=
AV_NOPTS_VALUE
) {
190
ret =
write_to_fifo
(s->
fifo
, buf);
191
if
(ret < 0)
192
return
ret;
193
194
s->
first_pts
= s->
pts
= buf->
pts
;
195
}
else
{
196
av_log
(ctx,
AV_LOG_WARNING
,
"Discarding initial frame(s) with no "
197
"timestamp.\n"
);
198
avfilter_unref_buffer
(buf);
199
s->
drop
++;
200
}
201
return
0;
202
}
203
204
/* now wait for the next timestamp */
205
if
(buf->
pts
==
AV_NOPTS_VALUE
) {
206
return
write_to_fifo
(s->
fifo
, buf);
207
}
208
209
/* number of output frames */
210
delta =
av_rescale_q_rnd
(buf->
pts
- s->
pts
, inlink->
time_base
,
211
outlink->
time_base
, s->
rounding
);
212
213
if
(delta < 1) {
214
/* drop the frame and everything buffered except the first */
215
AVFilterBufferRef
*tmp;
216
int
drop =
av_fifo_size
(s->
fifo
)/
sizeof
(
AVFilterBufferRef
*);
217
218
av_log
(ctx,
AV_LOG_DEBUG
,
"Dropping %d frame(s).\n"
, drop);
219
s->
drop
+= drop;
220
221
av_fifo_generic_read
(s->
fifo
, &tmp,
sizeof
(tmp),
NULL
);
222
flush_fifo
(s->
fifo
);
223
ret =
write_to_fifo
(s->
fifo
, tmp);
224
225
avfilter_unref_buffer
(buf);
226
return
ret;
227
}
228
229
/* can output >= 1 frames */
230
for
(i = 0; i <
delta
; i++) {
231
AVFilterBufferRef
*buf_out;
232
av_fifo_generic_read
(s->
fifo
, &buf_out,
sizeof
(buf_out),
NULL
);
233
234
/* duplicate the frame if needed */
235
if
(!
av_fifo_size
(s->
fifo
) && i < delta - 1) {
236
AVFilterBufferRef
*dup =
avfilter_ref_buffer
(buf_out, ~0);
237
238
av_log
(ctx,
AV_LOG_DEBUG
,
"Duplicating frame.\n"
);
239
if
(dup)
240
ret =
write_to_fifo
(s->
fifo
, dup);
241
else
242
ret =
AVERROR
(ENOMEM);
243
244
if
(ret < 0) {
245
avfilter_unref_bufferp
(&buf_out);
246
avfilter_unref_bufferp
(&buf);
247
return
ret;
248
}
249
250
s->
dup
++;
251
}
252
253
buf_out->
pts
=
av_rescale_q
(s->
first_pts
, inlink->
time_base
,
254
outlink->
time_base
) + s->
frames_out
;
255
256
if
((ret =
ff_filter_frame
(outlink, buf_out)) < 0) {
257
avfilter_unref_bufferp
(&buf);
258
return
ret;
259
}
260
261
s->
frames_out
++;
262
}
263
flush_fifo
(s->
fifo
);
264
265
ret =
write_to_fifo
(s->
fifo
, buf);
266
s->
pts
= s->
first_pts
+
av_rescale_q
(s->
frames_out
, outlink->
time_base
, inlink->
time_base
);
267
268
return
ret;
269
}
270
271
static
const
AVFilterPad
avfilter_vf_fps_inputs
[] = {
272
{
273
.
name
=
"default"
,
274
.type =
AVMEDIA_TYPE_VIDEO
,
275
.min_perms =
AV_PERM_READ
|
AV_PERM_PRESERVE
,
276
.filter_frame =
filter_frame
,
277
},
278
{
NULL
}
279
};
280
281
static
const
AVFilterPad
avfilter_vf_fps_outputs
[] = {
282
{
283
.
name
=
"default"
,
284
.type =
AVMEDIA_TYPE_VIDEO
,
285
.rej_perms =
AV_PERM_WRITE
,
286
.request_frame =
request_frame
,
287
.config_props =
config_props
288
},
289
{
NULL
}
290
};
291
292
AVFilter
avfilter_vf_fps
= {
293
.
name
=
"fps"
,
294
.description =
NULL_IF_CONFIG_SMALL
(
"Force constant framerate"
),
295
296
.init =
init
,
297
.uninit =
uninit
,
298
299
.priv_size =
sizeof
(
FPSContext
),
300
301
.
inputs
= avfilter_vf_fps_inputs,
302
.
outputs
= avfilter_vf_fps_outputs,
303
.priv_class = &fps_class,
304
};
Generated on Sat May 25 2013 03:58:45 for FFmpeg by
1.8.2