From f76ce9133ddaee988549e9ae0a0df8723392acaa Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sun, 12 Mar 2023 17:01:12 +0100 Subject: lavfi/framesync: switch ts maps to use pts+timebase Also, sort the entries. --- doc/filters.texi | 6 +++--- libavfilter/framesync.c | 44 +++++++++++++++++++++++++++++++++++--------- libavfilter/framesync.h | 7 ++++++- 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index afc6fd3ebf..bd964d4094 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -377,9 +377,9 @@ input frame. @item ts_map Specify an explicit timestamp map. The string should be composed of lines, one -per each output frame. The line should contain whitespace-separated times in -microseconds, one for every input. Frames with these timestamps will be matched -together to produces output events. +per each output frame. The line should contain whitespace-separated pairs of +"pts tb_num/tb_den", one for every input. Frames with these timestamps will be +matched together to produces output events. @end table @c man end OPTIONS FOR FILTERS WITH SEVERAL INPUTS diff --git a/libavfilter/framesync.c b/libavfilter/framesync.c index 6e628af647..2042c83a0b 100644 --- a/libavfilter/framesync.c +++ b/libavfilter/framesync.c @@ -130,10 +130,17 @@ static void framesync_sync_level_update(FFFrameSync *fs) framesync_eof(fs); } +static int map_sort(const void *m1, const void *m2) +{ + const TSMapEntry *e1 = m1; + const TSMapEntry *e2 = m2; + return av_compare_ts(e1->pts, e1->tb, e2->pts, e2->tb); +} + static int ts_map_parse(FFFrameSync *fs, const char *ts_map_str) { while (*ts_map_str) { - int64_t *dst; + TSMapEntry *dst; ts_map_str += strspn(ts_map_str, " \t\r\n"); @@ -153,7 +160,7 @@ static int ts_map_parse(FFFrameSync *fs, const char *ts_map_str) // read a timestamp for each input for (int i = 0; i < fs->nb_in; i++) { char *p; - dst[i] = strtol(ts_map_str, &p, 0); + dst[i].pts = strtol(ts_map_str, &p, 0); if (p == ts_map_str) { av_log(fs, AV_LOG_ERROR, "Invalid number in timestamp map on line %zu: %s\n", @@ -162,14 +169,29 @@ static int ts_map_parse(FFFrameSync *fs, const char *ts_map_str) } ts_map_str = p; - if (fs->nb_ts_map > 1 && dst[i - (int)fs->nb_in] > dst[i]) { - av_log(fs, AV_LOG_ERROR, - "Timestamp map for input %d, frame %zu goes backwards\n", - i, fs->nb_ts_map - 1); + ts_map_str += strspn(ts_map_str, " \t"); + + dst[i].tb.num = strtol(ts_map_str, &p, 0); + if (p == ts_map_str) { + av_log(fs, AV_LOG_ERROR, "Expected timebase numerator, got %s\n", p); + return AVERROR_INVALIDDATA; + }; + ts_map_str = p; + + ts_map_str += strspn(ts_map_str, " \t"); + if (*ts_map_str != '/') { + av_log(fs, AV_LOG_ERROR, "Expected '/' as the timebase separator, got %s\n", ts_map_str); return AVERROR_INVALIDDATA; } + ts_map_str++; + dst[i].tb.den = strtol(ts_map_str, &p, 0); + if (p == ts_map_str) { + av_log(fs, AV_LOG_ERROR, "Expected timebase denominator, got %s\n", p); + return AVERROR_INVALIDDATA; + } + ts_map_str = p; - ts_map_str += strspn(p, " \t"); + ts_map_str += strspn(ts_map_str, " \t"); } // skip everything after the needed timestamp @@ -179,6 +201,9 @@ skip_line: break; } + if (fs->ts_map) + qsort(fs->ts_map, fs->nb_ts_map, sizeof(*fs->ts_map) * fs->nb_in, map_sort); + return 0; } @@ -349,8 +374,9 @@ static int framesync_advance(FFFrameSync *fs) fs->frame_ready = 1; for (i = 0; i < fs->nb_in; i++) { FFFrameSyncIn * const in = &fs->in[i]; - int64_t next_ts = av_rescale_q(fs->ts_map[fs->nb_events * fs->nb_in + i], - AV_TIME_BASE_Q, fs->time_base); + int64_t next_ts = av_rescale_q(fs->ts_map[fs->nb_events * fs->nb_in + i].pts, + fs->ts_map[fs->nb_events * fs->nb_in + i].tb, + fs->time_base); uint64_t delta_cur = in->frame ? FFABS(in->pts - next_ts) : UINT64_MAX; uint64_t delta_next = in->frame_next ? FFABS(in->pts_next - next_ts) : UINT64_MAX; diff --git a/libavfilter/framesync.h b/libavfilter/framesync.h index 979f54e16e..10b116c925 100644 --- a/libavfilter/framesync.h +++ b/libavfilter/framesync.h @@ -162,6 +162,11 @@ typedef struct FFFrameSyncIn { enum FFFrameTSSyncMode ts_mode; } FFFrameSyncIn; +typedef struct TSMapEntry { + int64_t pts; + AVRational tb; +} TSMapEntry; + /** * Frame sync structure. */ @@ -237,7 +242,7 @@ typedef struct FFFrameSync { char *ts_map_str; // explicit frame map - int64_t *ts_map; + TSMapEntry *ts_map; size_t nb_ts_map; unsigned int ts_map_allocated; } FFFrameSync; -- cgit v1.2.3