]> git.sesse.net Git - ffmpeg/blob - libavfilter/vf_select.c
avio: add a destructor for AVIOContext
[ffmpeg] / libavfilter / vf_select.c
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
21 /**
22  * @file
23  * filter for selecting which frame passes in the filterchain
24  */
25
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",                 ///< Euler number
37     "PHI",               ///< golden ratio
38     "PI",                ///< Greek pi
39
40     "TB",                ///< timebase
41
42     "pts",               ///< original pts in the file of the frame
43     "start_pts",         ///< first PTS in the stream, expressed in TB units
44     "prev_pts",          ///< previous frame PTS
45     "prev_selected_pts", ///< previous selected frame PTS
46
47     "t",                 ///< first PTS in seconds
48     "start_t",           ///< first PTS in the stream, expressed in seconds
49     "prev_t",            ///< previous frame time
50     "prev_selected_t",   ///< previously selected time
51
52     "pict_type",         ///< the type of picture in the movie
53     "I",
54     "P",
55     "B",
56     "S",
57     "SI",
58     "SP",
59     "BI",
60
61     "interlace_type",    ///< the frame interlace type
62     "PROGRESSIVE",
63     "TOPFIRST",
64     "BOTTOMFIRST",
65
66     "n",                 ///< frame number (starting from zero)
67     "selected_n",        ///< selected frame number (starting from zero)
68     "prev_selected_n",   ///< number of the last selected frame
69
70     "key",               ///< tell if the frame is a key frame
71     "pos",               ///< original position in the file of the frame
72
73     NULL
74 };
75
76 enum var_name {
77     VAR_E,
78     VAR_PHI,
79     VAR_PI,
80
81     VAR_TB,
82
83     VAR_PTS,
84     VAR_START_PTS,
85     VAR_PREV_PTS,
86     VAR_PREV_SELECTED_PTS,
87
88     VAR_T,
89     VAR_START_T,
90     VAR_PREV_T,
91     VAR_PREV_SELECTED_T,
92
93     VAR_PICT_TYPE,
94     VAR_PICT_TYPE_I,
95     VAR_PICT_TYPE_P,
96     VAR_PICT_TYPE_B,
97     VAR_PICT_TYPE_S,
98     VAR_PICT_TYPE_SI,
99     VAR_PICT_TYPE_SP,
100     VAR_PICT_TYPE_BI,
101
102     VAR_INTERLACE_TYPE,
103     VAR_INTERLACE_TYPE_P,
104     VAR_INTERLACE_TYPE_T,
105     VAR_INTERLACE_TYPE_B,
106
107     VAR_N,
108     VAR_SELECTED_N,
109     VAR_PREV_SELECTED_N,
110
111     VAR_KEY,
112
113     VAR_VARS_NB
114 };
115
116 #define FIFO_SIZE 8
117
118 typedef struct SelectContext {
119     const AVClass *class;
120     char *expr_str;
121     AVExpr *expr;
122     double var_values[VAR_VARS_NB];
123     double select;
124     int cache_frames;
125     AVFifoBuffer *pending_frames; ///< FIFO buffer of video frames
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;
166     select->var_values[VAR_PREV_SELECTED_PTS] = NAN;
167     select->var_values[VAR_PREV_SELECTED_T]   = NAN;
168     select->var_values[VAR_START_PTS]         = NAN;
169     select->var_values[VAR_START_T]           = NAN;
170
171     select->var_values[VAR_PICT_TYPE_I]  = AV_PICTURE_TYPE_I;
172     select->var_values[VAR_PICT_TYPE_P]  = AV_PICTURE_TYPE_P;
173     select->var_values[VAR_PICT_TYPE_B]  = AV_PICTURE_TYPE_B;
174     select->var_values[VAR_PICT_TYPE_SI] = AV_PICTURE_TYPE_SI;
175     select->var_values[VAR_PICT_TYPE_SP] = AV_PICTURE_TYPE_SP;
176
177     select->var_values[VAR_INTERLACE_TYPE_P] = INTERLACE_TYPE_P;
178     select->var_values[VAR_INTERLACE_TYPE_T] = INTERLACE_TYPE_T;
179     select->var_values[VAR_INTERLACE_TYPE_B] = INTERLACE_TYPE_B;;
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] =
203         !frame->interlaced_frame     ? INTERLACE_TYPE_P :
204         frame->top_field_first ? INTERLACE_TYPE_T : INTERLACE_TYPE_B;
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];
213         select->var_values[VAR_PREV_SELECTED_PTS] = select->var_values[VAR_PTS];
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
318 static const AVFilterPad avfilter_vf_select_inputs[] = {
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
329 static const AVFilterPad avfilter_vf_select_outputs[] = {
330     {
331         .name          = "default",
332         .type          = AVMEDIA_TYPE_VIDEO,
333         .poll_frame    = poll_frame,
334         .request_frame = request_frame,
335     },
336     { NULL }
337 };
338
339 AVFilter ff_vf_select = {
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 };