On Mon, 24 Sep 2018, Karthick J wrote:
From: Karthick Jeyapal <kjeya...@akamai.com> This option is useful for maintaining input synchronization across N different hardware devices deployed for 'N-way' redundancy. The system time of different hardware devices should be synchronized with protocols such as NTP or PTP, before using this option.
Here is a review of the patch if you want to proceed with implementing the feature in decklink. The introduced code can be simple/small enough that I think it is OK to include it if you prefer that.
--- doc/indevs.texi | 10 ++++++++++ libavdevice/decklink_common_c.h | 1 + libavdevice/decklink_dec.cpp | 20 ++++++++++++++++++++ libavdevice/decklink_dec_c.c | 1 + 4 files changed, 32 insertions(+) diff --git a/doc/indevs.texi b/doc/indevs.texi index ed2784b..dfd530a 100644 --- a/doc/indevs.texi +++ b/doc/indevs.texi @@ -371,6 +371,16 @@ If set to @option{true}, timestamps are forwarded as they are without removing the initial offset. Defaults to @option{false}. +@item timestamp_align +Capture start time alignment in seconds. If set to nonzero, input frames are +dropped till the system timestamp aligns with configured value. +Alignment difference of upto one frame duration is tolerated. +This is useful for maintaining input synchronization across N different +hardware devices deployed for 'N-way' redundancy. The system time of different +hardware devices should be synchronized with protocols such as NTP or PTP, +before using this option. +Defaults to @samp{0}.
This approach is not perfect. If frame callbacks are roughly at the same time as the alignment, then - because of the jitter of the callbacks - segments can be skipped or 1 frame difference is possible. At least mention this in the docs.
Also I remember having some burst callbacks in case of signal loss/return on newer DeckLink models, that might mess this up as well.
An always working synchornization method probably needs a continous SDI timecode which is unfortunately not an option in most cases.
+ @end table @subsection Examples diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_c.h index 32a5d70..c4a8985 100644 --- a/libavdevice/decklink_common_c.h +++ b/libavdevice/decklink_common_c.h @@ -56,6 +56,7 @@ struct decklink_cctx { int raw_format; int64_t queue_size; int copyts; + int timestamp_align;
Make this int64_t and the option below AV_OPT_TYPE_DURATION.
}; #endif /* AVDEVICE_DECKLINK_COMMON_C_H */ diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp index 7fabef2..24f5ca9 100644 --- a/libavdevice/decklink_dec.cpp +++ b/libavdevice/decklink_dec.cpp @@ -703,6 +703,26 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( return S_OK; } + // Drop the frames till system's timestamp aligns with the configured value. + if (0 == ctx->frameCount && cctx->timestamp_align) { + int64_t current_time_us = av_gettime(); + int64_t align_factor_us = (cctx->timestamp_align * 1000000); + int remainder = current_time_us % align_factor_us; + if (videoFrame) { + videoFrame->GetStreamTime(&frameTime, &frameDuration, 1000000); + } else if (audioFrame) { + long sample_count = audioFrame->GetSampleFrameCount(); + frameDuration = (long)(sample_count * 1000000) / bmdAudioSampleRate48kHz; + } else { + frameDuration = 0; + } + // threshold of one frameDuration + if(remainder > frameDuration) { + ++ctx->dropped; + return S_OK; + }
You already know the frame rate, so I'd simply write something like: if (ctx->frameCount == 0 && ctx->timestamp_align) { AVRational remainder = av_make_q(av_gettime() % cctx->timestamp_align, 1000000); if (av_cmp_q(remainder, st->video_st->time_base) > 0) { ctx->dropped++; return S_OK; } }
+ } + ctx->frameCount++; if (ctx->audio_pts_source == PTS_SRC_WALLCLOCK || ctx->video_pts_source == PTS_SRC_WALLCLOCK) wallclock = av_gettime_relative(); diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c index 6ab3819..bef9c14 100644 --- a/libavdevice/decklink_dec_c.c +++ b/libavdevice/decklink_dec_c.c @@ -84,6 +84,7 @@ static const AVOption options[] = { { "queue_size", "input queue buffer size", OFFSET(queue_size), AV_OPT_TYPE_INT64, { .i64 = (1024 * 1024 * 1024)}, 0, INT64_MAX, DEC }, { "audio_depth", "audio bitdepth (16 or 32)", OFFSET(audio_depth), AV_OPT_TYPE_INT, { .i64 = 16}, 16, 32, DEC }, { "decklink_copyts", "copy timestamps, do not remove the initial offset", OFFSET(copyts), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, DEC }, + { "timestamp_align", "Capture start time alignment (in seconds)", OFFSET(timestamp_align), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, DEC },
AV_OPT_TYPE_DURATION. Regards, Marton _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel