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_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
int
rounding
;
///< AVRounding method for timestamps
49
50
/* statistics */
51
int
frames_in
;
///< number of frames on input
52
int
frames_out
;
///< number of frames on output
53
int
dup
;
///< number of frames duplicated
54
int
drop
;
///< number of framed dropped
55
}
FPSContext
;
56
57
#define OFFSET(x) offsetof(FPSContext, x)
58
#define V AV_OPT_FLAG_VIDEO_PARAM
59
#define F AV_OPT_FLAG_FILTERING_PARAM
60
static
const
AVOption
fps_options
[] = {
61
{
"fps"
,
"A string describing desired output framerate"
,
OFFSET
(framerate),
AV_OPT_TYPE_VIDEO_RATE
, { .str =
"25"
}, .flags =
V
|
F
},
62
{
"round"
,
"set rounding method for timestamps"
,
OFFSET
(rounding),
AV_OPT_TYPE_INT
, { .i64 =
AV_ROUND_NEAR_INF
}, 0, 5,
V
|
F
,
"round"
},
63
{
"zero"
,
"round towards 0"
,
OFFSET
(rounding),
AV_OPT_TYPE_CONST
, { .i64 =
AV_ROUND_ZERO
}, 0, 5,
V
|
F
,
"round"
},
64
{
"inf"
,
"round away from 0"
,
OFFSET
(rounding),
AV_OPT_TYPE_CONST
, { .i64 =
AV_ROUND_INF
}, 0, 5,
V
|
F
,
"round"
},
65
{
"down"
,
"round towards -infty"
,
OFFSET
(rounding),
AV_OPT_TYPE_CONST
, { .i64 =
AV_ROUND_DOWN
}, 0, 5,
V
|
F
,
"round"
},
66
{
"up"
,
"round towards +infty"
,
OFFSET
(rounding),
AV_OPT_TYPE_CONST
, { .i64 =
AV_ROUND_UP
}, 0, 5,
V
|
F
,
"round"
},
67
{
"near"
,
"round to nearest"
,
OFFSET
(rounding),
AV_OPT_TYPE_CONST
, { .i64 =
AV_ROUND_NEAR_INF
}, 0, 5,
V
|
F
,
"round"
},
68
{ NULL },
69
};
70
71
AVFILTER_DEFINE_CLASS
(fps);
72
73
static
av_cold
int
init
(
AVFilterContext
*ctx)
74
{
75
FPSContext
*
s
= ctx->
priv
;
76
77
if
(!(s->
fifo
=
av_fifo_alloc
(2*
sizeof
(
AVFrame
*))))
78
return
AVERROR
(ENOMEM);
79
80
s->
pts
=
AV_NOPTS_VALUE
;
81
82
av_log
(ctx,
AV_LOG_VERBOSE
,
"fps=%d/%d\n"
, s->
framerate
.
num
, s->
framerate
.
den
);
83
return
0;
84
}
85
86
static
void
flush_fifo
(
AVFifoBuffer
*fifo)
87
{
88
while
(
av_fifo_size
(fifo)) {
89
AVFrame
*tmp;
90
av_fifo_generic_read
(fifo, &tmp,
sizeof
(tmp), NULL);
91
av_frame_free
(&tmp);
92
}
93
}
94
95
static
av_cold
void
uninit
(
AVFilterContext
*ctx)
96
{
97
FPSContext
*
s
= ctx->
priv
;
98
if
(s->
fifo
) {
99
s->
drop
+=
av_fifo_size
(s->
fifo
) /
sizeof
(
AVFrame
*);
100
flush_fifo
(s->
fifo
);
101
av_fifo_free
(s->
fifo
);
102
}
103
104
av_log
(ctx,
AV_LOG_VERBOSE
,
"%d frames in, %d frames out; %d frames dropped, "
105
"%d frames duplicated.\n"
, s->
frames_in
, s->
frames_out
, s->
drop
, s->
dup
);
106
}
107
108
static
int
config_props
(
AVFilterLink
* link)
109
{
110
FPSContext
*
s
= link->
src
->
priv
;
111
112
link->
time_base
=
av_inv_q
(s->
framerate
);
113
link->
frame_rate
= s->
framerate
;
114
link->
w
= link->
src
->
inputs
[0]->
w
;
115
link->
h
= link->
src
->
inputs
[0]->
h
;
116
117
return
0;
118
}
119
120
static
int
request_frame
(
AVFilterLink
*outlink)
121
{
122
AVFilterContext
*ctx = outlink->
src
;
123
FPSContext
*
s
= ctx->
priv
;
124
int
frames_out = s->
frames_out
;
125
int
ret
= 0;
126
127
while
(ret >= 0 && s->
frames_out
== frames_out)
128
ret =
ff_request_frame
(ctx->
inputs
[0]);
129
130
/* flush the fifo */
131
if
(ret ==
AVERROR_EOF
&&
av_fifo_size
(s->
fifo
)) {
132
int
i;
133
for
(i = 0;
av_fifo_size
(s->
fifo
); i++) {
134
AVFrame
*
buf
;
135
136
av_fifo_generic_read
(s->
fifo
, &buf,
sizeof
(buf), NULL);
137
buf->
pts
=
av_rescale_q
(s->
first_pts
, ctx->
inputs
[0]->
time_base
,
138
outlink->
time_base
) + s->
frames_out
;
139
140
if
((ret =
ff_filter_frame
(outlink, buf)) < 0)
141
return
ret
;
142
143
s->
frames_out
++;
144
}
145
return
0;
146
}
147
148
return
ret
;
149
}
150
151
static
int
write_to_fifo
(
AVFifoBuffer
*fifo,
AVFrame
*
buf
)
152
{
153
int
ret
;
154
155
if
(!
av_fifo_space
(fifo) &&
156
(ret =
av_fifo_realloc2
(fifo, 2*
av_fifo_size
(fifo)))) {
157
av_frame_free
(&buf);
158
return
ret
;
159
}
160
161
av_fifo_generic_write
(fifo, &buf,
sizeof
(buf), NULL);
162
return
0;
163
}
164
165
static
int
filter_frame
(
AVFilterLink
*inlink,
AVFrame
*
buf
)
166
{
167
AVFilterContext
*ctx = inlink->
dst
;
168
FPSContext
*
s
= ctx->
priv
;
169
AVFilterLink
*outlink = ctx->
outputs
[0];
170
int64_t
delta
;
171
int
i,
ret
;
172
173
s->
frames_in
++;
174
/* discard frames until we get the first timestamp */
175
if
(s->
pts
==
AV_NOPTS_VALUE
) {
176
if
(buf->
pts
!=
AV_NOPTS_VALUE
) {
177
ret =
write_to_fifo
(s->
fifo
, buf);
178
if
(ret < 0)
179
return
ret
;
180
181
s->
first_pts
= s->
pts
= buf->
pts
;
182
}
else
{
183
av_log
(ctx,
AV_LOG_WARNING
,
"Discarding initial frame(s) with no "
184
"timestamp.\n"
);
185
av_frame_free
(&buf);
186
s->
drop
++;
187
}
188
return
0;
189
}
190
191
/* now wait for the next timestamp */
192
if
(buf->
pts
==
AV_NOPTS_VALUE
) {
193
return
write_to_fifo
(s->
fifo
, buf);
194
}
195
196
/* number of output frames */
197
delta =
av_rescale_q_rnd
(buf->
pts
- s->
pts
, inlink->
time_base
,
198
outlink->
time_base
, s->
rounding
);
199
200
if
(delta < 1) {
201
/* drop the frame and everything buffered except the first */
202
AVFrame
*tmp;
203
int
drop =
av_fifo_size
(s->
fifo
)/
sizeof
(
AVFrame
*);
204
205
av_log
(ctx,
AV_LOG_DEBUG
,
"Dropping %d frame(s).\n"
, drop);
206
s->
drop
+= drop;
207
208
av_fifo_generic_read
(s->
fifo
, &tmp,
sizeof
(tmp), NULL);
209
flush_fifo
(s->
fifo
);
210
ret =
write_to_fifo
(s->
fifo
, tmp);
211
212
av_frame_free
(&buf);
213
return
ret
;
214
}
215
216
/* can output >= 1 frames */
217
for
(i = 0; i <
delta
; i++) {
218
AVFrame
*buf_out;
219
av_fifo_generic_read
(s->
fifo
, &buf_out,
sizeof
(buf_out), NULL);
220
221
/* duplicate the frame if needed */
222
if
(!
av_fifo_size
(s->
fifo
) && i < delta - 1) {
223
AVFrame
*dup =
av_frame_clone
(buf_out);
224
225
av_log
(ctx,
AV_LOG_DEBUG
,
"Duplicating frame.\n"
);
226
if
(dup)
227
ret =
write_to_fifo
(s->
fifo
, dup);
228
else
229
ret =
AVERROR
(ENOMEM);
230
231
if
(ret < 0) {
232
av_frame_free
(&buf_out);
233
av_frame_free
(&buf);
234
return
ret
;
235
}
236
237
s->
dup
++;
238
}
239
240
buf_out->
pts
=
av_rescale_q
(s->
first_pts
, inlink->
time_base
,
241
outlink->
time_base
) + s->
frames_out
;
242
243
if
((ret =
ff_filter_frame
(outlink, buf_out)) < 0) {
244
av_frame_free
(&buf);
245
return
ret
;
246
}
247
248
s->
frames_out
++;
249
}
250
flush_fifo
(s->
fifo
);
251
252
ret =
write_to_fifo
(s->
fifo
, buf);
253
s->
pts
= s->
first_pts
+
av_rescale_q
(s->
frames_out
, outlink->
time_base
, inlink->
time_base
);
254
255
return
ret
;
256
}
257
258
static
const
AVFilterPad
avfilter_vf_fps_inputs
[] = {
259
{
260
.
name
=
"default"
,
261
.type =
AVMEDIA_TYPE_VIDEO
,
262
.filter_frame =
filter_frame
,
263
},
264
{ NULL }
265
};
266
267
static
const
AVFilterPad
avfilter_vf_fps_outputs
[] = {
268
{
269
.
name
=
"default"
,
270
.type =
AVMEDIA_TYPE_VIDEO
,
271
.request_frame =
request_frame
,
272
.config_props =
config_props
273
},
274
{ NULL }
275
};
276
277
AVFilter
avfilter_vf_fps
= {
278
.
name
=
"fps"
,
279
.description =
NULL_IF_CONFIG_SMALL
(
"Force constant framerate."
),
280
281
.init =
init
,
282
.uninit =
uninit
,
283
284
.priv_size =
sizeof
(
FPSContext
),
285
.priv_class = &fps_class,
286
287
.
inputs
= avfilter_vf_fps_inputs,
288
.
outputs
= avfilter_vf_fps_outputs,
289
};
Generated on Wed Jul 10 2013 23:48:10 for FFmpeg by
1.8.2