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.
Unified · Split
| @@ -18,12 +18,9 @@ · 17 unmodified lines | |||
| 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | 18 | * 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 | ||
| 52 | int ff_framesync2_init(FFFrameSync *fs, void *parent, unsigned nb_in) | 49 | int 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 | ||
| 66 | static 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 | |||
| 64 | static void framesync_sync_level_update(FFFrameSync *fs) | 73 | static 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 | else | 85 | else |
| 77 | fs->eof = 1; | 86 | framesync_eof(fs); |
| 78 | } | 87 | } |
| 79 | 88 | ||
| 80 | int ff_framesync2_configure(FFFrameSync *fs) | 89 | int 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 | ||
| 205 | int ff_framesync2_add_frame(FFFrameSync *fs, unsigned in, AVFrame *frame) | 206 | static 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 | |||
| 215 | void 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 | |||
| 227 | void 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 | ||
| 232 | int ff_framesync2_get_frame(FFFrameSync *fs, unsigned in, AVFrame **rframe, | 218 | int 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 | ||
| 282 | int ff_framesync2_process_frame(FFFrameSync *fs, unsigned all) | 267 | int 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 | |||
| 303 | int 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 | |||
| 317 | int 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 | } |
| @@ -25,7 +25,6 @@ · 24 unmodified lines | |||
| 25 | 25 | ||
| 26 | /* | 26 | /* |
| 27 | * TODO | 27 | * 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 of | 40 | * 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 using | 45 | * 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 | */ |
| 83 | typedef struct FFFrameSyncIn { | 75 | typedef 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 frame | 78 | * Extrapolation mode for timestamps before the first frame |
| 92 | */ | 79 | */ |
| @@ -152,7 +139,11 @@ typedef struct FFFrameSyncIn { · 59 unmodified lines | |||
| 152 | */ | 139 | */ |
| 153 | typedef struct FFFrameSync { | 140 | typedef 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 streams | 149 | * 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 initialize | 206 | * @param fs frame sync structure to initialize |
| 216 | * @param parent parent object, used for logging | 207 | * @param parent parent AVFilterContext object |
| 217 | * @param nb_in number of inputs | 208 | * @param nb_in number of inputs |
| 218 | * @return >= 0 for success or a negative error code | 209 | * @return >= 0 for success or a negative error code |
| 219 | */ | 210 | */ |
| 220 | int ff_framesync2_init(FFFrameSync *fs, void *parent, unsigned nb_in); | 211 | int 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 | */ |
| 234 | void ff_framesync2_uninit(FFFrameSync *fs); | 225 | void 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 | */ | ||
| 245 | int 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 | */ | ||
| 252 | void ff_framesync2_next(FFFrameSync *fs); | ||
| 253 | |||
| 254 | /** | ||
| 255 | * Drop the current frame event. | ||
| 256 | */ | ||
| 257 | void 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 | */ | ||
| 277 | int 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 | */ | ||
| 286 | int 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_frame | 243 | * 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 | */ |
| 295 | int ff_framesync2_request_frame(FFFrameSync *fs, AVFilterLink *outlink); | 246 | int ff_framesync2_activate(FFFrameSync *fs); |
| 296 | 247 | ||
| 297 | #endif /* AVFILTER_FRAMESYNC2_H */ | 248 | #endif /* AVFILTER_FRAMESYNC2_H */ |