[FFmpeg-devel] [PATCH] libavdevice/decklink: extend available actions on signal loss
Michael Riedl
michael.riedl at nativewaves.com
Thu Nov 2 15:01:16 EET 2023
On 9/25/23 13:58, Michael Riedl wrote:
> Deprecate the option 'draw_bars' in favor of the new option 'signal_loss_action',
> which controls the behavior when the input signal is not available
> (including the behavior previously available through draw_bars).
> The default behavior remains unchanged to be backwards compatible.
> The new option is more flexible for extending now and in the future.
>
> The new value 'repeat' repeats the last video frame.
> This is useful for very short dropouts and was not available before.
>
> Signed-off-by: Michael Riedl <michael.riedl at nativewaves.com>
> ---
> doc/indevs.texi | 16 ++++++++++++++++
> libavdevice/decklink_common.h | 1 +
> libavdevice/decklink_common_c.h | 7 +++++++
> libavdevice/decklink_dec.cpp | 23 ++++++++++++++++++++++-
> libavdevice/decklink_dec_c.c | 6 +++++-
> 5 files changed, 51 insertions(+), 2 deletions(-)
>
> diff --git a/doc/indevs.texi b/doc/indevs.texi
> index 863536a34d5..a985d58ce7f 100644
> --- a/doc/indevs.texi
> +++ b/doc/indevs.texi
> @@ -395,6 +395,22 @@ Defaults to @samp{audio}.
> @item draw_bars
> If set to @samp{true}, color bars are drawn in the event of a signal loss.
> Defaults to @samp{true}.
> +This option is deprecated, please use the @code{signal_loss_action} option.
> +
> + at item signal_loss_action
> +Sets the action to take in the event of a signal loss. Accepts one of the
> +following values:
> +
> + at table @option
> + at item 1, none
> +Do nothing on signal loss. This usually results in black frames.
> + at item 2, bars
> +Draw color bars on signal loss. Only supported for 8-bit input signals.
> + at item 3, repeat
> +Repeat the last video frame on signal loss.
> + at end table
> +
> +Defaults to @samp{bars}.
>
> @item queue_size
> Sets maximum input buffer size in bytes. If the buffering reaches this value,
> diff --git a/libavdevice/decklink_common.h b/libavdevice/decklink_common.h
> index 34ab1b96700..be666212e6c 100644
> --- a/libavdevice/decklink_common.h
> +++ b/libavdevice/decklink_common.h
> @@ -146,6 +146,7 @@ struct decklink_ctx {
> DecklinkPtsSource video_pts_source;
> int draw_bars;
> BMDPixelFormat raw_format;
> + DecklinkSignalLossAction signal_loss_action;
>
> int frames_preroll;
> int frames_buffer;
> diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_c.h
> index 9c55d891494..53d2c583e7e 100644
> --- a/libavdevice/decklink_common_c.h
> +++ b/libavdevice/decklink_common_c.h
> @@ -37,6 +37,12 @@ typedef enum DecklinkPtsSource {
> PTS_SRC_NB
> } DecklinkPtsSource;
>
> +typedef enum DecklinkSignalLossAction {
> + SIGNAL_LOSS_NONE = 1,
> + SIGNAL_LOSS_REPEAT = 2,
> + SIGNAL_LOSS_BARS = 3
> +} DecklinkSignalLossAction;
> +
> struct decklink_cctx {
> const AVClass *cclass;
>
> @@ -68,6 +74,7 @@ struct decklink_cctx {
> int64_t timestamp_align;
> int timing_offset;
> int wait_for_tc;
> + DecklinkSignalLossAction signal_loss_action;
> };
>
> #endif /* AVDEVICE_DECKLINK_COMMON_C_H */
> diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp
> index 11640f72caa..f6095c72359 100644
> --- a/libavdevice/decklink_dec.cpp
> +++ b/libavdevice/decklink_dec.cpp
> @@ -593,6 +593,7 @@ private:
> int no_video;
> int64_t initial_video_pts;
> int64_t initial_audio_pts;
> + IDeckLinkVideoInputFrame* last_video_frame;
> };
>
> decklink_input_callback::decklink_input_callback(AVFormatContext *_avctx) : _refs(1)
> @@ -602,10 +603,13 @@ decklink_input_callback::decklink_input_callback(AVFormatContext *_avctx) : _ref
> ctx = (struct decklink_ctx *)cctx->ctx;
> no_video = 0;
> initial_audio_pts = initial_video_pts = AV_NOPTS_VALUE;
> + last_video_frame = nullptr;
> }
>
> decklink_input_callback::~decklink_input_callback()
> {
> + if (last_video_frame)
> + last_video_frame->Release();
> }
>
> ULONG decklink_input_callback::AddRef(void)
> @@ -773,7 +777,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
> ctx->video_st->time_base.den);
>
> if (videoFrame->GetFlags() & bmdFrameHasNoInputSource) {
> - if (ctx->draw_bars && videoFrame->GetPixelFormat() == bmdFormat8BitYUV) {
> + if (ctx->signal_loss_action == SIGNAL_LOSS_BARS && videoFrame->GetPixelFormat() == bmdFormat8BitYUV) {
> unsigned bars[8] = {
> 0xEA80EA80, 0xD292D210, 0xA910A9A5, 0x90229035,
> 0x6ADD6ACA, 0x51EF515A, 0x286D28EF, 0x10801080 };
> @@ -785,6 +789,8 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
> for (int x = 0; x < width; x += 2)
> *p++ = bars[(x * 8) / width];
> }
> + } else if (ctx->signal_loss_action == SIGNAL_LOSS_REPEAT) {
> + last_video_frame->GetBytes(&frameBytes);
> }
>
> if (!no_video) {
> @@ -793,6 +799,12 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
> }
> no_video = 1;
> } else {
> + if (ctx->signal_loss_action == SIGNAL_LOSS_REPEAT) {
> + if (last_video_frame)
> + last_video_frame->Release();
> + last_video_frame = videoFrame;
> + last_video_frame->AddRef();
> + }
> if (no_video) {
> av_log(avctx, AV_LOG_WARNING, "Frame received (#%lu) - Input returned "
> "- Frames dropped %u\n", ctx->frameCount, ++ctx->dropped);
> @@ -1074,6 +1086,15 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx)
> ctx->audio_pts_source = cctx->audio_pts_source;
> ctx->video_pts_source = cctx->video_pts_source;
> ctx->draw_bars = cctx->draw_bars;
> + ctx->signal_loss_action = cctx->signal_loss_action;
> + if (!ctx->draw_bars && ctx->signal_loss_action == SIGNAL_LOSS_BARS) {
> + ctx->signal_loss_action = SIGNAL_LOSS_NONE;
> + av_log(avctx, AV_LOG_WARNING, "Setting signal_loss_action to none because draw_bars is false\n");
> + }
> + if (!ctx->draw_bars && ctx->signal_loss_action != SIGNAL_LOSS_NONE) {
> + av_log(avctx, AV_LOG_ERROR, "options draw_bars and signal_loss_action are mutually exclusive\n");
> + return AVERROR(EINVAL);
> + }
> ctx->audio_depth = cctx->audio_depth;
> if (cctx->raw_format > 0 && (unsigned int)cctx->raw_format < FF_ARRAY_ELEMS(decklink_raw_format_map))
> ctx->raw_format = decklink_raw_format_map[cctx->raw_format];
> diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c
> index 2159702c96b..7c0ef4f8c23 100644
> --- a/libavdevice/decklink_dec_c.c
> +++ b/libavdevice/decklink_dec_c.c
> @@ -94,12 +94,16 @@ static const AVOption options[] = {
> { "reference", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_REFERENCE}, 0, 0, DEC, "pts_source"},
> { "wallclock", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_WALLCLOCK}, 0, 0, DEC, "pts_source"},
> { "abs_wallclock", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_ABS_WALLCLOCK}, 0, 0, DEC, "pts_source"},
> - { "draw_bars", "draw bars on signal loss" , OFFSET(draw_bars), AV_OPT_TYPE_BOOL, { .i64 = 1}, 0, 1, DEC },
> + { "draw_bars", "use option signal_loss_action instead" , OFFSET(draw_bars), AV_OPT_TYPE_BOOL, { .i64 = 1}, 0, 1, DEC | AV_OPT_FLAG_DEPRECATED },
> { "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_DURATION, { .i64 = 0 }, 0, INT_MAX, DEC },
> { "wait_for_tc", "drop frames till a frame with timecode is received. TC format must be set", OFFSET(wait_for_tc), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, DEC },
> + { "signal_loss_action", "action on signal loss", OFFSET(signal_loss_action), AV_OPT_TYPE_INT, { .i64 = SIGNAL_LOSS_BARS }, SIGNAL_LOSS_NONE, SIGNAL_LOSS_BARS, DEC, "signal_loss_action" },
> + { "none", "do not do anything (usually leads to black frames)", 0, AV_OPT_TYPE_CONST, { .i64 = SIGNAL_LOSS_NONE }, 0, 0, DEC, "signal_loss_action"},
> + { "bars", "draw color bars (only supported for 8-bit signals)", 0, AV_OPT_TYPE_CONST, { .i64 = SIGNAL_LOSS_BARS }, 0, 0, DEC, "signal_loss_action"},
> + { "repeat", "repeat the last video frame", 0, AV_OPT_TYPE_CONST, { .i64 = SIGNAL_LOSS_REPEAT }, 0, 0, DEC, "signal_loss_action"},
> { NULL },
> };
Ping
More information about the ffmpeg-devel
mailing list