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 {
119  const AVClass *class;
120  char *expr_str;
122  double var_values[VAR_VARS_NB];
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  av_log(inlink->dst, AV_LOG_DEBUG,
209  "n:%d pts:%d t:%f interlace_type:%c key:%d pict_type:%c "
210  "-> select:%f\n",
211  (int)select->var_values[VAR_N],
212  (int)select->var_values[VAR_PTS],
213  select->var_values[VAR_T],
216  select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_B ? 'B' : '?',
217  (int)select->var_values[VAR_KEY],
219  res);
220 
221  select->var_values[VAR_N] += 1.0;
222 
223  if (res) {
224  select->var_values[VAR_PREV_SELECTED_N] = select->var_values[VAR_N];
226  select->var_values[VAR_PREV_SELECTED_T] = select->var_values[VAR_T];
227  select->var_values[VAR_SELECTED_N] += 1.0;
228  }
229  return res;
230 }
231 
232 static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
233 {
234  SelectContext *select = inlink->dst->priv;
235 
236  select->select = select_frame(inlink->dst, frame);
237  if (select->select) {
238  /* frame was requested through poll_frame */
239  if (select->cache_frames) {
240  if (!av_fifo_space(select->pending_frames)) {
241  av_log(inlink->dst, AV_LOG_ERROR,
242  "Buffering limit reached, cannot cache more frames\n");
243  av_frame_free(&frame);
244  } else
245  av_fifo_generic_write(select->pending_frames, &frame,
246  sizeof(frame), NULL);
247  return 0;
248  }
249  return ff_filter_frame(inlink->dst->outputs[0], frame);
250  }
251 
252  av_frame_free(&frame);
253  return 0;
254 }
255 
256 static int request_frame(AVFilterLink *outlink)
257 {
258  AVFilterContext *ctx = outlink->src;
259  SelectContext *select = ctx->priv;
260  AVFilterLink *inlink = outlink->src->inputs[0];
261  select->select = 0;
262 
263  if (av_fifo_size(select->pending_frames)) {
264  AVFrame *frame;
265 
266  av_fifo_generic_read(select->pending_frames, &frame, sizeof(frame), NULL);
267  return ff_filter_frame(outlink, frame);
268  }
269 
270  while (!select->select) {
271  int ret = ff_request_frame(inlink);
272  if (ret < 0)
273  return ret;
274  }
275 
276  return 0;
277 }
278 
279 static int poll_frame(AVFilterLink *outlink)
280 {
281  SelectContext *select = outlink->src->priv;
282  AVFilterLink *inlink = outlink->src->inputs[0];
283  int count, ret;
284 
285  if (!av_fifo_size(select->pending_frames)) {
286  if ((count = ff_poll_frame(inlink)) <= 0)
287  return count;
288  /* request frame from input, and apply select condition to it */
289  select->cache_frames = 1;
290  while (count-- && av_fifo_space(select->pending_frames)) {
291  ret = ff_request_frame(inlink);
292  if (ret < 0)
293  break;
294  }
295  select->cache_frames = 0;
296  }
297 
298  return av_fifo_size(select->pending_frames)/sizeof(AVFrame*);
299 }
300 
301 static av_cold void uninit(AVFilterContext *ctx)
302 {
303  SelectContext *select = ctx->priv;
304  AVFrame *frame;
305 
306  av_expr_free(select->expr);
307  select->expr = NULL;
308 
309  while (select->pending_frames &&
310  av_fifo_generic_read(select->pending_frames, &frame, sizeof(frame), NULL) == sizeof(frame))
311  av_frame_free(&frame);
312  av_fifo_free(select->pending_frames);
313  select->pending_frames = NULL;
314 }
315 
316 #define OFFSET(x) offsetof(SelectContext, x)
317 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM
318 static const AVOption options[] = {
319  { "expr", "An expression to use for selecting frames", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "1" }, .flags = FLAGS },
320  { NULL },
321 };
322 
323 static const AVClass select_class = {
324  .class_name = "select",
325  .item_name = av_default_item_name,
326  .option = options,
327  .version = LIBAVUTIL_VERSION_INT,
328 };
329 
331  {
332  .name = "default",
333  .type = AVMEDIA_TYPE_VIDEO,
334  .get_video_buffer = ff_null_get_video_buffer,
335  .config_props = config_input,
336  .filter_frame = filter_frame,
337  },
338  { NULL }
339 };
340 
342  {
343  .name = "default",
344  .type = AVMEDIA_TYPE_VIDEO,
345  .poll_frame = poll_frame,
346  .request_frame = request_frame,
347  },
348  { NULL }
349 };
350 
352  .name = "select",
353  .description = NULL_IF_CONFIG_SMALL("Select frames to pass in output."),
354  .init = init,
355  .uninit = uninit,
356 
357  .priv_size = sizeof(SelectContext),
358  .priv_class = &select_class,
359 
360  .inputs = avfilter_vf_select_inputs,
361  .outputs = avfilter_vf_select_outputs,
362 };
static const char *const var_names[]
Definition: vf_select.c:35
This structure describes decoded (raw) audio or video data.
Definition: frame.h:107
AVOption.
Definition: opt.h:233
static const AVFilterPad outputs[]
Definition: af_ashowinfo.c:122
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:728
#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:318
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:183
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
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:148
int interlaced_frame
The content of the picture is interlaced.
Definition: frame.h:292
A filter pad used for either input or output.
Definition: internal.h:36
#define FLAGS
Definition: vf_select.c:317
#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:341
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:232
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:55
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:142
void * priv
private data for use by the filter
Definition: avfilter.h:584
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:144
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:148
common internal API header
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:168
#define M_E
Definition: ratecontrol.c:38
#define OFFSET(x)
Definition: vf_select.c:316
LIBAVUTIL_VERSION_INT
Definition: eval.c:55
static const AVFilterPad avfilter_vf_select_inputs[]
Definition: vf_select.c:330
NULL
Definition: eval.c:55
static int poll_frame(AVFilterLink *outlink)
Definition: vf_select.c:279
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:45
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:111
#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:323
#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:301
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:256
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:297
#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:244
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:255
double select
Definition: vf_select.c:123
var_name
Definition: setpts.c:58
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:351