[FFmpeg-devel] [PATCH v4] ffmpeg: add option -isync

Paul B Mahol onemda at gmail.com
Thu Jul 14 13:31:53 EEST 2022


On Thu, Jul 14, 2022 at 12:21 PM Gyan Doshi <ffmpeg at gyani.pro> wrote:

> Pushed as 882aac99d2a7d15492ce1da9859676b0c04295b8
> and cherry-picked to 5.1
>

Why?

>
> On 2022-07-14 01:46 pm, Gyan Doshi wrote:
> > This is a per-file input option that adjusts an input's timestamps
> > with reference to another input, so that emitted packet timestamps
> > account for the difference between the start times of the two inputs.
> >
> > Typical use case is to sync two or more live inputs such as from capture
> > devices. Both the target and reference input source timestamps should be
> > based on the same clock source.
> >
> > If either input lacks starting timestamps, then no sync adjustment is
> made.
> > ---
> > v4 change: fallback on reception timestamp removed.
> >
> >   doc/ffmpeg.texi      | 15 +++++++++++
> >   fftools/ffmpeg.h     |  2 ++
> >   fftools/ffmpeg_opt.c | 60 ++++++++++++++++++++++++++++++++++++++++++++
> >   3 files changed, 77 insertions(+)
> >
> > diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi
> > index 1a534ff1cc..767df69b7f 100644
> > --- a/doc/ffmpeg.texi
> > +++ b/doc/ffmpeg.texi
> > @@ -518,6 +518,21 @@ see @ref{time duration syntax,,the Time duration
> section in the ffmpeg-utils(1)
> >   Like the @code{-ss} option but relative to the "end of file". That is
> negative
> >   values are earlier in the file, 0 is at EOF.
> >
> > + at item -isync @var{input_index} (@emph{input})
> > +Assign an input as a sync source.
> > +
> > +This will take the difference between the start times of the target and
> reference inputs and
> > +offset the timestamps of the target file by that difference. The source
> timestamps of the two
> > +inputs should derive from the same clock source for expected results.
> If @code{copyts} is set
> > +then @code{start_at_zero} must also be set. If either of the inputs has
> no starting timestamp
> > +then no sync adjustment is made.
> > +
> > +Acceptable values are those that refer to a valid ffmpeg input index.
> If the sync reference is
> > +the target index itself or @var{-1}, then no adjustment is made to
> target timestamps. A sync
> > +reference may not itself be synced to any other input.
> > +
> > +Default value is @var{-1}.
> > +
> >   @item -itsoffset @var{offset} (@emph{input})
> >   Set the input time offset.
> >
> > diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
> > index 99d31c346e..391a35cf50 100644
> > --- a/fftools/ffmpeg.h
> > +++ b/fftools/ffmpeg.h
> > @@ -118,6 +118,7 @@ typedef struct OptionsContext {
> >       float readrate;
> >       int accurate_seek;
> >       int thread_queue_size;
> > +    int input_sync_ref;
> >
> >       SpecifierOpt *ts_scale;
> >       int        nb_ts_scale;
> > @@ -410,6 +411,7 @@ typedef struct InputFile {
> >                                at the moment when looping happens */
> >       AVRational time_base; /* time base of the duration */
> >       int64_t input_ts_offset;
> > +    int input_sync_ref;
> >
> >       int64_t ts_offset;
> >       int64_t last_ts;
> > diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
> > index e08455478f..359d8f60b8 100644
> > --- a/fftools/ffmpeg_opt.c
> > +++ b/fftools/ffmpeg_opt.c
> > @@ -235,6 +235,7 @@ static void init_options(OptionsContext *o)
> >       o->chapters_input_file = INT_MAX;
> >       o->accurate_seek  = 1;
> >       o->thread_queue_size = -1;
> > +    o->input_sync_ref = -1;
> >   }
> >
> >   static int show_hwaccels(void *optctx, const char *opt, const char
> *arg)
> > @@ -287,6 +288,59 @@ static int parse_and_set_vsync(const char *arg, int
> *vsync_var, int file_idx, in
> >       return 0;
> >   }
> >
> > +static int apply_sync_offsets(void)
> > +{
> > +    for (int i = 0; i < nb_input_files; i++) {
> > +        InputFile *ref, *self = input_files[i];
> > +        int64_t adjustment;
> > +        int64_t self_start_time, ref_start_time, self_seek_start,
> ref_seek_start;
> > +        int start_times_set = 1;
> > +
> > +        if (self->input_sync_ref == -1 || self->input_sync_ref == i)
> continue;
> > +        if (self->input_sync_ref >= nb_input_files ||
> self->input_sync_ref < -1) {
> > +            av_log(NULL, AV_LOG_FATAL, "-isync for input %d references
> non-existent input %d.\n", i, self->input_sync_ref);
> > +            exit_program(1);
> > +        }
> > +
> > +        if (copy_ts && !start_at_zero) {
> > +            av_log(NULL, AV_LOG_FATAL, "Use of -isync requires that
> start_at_zero be set if copyts is set.\n");
> > +            exit_program(1);
> > +        }
> > +
> > +        ref = input_files[self->input_sync_ref];
> > +        if (ref->input_sync_ref != -1 && ref->input_sync_ref !=
> self->input_sync_ref) {
> > +            av_log(NULL, AV_LOG_ERROR, "-isync for input %d references
> a resynced input %d. Sync not set.\n", i, self->input_sync_ref);
> > +            continue;
> > +        }
> > +
> > +        if (self->ctx->start_time_realtime != AV_NOPTS_VALUE &&
> ref->ctx->start_time_realtime != AV_NOPTS_VALUE) {
> > +            self_start_time = self->ctx->start_time_realtime;
> > +            ref_start_time  =  ref->ctx->start_time_realtime;
> > +        } else if (self->ctx->start_time != AV_NOPTS_VALUE &&
> ref->ctx->start_time != AV_NOPTS_VALUE) {
> > +            self_start_time = self->ctx->start_time;
> > +            ref_start_time  =  ref->ctx->start_time;
> > +        } else {
> > +            start_times_set = 0;
> > +        }
> > +
> > +        if (start_times_set) {
> > +            self_seek_start = self->start_time == AV_NOPTS_VALUE ? 0 :
> self->start_time;
> > +            ref_seek_start  =  ref->start_time == AV_NOPTS_VALUE ? 0 :
> ref->start_time;
> > +
> > +            adjustment = (self_start_time - ref_start_time) +
> !copy_ts*(self_seek_start - ref_seek_start) + ref->input_ts_offset;
> > +
> > +            self->ts_offset += adjustment;
> > +
> > +            av_log(NULL, AV_LOG_INFO, "Adjusted ts offset for Input #%d
> by %"PRId64" us to sync with Input #%d.\n", i, adjustment,
> self->input_sync_ref);
> > +        } else {
> > +            av_log(NULL, AV_LOG_INFO, "Unable to identify start times
> for Inputs #%d and %d both. No sync adjustment made.\n",
> > +                   i, self->input_sync_ref);
> > +        }
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> >   static int opt_filter_threads(void *optctx, const char *opt, const
> char *arg)
> >   {
> >       av_free(filter_nbthreads);
> > @@ -1305,6 +1359,7 @@ static int open_input_file(OptionsContext *o,
> const char *filename)
> >       f->ist_index  = nb_input_streams - ic->nb_streams;
> >       f->start_time = o->start_time;
> >       f->recording_time = o->recording_time;
> > +    f->input_sync_ref = o->input_sync_ref;
> >       f->input_ts_offset = o->input_ts_offset;
> >       f->ts_offset  = o->input_ts_offset - (copy_ts ? (start_at_zero &&
> ic->start_time != AV_NOPTS_VALUE ? ic->start_time : 0) : timestamp);
> >       f->nb_streams = ic->nb_streams;
> > @@ -3489,6 +3544,8 @@ int ffmpeg_parse_options(int argc, char **argv)
> >           goto fail;
> >       }
> >
> > +    apply_sync_offsets();
> > +
> >       /* create the complex filtergraphs */
> >       ret = init_complex_filters();
> >       if (ret < 0) {
> > @@ -3603,6 +3660,9 @@ const OptionDef options[] = {
> >       { "accurate_seek",  OPT_BOOL | OPT_OFFSET | OPT_EXPERT |
> >                           OPT_INPUT,                                   {
> .off = OFFSET(accurate_seek) },
> >           "enable/disable accurate seeking with -ss" },
> > +    { "isync",          HAS_ARG | OPT_INT | OPT_OFFSET |
> > +                        OPT_EXPERT | OPT_INPUT,                      {
> .off = OFFSET(input_sync_ref) },
> > +        "Indicate the input index for sync reference", "sync ref" },
> >       { "itsoffset",      HAS_ARG | OPT_TIME | OPT_OFFSET |
> >                           OPT_EXPERT | OPT_INPUT,                      {
> .off = OFFSET(input_ts_offset) },
> >           "set the input ts offset", "time_off" },
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe".
>


More information about the ffmpeg-devel mailing list