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 {
79 
81 
86 
91 
100 
105 
109 
112 
114 };
115 
116 #define FIFO_SIZE 8
117 
118 typedef struct {
120  double var_values[VAR_VARS_NB];
121  double select;
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 
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;
165  select->var_values[VAR_START_PTS] = NAN;
166  select->var_values[VAR_START_T] = NAN;
167 
173 
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 
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 :
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],
215  select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_B ? 'B' : '?',
216  (int)select->var_values[VAR_KEY],
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];
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 
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 
327  {
328  .name = "default",
329  .type = AVMEDIA_TYPE_VIDEO,
330  .poll_frame = poll_frame,
331  .request_frame = request_frame,
332  },
333  { NULL }
334 };
335 
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 };
static const char *const var_names[]
Definition: vf_select.c:34
AVFilterBufferRefVideoProps * video
video buffer specific properties
Definition: avfilter.h:159
static int select_frame(AVFilterContext *ctx, AVFilterBufferRef *picref)
Definition: vf_select.c:184
static const AVFilterPad outputs[]
Definition: af_ashowinfo.c:122
int ff_filter_frame(AVFilterLink *link, AVFilterBufferRef *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:459
static int config_input(AVFilterLink *inlink)
Definition: vf_select.c:149
int av_expr_parse(AVExpr **expr, const char *s, const char *const *const_names, const char *const *func1_names, double(*const *funcs1)(void *, double), const char *const *func2_names, double(*const *funcs2)(void *, double, double), int log_offset, void *log_ctx)
Parse an expression.
Definition: eval.c:489
int av_fifo_generic_write(AVFifoBuffer *f, void *src, int size, int(*func)(void *, void *, int))
Feed data from a user-supplied callback to an AVFifoBuffer.
Definition: fifo.c:82
void avfilter_unref_buffer(AVFilterBufferRef *ref)
Remove a reference to a buffer.
Definition: buffer.c:75
Switching Intra.
Definition: avutil.h:249
const char * name
Pad name.
Definition: internal.h:39
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:426
int top_field_first
field order
Definition: avfilter.h:126
static av_always_inline av_const int isnan(float x)
Definition: libm.h:85
#define NAN
Definition: math.h:7
AVFilter avfilter_vf_select
Definition: vf_select.c:336
Definition: eval.c:125
void avfilter_unref_bufferp(AVFilterBufferRef **ref)
Remove a reference to a buffer and set the pointer to NULL.
Definition: buffer.c:88
static double av_q2d(AVRational a)
Convert rational to double.
Definition: rational.h:69
char av_get_picture_type_char(enum AVPictureType pict_type)
Return a single letter to describe the given picture type pict_type.
Definition: utils.c:43
void av_fifo_free(AVFifoBuffer *f)
Free an AVFifoBuffer.
Definition: fifo.c:38
#define INTERLACE_TYPE_P
Definition: vf_select.c:145
var_name
Definition: vf_boxblur.c:47
int64_t pts
presentation timestamp.
Definition: avfilter.h:167
A filter pad used for either input or output.
Definition: internal.h:33
static const AVFilterPad avfilter_vf_select_outputs[]
Definition: vf_select.c:326
double var_values[VAR_VARS_NB]
Definition: vf_select.c:120
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:88
void * priv
private data for use by the filter
Definition: avfilter.h:439
int av_fifo_generic_read(AVFifoBuffer *f, void *dest, int buf_size, void(*func)(void *, void *, int))
Feed data from an AVFifoBuffer to a user-supplied callback.
Definition: fifo.c:105
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:146
common internal API header
#define M_E
Definition: ratecontrol.c:39
static const AVFilterPad avfilter_vf_select_inputs[]
Definition: vf_select.c:315
A reference to an AVFilterBuffer.
Definition: avfilter.h:139
NULL
Definition: eval.c:52
static int poll_frame(AVFilterLink *outlink)
Definition: vf_select.c:278
int av_fifo_space(AVFifoBuffer *f)
Return the amount of space in bytes in the AVFifoBuffer, that is the amount of data you can write int...
Definition: fifo.c:57
void av_expr_free(AVExpr *e)
Free a parsed expression previously created with av_expr_parse().
Definition: eval.c:192
a very simple circular buffer FIFO implementation
static av_cold int init(AVFilterContext *ctx, const char *args)
Definition: vf_select.c:126
enum AVPictureType pict_type
picture type of the frame
Definition: avfilter.h:127
Switching Predicted.
Definition: avutil.h:250
Filter definition.
Definition: avfilter.h:371
static const AVFilterPad inputs[]
Definition: af_ashowinfo.c:110
#define M_PHI
Definition: mathematics.h:34
const char * name
filter name
Definition: avfilter.h:372
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:433
#define INTERLACE_TYPE_B
Definition: vf_select.c:147
#define FIFO_SIZE
Definition: vf_select.c:116
int av_fifo_size(AVFifoBuffer *f)
Return the amount of data in bytes in the AVFifoBuffer, that is the amount of data you can read from ...
Definition: fifo.c:52
int interlaced
is frame interlaced
Definition: avfilter.h:125
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_select.c:300
Bi-dir predicted.
Definition: avutil.h:247
AVFifoBuffer * pending_frames
FIFO buffer of video frames.
Definition: vf_select.c:123
static int request_frame(AVFilterLink *outlink)
Definition: vf_select.c:255
int64_t pos
byte position in stream, -1 if unknown
Definition: avfilter.h:168
AVFifoBuffer * av_fifo_alloc(unsigned int size)
Initialize an AVFifoBuffer.
Definition: fifo.c:25
double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
Evaluate a previously parsed expression.
Definition: eval.c:539
AVExpr * expr
Definition: vf_select.c:119
An instance of a filter.
Definition: avfilter.h:418
#define INTERLACE_TYPE_T
Definition: vf_select.c:146
int ff_request_frame(AVFilterLink *link)
Request an input frame from the filter at the other end of the link.
Definition: avfilter.c:239
internal API functions
int cache_frames
Definition: vf_select.c:122
int ff_poll_frame(AVFilterLink *link)
Poll a frame from the filter chain.
Definition: avfilter.c:250
AVFilterBufferRef * ff_null_get_video_buffer(AVFilterLink *link, int perms, int w, int h)
Definition: video.c:72
double select
Definition: vf_select.c:121
static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
Definition: vf_select.c:231
Predicted.
Definition: avutil.h:246
simple arithmetic expression evaluator
#define TS2D(ts)
Definition: vf_select.c:182