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