History

lavfi/framesync2: implement "activate" design.

With this helper API, filters that used the first framesync helper API can easily be changed to use the new and more extensible design for filters with a single activate() callback.

Nicolas George committed 9 years ago

Commit 4e0e9ce1 parent ed1c8842 files · +82 −161Browse files

Unified · Split

2 files
  1. libavfilter/framesync2.c +68 −98
  2. libavfilter/framesync2.h +14 −63
libavfilter/framesync2.c+68−98
@@ -18,12 +18,9 @@ · 17 unmodified lines
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */19 */
20 20
21#define FF_INTERNAL_FIELDS 1
22#include "framequeue.h"
23
24#include "libavutil/avassert.h"21#include "libavutil/avassert.h"
25#include "avfilter.h"22#include "avfilter.h"
26#include "bufferqueue.h"23#include "filters.h"
27#include "framesync2.h"24#include "framesync2.h"
28#include "internal.h"25#include "internal.h"
29 26
@@ -49,8 +46,13 @@ enum { · 19 unmodified lines
49 STATE_EOF,46 STATE_EOF,
50};47};
51 48
52int ff_framesync2_init(FFFrameSync *fs, void *parent, unsigned nb_in)49int ff_framesync2_init(FFFrameSync *fs, AVFilterContext *parent, unsigned nb_in)
53{50{
51 /* For filters with several outputs, we will not be able to assume which
52 output is relevant for ff_outlink_frame_wanted() and
53 ff_outlink_set_status(). To be designed when needed. */
54 av_assert0(parent->nb_outputs == 1);
55
54 fs->class = &framesync_class;56 fs->class = &framesync_class;
55 fs->parent = parent;57 fs->parent = parent;
56 fs->nb_in = nb_in;58 fs->nb_in = nb_in;
@@ -61,6 +63,13 @@ int ff_framesync2_init(FFFrameSync *fs, void *parent, unsigned nb_in) · 4 unmodified lines
61 return 0;63 return 0;
62}64}
63 65
66static void framesync_eof(FFFrameSync *fs)
67{
68 fs->eof = 1;
69 fs->frame_ready = 0;
70 ff_outlink_set_status(fs->parent->outputs[0], AVERROR_EOF, AV_NOPTS_VALUE);
71}
72
64static void framesync_sync_level_update(FFFrameSync *fs)73static void framesync_sync_level_update(FFFrameSync *fs)
65{74{
66 unsigned i, level = 0;75 unsigned i, level = 0;
@@ -74,7 +83,7 @@ static void framesync_sync_level_update(FFFrameSync *fs) · 7 unmodified lines
74 if (level)83 if (level)
75 fs->sync_level = level;84 fs->sync_level = level;
76 else85 else
77 fs->eof = 1;86 framesync_eof(fs);
78}87}
79 88
80int ff_framesync2_configure(FFFrameSync *fs)89int ff_framesync2_configure(FFFrameSync *fs)
@@ -144,7 +153,7 @@ static void framesync_advance(FFFrameSync *fs) · 63 unmodified lines
144 if (fs->in[i].pts_next < pts)153 if (fs->in[i].pts_next < pts)
145 pts = fs->in[i].pts_next;154 pts = fs->in[i].pts_next;
146 if (pts == INT64_MAX) {155 if (pts == INT64_MAX) {
147 fs->eof = 1;156 framesync_eof(fs);
148 break;157 break;
149 }158 }
150 for (i = 0; i < fs->nb_in; i++) {159 for (i = 0; i < fs->nb_in; i++) {
@@ -162,11 +171,9 @@ static void framesync_advance(FFFrameSync *fs) · 11 unmodified lines
162 fs->frame_ready = 1;171 fs->frame_ready = 1;
163 if (fs->in[i].state == STATE_EOF &&172 if (fs->in[i].state == STATE_EOF &&
164 fs->in[i].after == EXT_STOP)173 fs->in[i].after == EXT_STOP)
165 fs->eof = 1;174 framesync_eof(fs);
166 }175 }
167 }176 }
168 if (fs->eof)
169 fs->frame_ready = 0;
170 if (fs->frame_ready)177 if (fs->frame_ready)
171 for (i = 0; i < fs->nb_in; i++)178 for (i = 0; i < fs->nb_in; i++)
172 if ((fs->in[i].state == STATE_BOF &&179 if ((fs->in[i].state == STATE_BOF &&
@@ -188,45 +195,24 @@ static void framesync_inject_frame(FFFrameSync *fs, unsigned in, AVFrame *frame) · 15 unmodified lines
188 int64_t pts;195 int64_t pts;
189 196
190 av_assert0(!fs->in[in].have_next);197 av_assert0(!fs->in[in].have_next);
191 if (frame) {198 av_assert0(frame);
192 pts = av_rescale_q(frame->pts, fs->in[in].time_base, fs->time_base);199 pts = av_rescale_q(frame->pts, fs->in[in].time_base, fs->time_base);
193 frame->pts = pts;200 frame->pts = pts;
194 } else {
195 pts = fs->in[in].state != STATE_RUN || fs->in[in].after == EXT_INFINITY
196 ? INT64_MAX : framesync_pts_extrapolate(fs, in, fs->in[in].pts);
197 fs->in[in].sync = 0;
198 framesync_sync_level_update(fs);
199 }
200 fs->in[in].frame_next = frame;201 fs->in[in].frame_next = frame;
201 fs->in[in].pts_next = pts;202 fs->in[in].pts_next = pts;
202 fs->in[in].have_next = 1;203 fs->in[in].have_next = 1;
203}204}
204 205
205int ff_framesync2_add_frame(FFFrameSync *fs, unsigned in, AVFrame *frame)206static void framesync_inject_status(FFFrameSync *fs, unsigned in, int status, int64_t pts)
206{
207 av_assert1(in < fs->nb_in);
208 if (!fs->in[in].have_next)
209 framesync_inject_frame(fs, in, frame);
210 else
211 ff_bufqueue_add(fs, &fs->in[in].queue, frame);
212 return 0;
213}
214
215void ff_framesync2_next(FFFrameSync *fs)
216{
217 unsigned i;
218
219 av_assert0(!fs->frame_ready);
220 for (i = 0; i < fs->nb_in; i++)
221 if (!fs->in[i].have_next && fs->in[i].queue.available)
222 framesync_inject_frame(fs, i, ff_bufqueue_get(&fs->in[i].queue));
223 fs->frame_ready = 0;
224 framesync_advance(fs);
225}
226
227void ff_framesync2_drop(FFFrameSync *fs)
228{207{
229 fs->frame_ready = 0;208 av_assert0(!fs->in[in].have_next);
209 pts = fs->in[in].state != STATE_RUN || fs->in[in].after == EXT_INFINITY
210 ? INT64_MAX : framesync_pts_extrapolate(fs, in, fs->in[in].pts);
211 fs->in[in].sync = 0;
212 framesync_sync_level_update(fs);
213 fs->in[in].frame_next = NULL;
214 fs->in[in].pts_next = pts;
215 fs->in[in].have_next = 1;
230}216}
231 217
232int ff_framesync2_get_frame(FFFrameSync *fs, unsigned in, AVFrame **rframe,218int ff_framesync2_get_frame(FFFrameSync *fs, unsigned in, AVFrame **rframe,
@@ -273,71 +259,55 @@ void ff_framesync2_uninit(FFFrameSync *fs) · 40 unmodified lines
273 for (i = 0; i < fs->nb_in; i++) {259 for (i = 0; i < fs->nb_in; i++) {
274 av_frame_free(&fs->in[i].frame);260 av_frame_free(&fs->in[i].frame);
275 av_frame_free(&fs->in[i].frame_next);261 av_frame_free(&fs->in[i].frame_next);
276 ff_bufqueue_discard_all(&fs->in[i].queue);
277 }262 }
278 263
279 av_freep(&fs->in);264 av_freep(&fs->in);
280}265}
281 266
282int ff_framesync2_process_frame(FFFrameSync *fs, unsigned all)267int ff_framesync2_activate(FFFrameSync *fs)
283{268{
284 int ret, count = 0;269 AVFilterContext *ctx = fs->parent;
270 AVFrame *frame = NULL;
271 int64_t pts;
272 unsigned i, nb_active, nb_miss;
273 int ret, status;
285 274
286 av_assert0(fs->on_event);275 nb_active = nb_miss = 0;
287 while (1) {276 for (i = 0; i < fs->nb_in; i++) {
288 ff_framesync2_next(fs);277 if (fs->in[i].have_next || fs->in[i].state == STATE_EOF)
289 if (fs->eof || !fs->frame_ready)278 continue;
290 break;279 nb_active++;
291 if ((ret = fs->on_event(fs)) < 0)280 ret = ff_inlink_consume_frame(ctx->inputs[i], &frame);
281 if (ret < 0)
292 return ret;282 return ret;
293 ff_framesync2_drop(fs);283 if (ret) {
294 count++;284 av_assert0(frame);
295 if (!all)285 framesync_inject_frame(fs, i, frame);
296 break;286 } else {
287 ret = ff_inlink_acknowledge_status(ctx->inputs[i], &status, &pts);
288 if (ret > 0) {
289 framesync_inject_status(fs, i, status, pts);
290 } else if (!ret) {
291 nb_miss++;
292 }
293 }
294 }
295 if (nb_miss) {
296 if (nb_miss == nb_active && !ff_outlink_frame_wanted(ctx->outputs[0]))
297 return FFERROR_NOT_READY;
298 for (i = 0; i < fs->nb_in; i++)
299 if (!fs->in[i].have_next && fs->in[i].state != STATE_EOF)
300 ff_inlink_request_frame(ctx->inputs[i]);
301 return 0;
297 }302 }
298 if (!count && fs->eof)
299 return AVERROR_EOF;
300 return count;
301}
302
303int ff_framesync2_filter_frame(FFFrameSync *fs, AVFilterLink *inlink,
304 AVFrame *in)
305{
306 int ret;
307 303
308 if ((ret = ff_framesync2_process_frame(fs, 1)) < 0)304 framesync_advance(fs);
309 return ret;305 if (fs->eof || !fs->frame_ready)
310 if ((ret = ff_framesync2_add_frame(fs, FF_INLINK_IDX(inlink), in)) < 0)306 return 0;
311 return ret;307 ret = fs->on_event(fs);
312 if ((ret = ff_framesync2_process_frame(fs, 0)) < 0)308 if (ret < 0)
313 return ret;309 return ret;
314 return 0;310 fs->frame_ready = 0;
315}
316
317int ff_framesync2_request_frame(FFFrameSync *fs, AVFilterLink *outlink)
318{
319 AVFilterContext *ctx = outlink->src;
320 int input, ret, i;
321 311
322 if ((ret = ff_framesync2_process_frame(fs, 0)) < 0)312 return 0;
323 return ret;
324 if (ret > 0)
325 return 0;
326 if (fs->eof)
327 return AVERROR_EOF;
328 input = fs->in_request;
329 /* Detect status change early */
330 for (i = 0; i < fs->nb_in; i++)
331 if (!ff_framequeue_queued_frames(&ctx->inputs[i]->fifo) &&
332 ctx->inputs[i]->status_in && !ctx->inputs[i]->status_out)
333 input = i;
334 ret = ff_request_frame(ctx->inputs[input]);
335 if (ret == AVERROR_EOF) {
336 if ((ret = ff_framesync2_add_frame(fs, input, NULL)) < 0)
337 return ret;
338 if ((ret = ff_framesync2_process_frame(fs, 0)) < 0)
339 return ret;
340 ret = 0;
341 }
342 return ret;
343}313}
libavfilter/framesync2.h+14−63
@@ -25,7 +25,6 @@ · 24 unmodified lines
25 25
26/*26/*
27 * TODO27 * TODO
28 * Callback-based API similar to dualinput.
29 * Export convenient options.28 * Export convenient options.
30 */29 */
31 30
@@ -41,16 +40,9 @@ · 9 unmodified lines
41 * situations where some stream extend beyond the beginning or the end of40 * situations where some stream extend beyond the beginning or the end of
42 * others can be configured.41 * others can be configured.
43 *42 *
44 * The basic working of this API is the following:43 * The basic working of this API is the following: set the on_event
45 *44 * callback, then call ff_framesync2_activate() from the filter's activate
46 * - When a frame is available on any input, add it using45 * callback.
47 * ff_framesync2_add_frame().
48 *
49 * - When a frame event is ready to be processed (i.e. after adding a frame
50 * or when requested on input):
51 * - call ff_framesync2_next();
52 * - if fs->frame_ready is true, process the frames;
53 * - call ff_framesync2_drop().
54 */46 */
55 47
56/**48/**
@@ -82,11 +74,6 @@ enum FFFrameSyncExtMode { · 25 unmodified lines
82 */74 */
83typedef struct FFFrameSyncIn {75typedef struct FFFrameSyncIn {
84 76
85 /**
86 * Queue of incoming AVFrame, and NULL to mark EOF
87 */
88 struct FFBufQueue queue;
89
90 /**77 /**
91 * Extrapolation mode for timestamps before the first frame78 * Extrapolation mode for timestamps before the first frame
92 */79 */
@@ -152,7 +139,11 @@ typedef struct FFFrameSyncIn { · 59 unmodified lines
152 */139 */
153typedef struct FFFrameSync {140typedef struct FFFrameSync {
154 const AVClass *class;141 const AVClass *class;
155 void *parent;142
143 /**
144 * Parent filter context.
145 */
146 AVFilterContext *parent;
156 147
157 /**148 /**
158 * Number of input streams149 * Number of input streams
@@ -213,11 +204,11 @@ typedef struct FFFrameSync { · 54 unmodified lines
213 * The entire structure is expected to be already set to 0.204 * The entire structure is expected to be already set to 0.
214 *205 *
215 * @param fs frame sync structure to initialize206 * @param fs frame sync structure to initialize
216 * @param parent parent object, used for logging207 * @param parent parent AVFilterContext object
217 * @param nb_in number of inputs208 * @param nb_in number of inputs
218 * @return >= 0 for success or a negative error code209 * @return >= 0 for success or a negative error code
219 */210 */
220int ff_framesync2_init(FFFrameSync *fs, void *parent, unsigned nb_in);211int ff_framesync2_init(FFFrameSync *fs, AVFilterContext *parent, unsigned nb_in);
221 212
222/**213/**
223 * Configure a frame sync structure.214 * Configure a frame sync structure.
@@ -233,29 +224,6 @@ int ff_framesync2_configure(FFFrameSync *fs); · 9 unmodified lines
233 */224 */
234void ff_framesync2_uninit(FFFrameSync *fs);225void ff_framesync2_uninit(FFFrameSync *fs);
235 226
236/**
237 * Add a frame to an input
238 *
239 * Typically called from the filter_frame() method.
240 *
241 * @param fs frame sync structure
242 * @param in index of the input
243 * @param frame input frame, or NULL for EOF
244 */
245int ff_framesync2_add_frame(FFFrameSync *fs, unsigned in, AVFrame *frame);
246
247/**
248 * Prepare the next frame event.
249 *
250 * The status of the operation can be found in fs->frame_ready and fs->eof.
251 */
252void ff_framesync2_next(FFFrameSync *fs);
253
254/**
255 * Drop the current frame event.
256 */
257void ff_framesync2_drop(FFFrameSync *fs);
258
259/**227/**
260 * Get the current frame in an input.228 * Get the current frame in an input.
261 *229 *
@@ -270,28 +238,11 @@ int ff_framesync2_get_frame(FFFrameSync *fs, unsigned in, AVFrame **rframe, · 8 unmodified lines
270 unsigned get);238 unsigned get);
271 239
272/**240/**
273 * Process one or several frame using the on_event callback.241 * Examine the frames in the filter's input and try to produce output.
274 *
275 * @return number of frames processed or negative error code
276 */
277int ff_framesync2_process_frame(FFFrameSync *fs, unsigned all);
278
279
280/**
281 * Accept a frame on a filter input.
282 *
283 * This function can be the complete implementation of all filter_frame
284 * methods of a filter using framesync.
285 */
286int ff_framesync2_filter_frame(FFFrameSync *fs, AVFilterLink *inlink,
287 AVFrame *in);
288
289/**
290 * Request a frame on the filter output.
291 *242 *
292 * This function can be the complete implementation of all filter_frame243 * This function can be the complete implementation of the activate
293 * methods of a filter using framesync if it has only one output.244 * method of a filter using framesync2.
294 */245 */
295int ff_framesync2_request_frame(FFFrameSync *fs, AVFilterLink *outlink);246int ff_framesync2_activate(FFFrameSync *fs);
296 247
297#endif /* AVFILTER_FRAMESYNC2_H */248#endif /* AVFILTER_FRAMESYNC2_H */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t