Libav
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 "libavutil/opt.h"
31 #include "avfilter.h"
32 #include "internal.h"
33 #include "video.h"
34 
35 static const char *const var_names[] = {
36  "E",
37  "PHI",
38  "PI",
39 
40  "TB",
41 
42  "pts",
43  "start_pts",
44  "prev_pts",
45  "prev_selected_pts",
46 
47  "t",
48  "start_t",
49  "prev_t",
50  "prev_selected_t",
51 
52  "pict_type",
53  "I",
54  "P",
55  "B",
56  "S",
57  "SI",
58  "SP",
59  "BI",
60 
61  "interlace_type",
62  "PROGRESSIVE",
63  "TOPFIRST",
64  "BOTTOMFIRST",
65 
66  "n",
67  "selected_n",
68  "prev_selected_n",
69 
70  "key",
71  "pos",
72 
73  NULL
74 };
75 
76 enum var_name {
80 
82 
87 
92 
101 
106 
110 
112 
114 };
115 
116 #define FIFO_SIZE 8
117 
118 typedef struct SelectContext {
119  const AVClass *class;
120  char *expr_str;
123  double select;
126 } SelectContext;
127 
128 static av_cold int init(AVFilterContext *ctx)
129 {
130  SelectContext *select = ctx->priv;
131  int ret;
132 
133  if ((ret = av_expr_parse(&select->expr, select->expr_str,
134  var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
135  av_log(ctx, AV_LOG_ERROR, "Error while parsing expression '%s'\n",
136  select->expr_str);
137  return ret;
138  }
139 
140  select->pending_frames = av_fifo_alloc(FIFO_SIZE*sizeof(AVFrame*));
141  if (!select->pending_frames) {
142  av_log(ctx, AV_LOG_ERROR, "Failed to allocate pending frames buffer.\n");
143  return AVERROR(ENOMEM);
144  }
145  return 0;
146 }
147 
148 #define INTERLACE_TYPE_P 0
149 #define INTERLACE_TYPE_T 1
150 #define INTERLACE_TYPE_B 2
151 
152 static int config_input(AVFilterLink *inlink)
153 {
154  SelectContext *select = inlink->dst->priv;
155 
156  select->var_values[VAR_E] = M_E;
157  select->var_values[VAR_PHI] = M_PHI;
158  select->var_values[VAR_PI] = M_PI;
159 
160  select->var_values[VAR_N] = 0.0;
161  select->var_values[VAR_SELECTED_N] = 0.0;
162 
163  select->var_values[VAR_TB] = av_q2d(inlink->time_base);
164 
165  select->var_values[VAR_PREV_PTS] = NAN;
168  select->var_values[VAR_START_PTS] = NAN;
169  select->var_values[VAR_START_T] = NAN;
170 
176 
180 
181  return 0;
182 }
183 
184 #define D2TS(d) (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d))
185 #define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts))
186 
187 static int select_frame(AVFilterContext *ctx, AVFrame *frame)
188 {
189  SelectContext *select = ctx->priv;
190  AVFilterLink *inlink = ctx->inputs[0];
191  double res;
192 
193  if (isnan(select->var_values[VAR_START_PTS]))
194  select->var_values[VAR_START_PTS] = TS2D(frame->pts);
195  if (isnan(select->var_values[VAR_START_T]))
196  select->var_values[VAR_START_T] = TS2D(frame->pts) * av_q2d(inlink->time_base);
197 
198  select->var_values[VAR_PTS] = TS2D(frame->pts);
199  select->var_values[VAR_T ] = TS2D(frame->pts) * av_q2d(inlink->time_base);
200  select->var_values[VAR_PREV_PTS] = TS2D(frame->pts);
201 
202  select->var_values[VAR_INTERLACE_TYPE] =
205  select->var_values[VAR_PICT_TYPE] = frame->pict_type;
206 
207  res = av_expr_eval(select->expr, select->var_values, NULL);
208 
209  select->var_values[VAR_N] += 1.0;
210 
211  if (res) {
212  select->var_values[VAR_PREV_SELECTED_N] = select->var_values[VAR_N];
214  select->var_values[VAR_PREV_SELECTED_T] = select->var_values[VAR_T];
215  select->var_values[VAR_SELECTED_N] += 1.0;
216  }
217  return res;
218 }
219 
220 static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
221 {
222  SelectContext *select = inlink->dst->priv;
223 
224  select->select = select_frame(inlink->dst, frame);
225  if (select->select) {
226  /* frame was requested through poll_frame */
227  if (select->cache_frames) {
228  if (!av_fifo_space(select->pending_frames)) {
229  av_log(inlink->dst, AV_LOG_ERROR,
230  "Buffering limit reached, cannot cache more frames\n");
231  av_frame_free(&frame);
232  } else
233  av_fifo_generic_write(select->pending_frames, &frame,
234  sizeof(frame), NULL);
235  return 0;
236  }
237  return ff_filter_frame(inlink->dst->outputs[0], frame);
238  }
239 
240  av_frame_free(&frame);
241  return 0;
242 }
243 
244 static int request_frame(AVFilterLink *outlink)
245 {
246  AVFilterContext *ctx = outlink->src;
247  SelectContext *select = ctx->priv;
248  AVFilterLink *inlink = outlink->src->inputs[0];
249  select->select = 0;
250 
251  if (av_fifo_size(select->pending_frames)) {
252  AVFrame *frame;
253 
254  av_fifo_generic_read(select->pending_frames, &frame, sizeof(frame), NULL);
255  return ff_filter_frame(outlink, frame);
256  }
257 
258  while (!select->select) {
259  int ret = ff_request_frame(inlink);
260  if (ret < 0)
261  return ret;
262  }
263 
264  return 0;
265 }
266 
267 static int poll_frame(AVFilterLink *outlink)
268 {
269  SelectContext *select = outlink->src->priv;
270  AVFilterLink *inlink = outlink->src->inputs[0];
271  int count, ret;
272 
273  if (!av_fifo_size(select->pending_frames)) {
274  if ((count = ff_poll_frame(inlink)) <= 0)
275  return count;
276  /* request frame from input, and apply select condition to it */
277  select->cache_frames = 1;
278  while (count-- && av_fifo_space(select->pending_frames)) {
279  ret = ff_request_frame(inlink);
280  if (ret < 0)
281  break;
282  }
283  select->cache_frames = 0;
284  }
285 
286  return av_fifo_size(select->pending_frames)/sizeof(AVFrame*);
287 }
288 
289 static av_cold void uninit(AVFilterContext *ctx)
290 {
291  SelectContext *select = ctx->priv;
292  AVFrame *frame;
293 
294  av_expr_free(select->expr);
295  select->expr = NULL;
296 
297  while (select->pending_frames &&
298  av_fifo_generic_read(select->pending_frames, &frame, sizeof(frame), NULL) == sizeof(frame))
299  av_frame_free(&frame);
300  av_fifo_free(select->pending_frames);
301  select->pending_frames = NULL;
302 }
303 
304 #define OFFSET(x) offsetof(SelectContext, x)
305 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM
306 static const AVOption options[] = {
307  { "expr", "An expression to use for selecting frames", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "1" }, .flags = FLAGS },
308  { NULL },
309 };
310 
311 static const AVClass select_class = {
312  .class_name = "select",
313  .item_name = av_default_item_name,
314  .option = options,
315  .version = LIBAVUTIL_VERSION_INT,
316 };
317 
319  {
320  .name = "default",
321  .type = AVMEDIA_TYPE_VIDEO,
322  .get_video_buffer = ff_null_get_video_buffer,
323  .config_props = config_input,
324  .filter_frame = filter_frame,
325  },
326  { NULL }
327 };
328 
330  {
331  .name = "default",
332  .type = AVMEDIA_TYPE_VIDEO,
333  .poll_frame = poll_frame,
334  .request_frame = request_frame,
335  },
336  { NULL }
337 };
338 
340  .name = "select",
341  .description = NULL_IF_CONFIG_SMALL("Select frames to pass in output."),
342  .init = init,
343  .uninit = uninit,
344 
345  .priv_size = sizeof(SelectContext),
346  .priv_class = &select_class,
347 
348  .inputs = avfilter_vf_select_inputs,
349  .outputs = avfilter_vf_select_outputs,
350 };
static const char *const var_names[]
Definition: vf_select.c:35
This structure describes decoded (raw) audio or video data.
Definition: frame.h:135
AVOption.
Definition: opt.h:234
static const AVFilterPad outputs[]
Definition: af_ashowinfo.c:232
Main libavfilter public API header.
static int config_input(AVFilterLink *inlink)
Definition: vf_select.c:152
AVFrame * ff_null_get_video_buffer(AVFilterLink *link, int w, int h)
Definition: video.c:30
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:492
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:84
Switching Intra.
Definition: avutil.h:257
const char * name
Pad name.
Definition: internal.h:42
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:38
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:571
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:733
#define av_cold
Definition: attributes.h:66
AVOptions.
static av_always_inline av_const int isnan(float x)
Definition: libm.h:85
static const AVOption options[]
Definition: vf_select.c:306
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:211
Definition: eval.c:128
char * expr_str
Definition: vf_select.c:120
static double av_q2d(AVRational a)
Convert rational to double.
Definition: rational.h:69
void av_fifo_free(AVFifoBuffer *f)
Free an AVFifoBuffer.
Definition: fifo.c:38
#define INTERLACE_TYPE_P
Definition: vf_select.c:148
int interlaced_frame
The content of the picture is interlaced.
Definition: frame.h:320
A filter pad used for either input or output.
Definition: internal.h:36
#define FLAGS
Definition: vf_select.c:305
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:123
static const AVFilterPad avfilter_vf_select_outputs[]
Definition: vf_select.c:329
double var_values[VAR_VARS_NB]
Definition: vf_select.c:122
#define AVERROR(e)
Definition: error.h:43
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
Definition: vf_select.c:220
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:69
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:150
void * priv
private data for use by the filter
Definition: avfilter.h:584
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:107
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:168
common internal API header
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:196
#define M_E
Definition: ratecontrol.c:39
#define OFFSET(x)
Definition: vf_select.c:304
LIBAVUTIL_VERSION_INT
Definition: eval.c:55
static const AVFilterPad avfilter_vf_select_inputs[]
Definition: vf_select.c:318
NULL
Definition: eval.c:55
static int poll_frame(AVFilterLink *outlink)
Definition: vf_select.c:267
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:195
static av_cold int init(AVFilterContext *ctx)
Definition: vf_select.c:128
av_default_item_name
Definition: dnxhdenc.c:52
a very simple circular buffer FIFO implementation
Switching Predicted.
Definition: avutil.h:258
Describe the class of an AVClass context structure.
Definition: log.h:33
Filter definition.
Definition: avfilter.h:421
static const AVFilterPad inputs[]
Definition: af_ashowinfo.c:221
#define M_PHI
Definition: mathematics.h:34
static int select_frame(AVFilterContext *ctx, AVFrame *frame)
Definition: vf_select.c:187
const char * name
Filter name.
Definition: avfilter.h:425
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:578
#define INTERLACE_TYPE_B
Definition: vf_select.c:150
static const AVClass select_class
Definition: vf_select.c:311
#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
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_select.c:289
Bi-dir predicted.
Definition: avutil.h:255
AVFifoBuffer * pending_frames
FIFO buffer of video frames.
Definition: vf_select.c:125
static int request_frame(AVFilterLink *outlink)
Definition: vf_select.c:244
AVFifoBuffer * av_fifo_alloc(unsigned int size)
Initialize an AVFifoBuffer.
Definition: fifo.c:25
int top_field_first
If the content is interlaced, is top field displayed first.
Definition: frame.h:325
#define NAN
Definition: math.h:28
double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
Evaluate a previously parsed expression.
Definition: eval.c:542
AVExpr * expr
Definition: vf_select.c:121
An instance of a filter.
Definition: avfilter.h:563
#define INTERLACE_TYPE_T
Definition: vf_select.c:149
int ff_request_frame(AVFilterLink *link)
Request an input frame from the filter at the other end of the link.
Definition: avfilter.c:249
internal API functions
int cache_frames
Definition: vf_select.c:124
int ff_poll_frame(AVFilterLink *link)
Poll a frame from the filter chain.
Definition: avfilter.c:260
double select
Definition: vf_select.c:123
var_name
Definition: setpts.c:60
Predicted.
Definition: avutil.h:254
simple arithmetic expression evaluator
#define TS2D(ts)
Definition: vf_select.c:185
AVFilter ff_vf_select
Definition: vf_select.c:339