Main Page
Related Pages
Modules
Data Structures
Files
Examples
File List
Globals
libavfilter
vf_select.c
Go to the documentation of this file.
1
/*
2
* Copyright (c) 2011 Stefano Sabatini
3
*
4
* This file is part of Libav.
5
*
6
* Libav is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
10
*
11
* Libav is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
15
*
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with Libav; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
*/
20
26
#include "
libavutil/eval.h
"
27
#include "
libavutil/fifo.h
"
28
#include "
libavutil/internal.h
"
29
#include "
libavutil/mathematics.h
"
30
#include "
avfilter.h
"
31
#include "
internal.h
"
32
#include "
video.h
"
33
34
static
const
char
*
const
var_names
[] = {
35
"E"
,
36
"PHI"
,
37
"PI"
,
38
39
"TB"
,
40
41
"pts"
,
42
"start_pts"
,
43
"prev_pts"
,
44
"prev_selected_pts"
,
45
46
"t"
,
47
"start_t"
,
48
"prev_t"
,
49
"prev_selected_t"
,
50
51
"pict_type"
,
52
"I"
,
53
"P"
,
54
"B"
,
55
"S"
,
56
"SI"
,
57
"SP"
,
58
"BI"
,
59
60
"interlace_type"
,
61
"PROGRESSIVE"
,
62
"TOPFIRST"
,
63
"BOTTOMFIRST"
,
64
65
"n"
,
66
"selected_n"
,
67
"prev_selected_n"
,
68
69
"key"
,
70
"pos"
,
71
72
NULL
73
};
74
75
enum
var_name
{
76
VAR_E
,
77
VAR_PHI
,
78
VAR_PI
,
79
80
VAR_TB
,
81
82
VAR_PTS
,
83
VAR_START_PTS
,
84
VAR_PREV_PTS
,
85
VAR_PREV_SELECTED_PTS
,
86
87
VAR_T
,
88
VAR_START_T
,
89
VAR_PREV_T
,
90
VAR_PREV_SELECTED_T
,
91
92
VAR_PICT_TYPE
,
93
VAR_PICT_TYPE_I
,
94
VAR_PICT_TYPE_P
,
95
VAR_PICT_TYPE_B
,
96
VAR_PICT_TYPE_S
,
97
VAR_PICT_TYPE_SI
,
98
VAR_PICT_TYPE_SP
,
99
VAR_PICT_TYPE_BI
,
100
101
VAR_INTERLACE_TYPE
,
102
VAR_INTERLACE_TYPE_P
,
103
VAR_INTERLACE_TYPE_T
,
104
VAR_INTERLACE_TYPE_B
,
105
106
VAR_N
,
107
VAR_SELECTED_N
,
108
VAR_PREV_SELECTED_N
,
109
110
VAR_KEY
,
111
VAR_POS
,
112
113
VAR_VARS_NB
114
};
115
116
#define FIFO_SIZE 8
117
118
typedef
struct
{
119
AVExpr
*
expr
;
120
double
var_values[
VAR_VARS_NB
];
121
double
select
;
122
int
cache_frames
;
123
AVFifoBuffer
*
pending_frames
;
124
}
SelectContext
;
125
126
static
av_cold
int
init
(
AVFilterContext
*ctx,
const
char
*args)
127
{
128
SelectContext
*select = ctx->
priv
;
129
int
ret;
130
131
if
((ret =
av_expr_parse
(&select->
expr
, args ? args :
"1"
,
132
var_names
,
NULL
,
NULL
,
NULL
,
NULL
, 0, ctx)) < 0) {
133
av_log
(ctx,
AV_LOG_ERROR
,
"Error while parsing expression '%s'\n"
, args);
134
return
ret;
135
}
136
137
select->
pending_frames
=
av_fifo_alloc
(
FIFO_SIZE
*
sizeof
(
AVFilterBufferRef
*));
138
if
(!select->
pending_frames
) {
139
av_log
(ctx,
AV_LOG_ERROR
,
"Failed to allocate pending frames buffer.\n"
);
140
return
AVERROR
(ENOMEM);
141
}
142
return
0;
143
}
144
145
#define INTERLACE_TYPE_P 0
146
#define INTERLACE_TYPE_T 1
147
#define INTERLACE_TYPE_B 2
148
149
static
int
config_input
(
AVFilterLink
*inlink)
150
{
151
SelectContext
*select = inlink->
dst
->
priv
;
152
153
select->
var_values
[
VAR_E
] =
M_E
;
154
select->
var_values
[
VAR_PHI
] =
M_PHI
;
155
select->
var_values
[
VAR_PI
] = M_PI;
156
157
select->
var_values
[
VAR_N
] = 0.0;
158
select->
var_values
[
VAR_SELECTED_N
] = 0.0;
159
160
select->
var_values
[
VAR_TB
] =
av_q2d
(inlink->
time_base
);
161
162
select->
var_values
[
VAR_PREV_PTS
] =
NAN
;
163
select->
var_values
[
VAR_PREV_SELECTED_PTS
] =
NAN
;
164
select->
var_values
[
VAR_PREV_SELECTED_T
] =
NAN
;
165
select->
var_values
[
VAR_START_PTS
] =
NAN
;
166
select->
var_values
[
VAR_START_T
] =
NAN
;
167
168
select->
var_values
[
VAR_PICT_TYPE_I
] =
AV_PICTURE_TYPE_I
;
169
select->
var_values
[
VAR_PICT_TYPE_P
] =
AV_PICTURE_TYPE_P
;
170
select->
var_values
[
VAR_PICT_TYPE_B
] =
AV_PICTURE_TYPE_B
;
171
select->
var_values
[
VAR_PICT_TYPE_SI
] =
AV_PICTURE_TYPE_SI
;
172
select->
var_values
[
VAR_PICT_TYPE_SP
] =
AV_PICTURE_TYPE_SP
;
173
174
select->
var_values
[
VAR_INTERLACE_TYPE_P
] =
INTERLACE_TYPE_P
;
175
select->
var_values
[
VAR_INTERLACE_TYPE_T
] =
INTERLACE_TYPE_T
;
176
select->
var_values
[
VAR_INTERLACE_TYPE_B
] =
INTERLACE_TYPE_B
;;
177
178
return
0;
179
}
180
181
#define D2TS(d) (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d))
182
#define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts))
183
184
static
int
select_frame
(
AVFilterContext
*ctx,
AVFilterBufferRef
*picref)
185
{
186
SelectContext
*select = ctx->
priv
;
187
AVFilterLink
*inlink = ctx->
inputs
[0];
188
double
res;
189
190
if
(
isnan
(select->
var_values
[
VAR_START_PTS
]))
191
select->
var_values
[
VAR_START_PTS
] =
TS2D
(picref->
pts
);
192
if
(
isnan
(select->
var_values
[
VAR_START_T
]))
193
select->
var_values
[
VAR_START_T
] =
TS2D
(picref->
pts
) *
av_q2d
(inlink->
time_base
);
194
195
select->
var_values
[
VAR_PTS
] =
TS2D
(picref->
pts
);
196
select->
var_values
[
VAR_T
] =
TS2D
(picref->
pts
) *
av_q2d
(inlink->
time_base
);
197
select->
var_values
[
VAR_POS
] = picref->
pos
== -1 ?
NAN
: picref->
pos
;
198
select->
var_values
[
VAR_PREV_PTS
] =
TS2D
(picref ->pts);
199
200
select->
var_values
[
VAR_INTERLACE_TYPE
] =
201
!picref->
video
->
interlaced
?
INTERLACE_TYPE_P
:
202
picref->
video
->
top_field_first
?
INTERLACE_TYPE_T
:
INTERLACE_TYPE_B
;
203
select->
var_values
[
VAR_PICT_TYPE
] = picref->
video
->
pict_type
;
204
205
res =
av_expr_eval
(select->
expr
, select->
var_values
,
NULL
);
206
av_log
(inlink->
dst
,
AV_LOG_DEBUG
,
207
"n:%d pts:%d t:%f pos:%d interlace_type:%c key:%d pict_type:%c "
208
"-> select:%f\n"
,
209
(
int
)select->
var_values
[
VAR_N
],
210
(
int
)select->
var_values
[
VAR_PTS
],
211
select->
var_values
[
VAR_T
],
212
(
int
)select->
var_values
[
VAR_POS
],
213
select->
var_values
[
VAR_INTERLACE_TYPE
] ==
INTERLACE_TYPE_P
?
'P'
:
214
select->
var_values
[
VAR_INTERLACE_TYPE
] ==
INTERLACE_TYPE_T
?
'T'
:
215
select->
var_values
[
VAR_INTERLACE_TYPE
] ==
INTERLACE_TYPE_B
?
'B'
:
'?'
,
216
(
int
)select->
var_values
[
VAR_KEY
],
217
av_get_picture_type_char
(select->
var_values
[
VAR_PICT_TYPE
]),
218
res);
219
220
select->
var_values
[
VAR_N
] += 1.0;
221
222
if
(res) {
223
select->
var_values
[
VAR_PREV_SELECTED_N
] = select->
var_values
[
VAR_N
];
224
select->
var_values
[
VAR_PREV_SELECTED_PTS
] = select->
var_values
[
VAR_PTS
];
225
select->
var_values
[
VAR_PREV_SELECTED_T
] = select->
var_values
[
VAR_T
];
226
select->
var_values
[
VAR_SELECTED_N
] += 1.0;
227
}
228
return
res;
229
}
230
231
static
int
filter_frame
(
AVFilterLink
*inlink,
AVFilterBufferRef
*frame)
232
{
233
SelectContext
*select = inlink->
dst
->
priv
;
234
235
select->
select
=
select_frame
(inlink->
dst
, frame);
236
if
(select->
select
) {
237
/* frame was requested through poll_frame */
238
if
(select->
cache_frames
) {
239
if
(!
av_fifo_space
(select->
pending_frames
)) {
240
av_log
(inlink->
dst
,
AV_LOG_ERROR
,
241
"Buffering limit reached, cannot cache more frames\n"
);
242
avfilter_unref_bufferp
(&frame);
243
}
else
244
av_fifo_generic_write
(select->
pending_frames
, &frame,
245
sizeof
(frame),
NULL
);
246
return
0;
247
}
248
return
ff_filter_frame
(inlink->
dst
->
outputs
[0], frame);
249
}
250
251
avfilter_unref_bufferp
(&frame);
252
return
0;
253
}
254
255
static
int
request_frame
(
AVFilterLink
*outlink)
256
{
257
AVFilterContext
*ctx = outlink->
src
;
258
SelectContext
*select = ctx->
priv
;
259
AVFilterLink
*inlink = outlink->
src
->
inputs
[0];
260
select->
select
= 0;
261
262
if
(
av_fifo_size
(select->
pending_frames
)) {
263
AVFilterBufferRef
*picref;
264
265
av_fifo_generic_read
(select->
pending_frames
, &picref,
sizeof
(picref),
NULL
);
266
return
ff_filter_frame
(outlink, picref);
267
}
268
269
while
(!select->
select
) {
270
int
ret =
ff_request_frame
(inlink);
271
if
(ret < 0)
272
return
ret;
273
}
274
275
return
0;
276
}
277
278
static
int
poll_frame
(
AVFilterLink
*outlink)
279
{
280
SelectContext
*select = outlink->
src
->
priv
;
281
AVFilterLink
*inlink = outlink->
src
->
inputs
[0];
282
int
count, ret;
283
284
if
(!
av_fifo_size
(select->
pending_frames
)) {
285
if
((count =
ff_poll_frame
(inlink)) <= 0)
286
return
count;
287
/* request frame from input, and apply select condition to it */
288
select->
cache_frames
= 1;
289
while
(count-- &&
av_fifo_space
(select->
pending_frames
)) {
290
ret =
ff_request_frame
(inlink);
291
if
(ret < 0)
292
break
;
293
}
294
select->
cache_frames
= 0;
295
}
296
297
return
av_fifo_size
(select->
pending_frames
)/
sizeof
(
AVFilterBufferRef
*);
298
}
299
300
static
av_cold
void
uninit
(
AVFilterContext
*ctx)
301
{
302
SelectContext
*select = ctx->
priv
;
303
AVFilterBufferRef
*picref;
304
305
av_expr_free
(select->
expr
);
306
select->
expr
=
NULL
;
307
308
while
(select->
pending_frames
&&
309
av_fifo_generic_read
(select->
pending_frames
, &picref,
sizeof
(picref),
NULL
) ==
sizeof
(picref))
310
avfilter_unref_buffer
(picref);
311
av_fifo_free
(select->
pending_frames
);
312
select->
pending_frames
=
NULL
;
313
}
314
315
static
const
AVFilterPad
avfilter_vf_select_inputs
[] = {
316
{
317
.
name
=
"default"
,
318
.type =
AVMEDIA_TYPE_VIDEO
,
319
.get_video_buffer =
ff_null_get_video_buffer
,
320
.config_props =
config_input
,
321
.filter_frame =
filter_frame
,
322
},
323
{
NULL
}
324
};
325
326
static
const
AVFilterPad
avfilter_vf_select_outputs
[] = {
327
{
328
.
name
=
"default"
,
329
.type =
AVMEDIA_TYPE_VIDEO
,
330
.poll_frame =
poll_frame
,
331
.request_frame =
request_frame
,
332
},
333
{
NULL
}
334
};
335
336
AVFilter
avfilter_vf_select
= {
337
.
name
=
"select"
,
338
.description =
NULL_IF_CONFIG_SMALL
(
"Select frames to pass in output."
),
339
.init =
init
,
340
.uninit =
uninit
,
341
342
.priv_size =
sizeof
(
SelectContext
),
343
344
.
inputs
= avfilter_vf_select_inputs,
345
.
outputs
= avfilter_vf_select_outputs,
346
};