Include two values for it, a default one that sets/keeps the current behavior, where the frame event generated by the primary input will have a timestamp equal or higher than frames in secondary input, plus a new one where the secondary input frame will be that with the absolute closest timestamp to that of the frame event one. Addresses ticket #9689, where the new optional behavior produces better frame syncronization.
Showing the changes to libavfilter/framesync.c (1 of 2 files). Show all
Unified · Split
| @@ -42,6 +42,13 @@ static const AVOption framesync_options[] = { · 41 unmodified lines | |||
| 42 | { "pass", "Pass through the main input.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_PASS }, .flags = FLAGS, "eof_action" }, | 42 | { "pass", "Pass through the main input.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_PASS }, .flags = FLAGS, "eof_action" }, |
| 43 | { "shortest", "force termination when the shortest input terminates", OFFSET(opt_shortest), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, | 43 | { "shortest", "force termination when the shortest input terminates", OFFSET(opt_shortest), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, |
| 44 | { "repeatlast", "extend last frame of secondary streams beyond EOF", OFFSET(opt_repeatlast), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS }, | 44 | { "repeatlast", "extend last frame of secondary streams beyond EOF", OFFSET(opt_repeatlast), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS }, |
| 45 | { "ts_sync_mode", "How strictly to sync streams based on secondary input timestamps", | ||
| 46 | OFFSET(opt_ts_sync_mode), AV_OPT_TYPE_INT, { .i64 = TS_DEFAULT }, | ||
| 47 | TS_DEFAULT, TS_NEAREST, .flags = FLAGS, "ts_sync_mode" }, | ||
| 48 | { "default", "Frame from secondary input with the nearest lower or equal timestamp to the primary input frame", | ||
| 49 | 0, AV_OPT_TYPE_CONST, { .i64 = TS_DEFAULT }, .flags = FLAGS, "ts_sync_mode" }, | ||
| 50 | { "nearest", "Frame from secondary input with the absolute nearest timestamp to the primary input frame", | ||
| 51 | 0, AV_OPT_TYPE_CONST, { .i64 = TS_NEAREST }, .flags = FLAGS, "ts_sync_mode" }, | ||
| 45 | { NULL } | 52 | { NULL } |
| 46 | }; | 53 | }; |
| 47 | static const AVClass framesync_class = { | 54 | static const AVClass framesync_class = { |
| @@ -110,6 +117,14 @@ static void framesync_sync_level_update(FFFrameSync *fs) · 62 unmodified lines | |||
| 110 | av_assert0(level <= fs->sync_level); | 117 | av_assert0(level <= fs->sync_level); |
| 111 | if (level < fs->sync_level) | 118 | if (level < fs->sync_level) |
| 112 | av_log(fs, AV_LOG_VERBOSE, "Sync level %u\n", level); | 119 | av_log(fs, AV_LOG_VERBOSE, "Sync level %u\n", level); |
| 120 | if (fs->opt_ts_sync_mode > TS_DEFAULT) { | ||
| 121 | for (i = 0; i < fs->nb_in; i++) { | ||
| 122 | if (fs->in[i].sync < level) | ||
| 123 | fs->in[i].ts_mode = fs->opt_ts_sync_mode; | ||
| 124 | else | ||
| 125 | fs->in[i].ts_mode = TS_DEFAULT; | ||
| 126 | } | ||
| 127 | } | ||
| 113 | if (level) | 128 | if (level) |
| 114 | fs->sync_level = level; | 129 | fs->sync_level = level; |
| 115 | else | 130 | else |
| @@ -187,6 +202,10 @@ static int framesync_advance(FFFrameSync *fs) · 71 unmodified lines | |||
| 187 | } | 202 | } |
| 188 | for (i = 0; i < fs->nb_in; i++) { | 203 | for (i = 0; i < fs->nb_in; i++) { |
| 189 | if (fs->in[i].pts_next == pts || | 204 | if (fs->in[i].pts_next == pts || |
| 205 | (fs->in[i].ts_mode == TS_NEAREST && | ||
| 206 | fs->in[i].have_next && | ||
| 207 | fs->in[i].pts_next != INT64_MAX && fs->in[i].pts != AV_NOPTS_VALUE && | ||
| 208 | fs->in[i].pts_next - pts < pts - fs->in[i].pts) || | ||
| 190 | (fs->in[i].before == EXT_INFINITY && | 209 | (fs->in[i].before == EXT_INFINITY && |
| 191 | fs->in[i].state == STATE_BOF)) { | 210 | fs->in[i].state == STATE_BOF)) { |
| 192 | av_frame_free(&fs->in[i].frame); | 211 | av_frame_free(&fs->in[i].frame); |