Skip to content

Commit 9bcb86b

Browse files
MichiiRcus
authored andcommitted
avdevice/decklink_dec: extend available actions on signal loss
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 <[email protected]> Signed-off-by: Marton Balint <[email protected]>
1 parent 071c499 commit 9bcb86b

File tree

6 files changed

+59
-5
lines changed

6 files changed

+59
-5
lines changed

doc/indevs.texi

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,22 @@ Defaults to @samp{audio}.
396396
@item draw_bars
397397
If set to @samp{true}, color bars are drawn in the event of a signal loss.
398398
Defaults to @samp{true}.
399+
This option is deprecated, please use the @code{signal_loss_action} option.
400+
401+
@item signal_loss_action
402+
Sets the action to take in the event of a signal loss. Accepts one of the
403+
following values:
404+
405+
@table @option
406+
@item 1, none
407+
Do nothing on signal loss. This usually results in black frames.
408+
@item 2, bars
409+
Draw color bars on signal loss. Only supported for 8-bit input signals.
410+
@item 3, repeat
411+
Repeat the last video frame on signal loss.
412+
@end table
413+
414+
Defaults to @samp{bars}.
399415

400416
@item queue_size
401417
Sets maximum input buffer size in bytes. If the buffering reaches this value,

libavdevice/decklink_common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ struct decklink_ctx {
147147
DecklinkPtsSource video_pts_source;
148148
int draw_bars;
149149
BMDPixelFormat raw_format;
150+
DecklinkSignalLossAction signal_loss_action;
150151

151152
int frames_preroll;
152153
int frames_buffer;

libavdevice/decklink_common_c.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ typedef enum DecklinkPtsSource {
3737
PTS_SRC_NB
3838
} DecklinkPtsSource;
3939

40+
typedef enum DecklinkSignalLossAction {
41+
SIGNAL_LOSS_NONE = 1,
42+
SIGNAL_LOSS_REPEAT = 2,
43+
SIGNAL_LOSS_BARS = 3
44+
} DecklinkSignalLossAction;
45+
4046
struct decklink_cctx {
4147
const AVClass *cclass;
4248

@@ -68,6 +74,7 @@ struct decklink_cctx {
6874
int64_t timestamp_align;
6975
int timing_offset;
7076
int wait_for_tc;
77+
DecklinkSignalLossAction signal_loss_action;
7178
};
7279

7380
#endif /* AVDEVICE_DECKLINK_COMMON_C_H */

libavdevice/decklink_dec.cpp

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,7 @@ class decklink_input_callback : public IDeckLinkInputCallback
593593
int no_video;
594594
int64_t initial_video_pts;
595595
int64_t initial_audio_pts;
596+
IDeckLinkVideoInputFrame* last_video_frame;
596597
};
597598

598599
decklink_input_callback::decklink_input_callback(AVFormatContext *_avctx) : _refs(1)
@@ -602,10 +603,13 @@ decklink_input_callback::decklink_input_callback(AVFormatContext *_avctx) : _ref
602603
ctx = (struct decklink_ctx *)cctx->ctx;
603604
no_video = 0;
604605
initial_audio_pts = initial_video_pts = AV_NOPTS_VALUE;
606+
last_video_frame = nullptr;
605607
}
606608

607609
decklink_input_callback::~decklink_input_callback()
608610
{
611+
if (last_video_frame)
612+
last_video_frame->Release();
609613
}
610614

611615
ULONG decklink_input_callback::AddRef(void)
@@ -729,6 +733,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
729733
BMDTimeValue frameTime;
730734
BMDTimeValue frameDuration;
731735
int64_t wallclock = 0, abs_wallclock = 0;
736+
int64_t video_pkt_pts, audio_pkt_pts;
732737
struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
733738

734739
if (ctx->autodetect) {
@@ -755,6 +760,8 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
755760
wallclock = av_gettime_relative();
756761
if (ctx->audio_pts_source == PTS_SRC_ABS_WALLCLOCK || ctx->video_pts_source == PTS_SRC_ABS_WALLCLOCK)
757762
abs_wallclock = av_gettime();
763+
video_pkt_pts = get_pkt_pts(videoFrame, audioFrame, wallclock, abs_wallclock, ctx->video_pts_source, ctx->video_st->time_base, &initial_video_pts, cctx->copyts);
764+
audio_pkt_pts = get_pkt_pts(videoFrame, audioFrame, wallclock, abs_wallclock, ctx->audio_pts_source, ctx->audio_st->time_base, &initial_audio_pts, cctx->copyts);
758765

759766
// Handle Video Frame
760767
if (videoFrame) {
@@ -773,7 +780,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
773780
ctx->video_st->time_base.den);
774781

775782
if (videoFrame->GetFlags() & bmdFrameHasNoInputSource) {
776-
if (ctx->draw_bars && videoFrame->GetPixelFormat() == bmdFormat8BitYUV) {
783+
if (ctx->signal_loss_action == SIGNAL_LOSS_BARS && videoFrame->GetPixelFormat() == bmdFormat8BitYUV) {
777784
unsigned bars[8] = {
778785
0xEA80EA80, 0xD292D210, 0xA910A9A5, 0x90229035,
779786
0x6ADD6ACA, 0x51EF515A, 0x286D28EF, 0x10801080 };
@@ -785,6 +792,9 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
785792
for (int x = 0; x < width; x += 2)
786793
*p++ = bars[(x * 8) / width];
787794
}
795+
} else if (ctx->signal_loss_action == SIGNAL_LOSS_REPEAT && last_video_frame) {
796+
videoFrame = last_video_frame;
797+
videoFrame->GetBytes(&frameBytes);
788798
}
789799

790800
if (!no_video) {
@@ -793,6 +803,12 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
793803
}
794804
no_video = 1;
795805
} else {
806+
if (ctx->signal_loss_action == SIGNAL_LOSS_REPEAT) {
807+
if (last_video_frame)
808+
last_video_frame->Release();
809+
last_video_frame = videoFrame;
810+
last_video_frame->AddRef();
811+
}
796812
if (no_video) {
797813
av_log(avctx, AV_LOG_WARNING, "Frame received (#%lu) - Input returned "
798814
"- Frames dropped %u\n", ctx->frameCount, ++ctx->dropped);
@@ -846,7 +862,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
846862
return S_OK;
847863
}
848864

849-
pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, abs_wallclock, ctx->video_pts_source, ctx->video_st->time_base, &initial_video_pts, cctx->copyts);
865+
pkt.pts = video_pkt_pts;
850866
pkt.dts = pkt.pts;
851867

852868
pkt.duration = frameDuration;
@@ -949,7 +965,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
949965
pkt.size = audioFrame->GetSampleFrameCount() * ctx->audio_st->codecpar->ch_layout.nb_channels * (ctx->audio_depth / 8);
950966
audioFrame->GetBytes(&audioFrameBytes);
951967
audioFrame->GetPacketTime(&audio_pts, ctx->audio_st->time_base.den);
952-
pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, abs_wallclock, ctx->audio_pts_source, ctx->audio_st->time_base, &initial_audio_pts, cctx->copyts);
968+
pkt.pts = audio_pkt_pts;
953969
pkt.dts = pkt.pts;
954970

955971
//fprintf(stderr,"Audio Frame size %d ts %d\n", pkt.size, pkt.pts);
@@ -1036,6 +1052,7 @@ av_cold int ff_decklink_read_close(AVFormatContext *avctx)
10361052
ctx->dli->StopStreams();
10371053
ctx->dli->DisableVideoInput();
10381054
ctx->dli->DisableAudioInput();
1055+
ctx->dli->SetCallback(nullptr);
10391056
}
10401057

10411058
ff_decklink_cleanup(avctx);
@@ -1074,6 +1091,15 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx)
10741091
ctx->audio_pts_source = cctx->audio_pts_source;
10751092
ctx->video_pts_source = cctx->video_pts_source;
10761093
ctx->draw_bars = cctx->draw_bars;
1094+
ctx->signal_loss_action = cctx->signal_loss_action;
1095+
if (!ctx->draw_bars && ctx->signal_loss_action == SIGNAL_LOSS_BARS) {
1096+
ctx->signal_loss_action = SIGNAL_LOSS_NONE;
1097+
av_log(avctx, AV_LOG_WARNING, "Setting signal_loss_action to none because draw_bars is false\n");
1098+
}
1099+
if (!ctx->draw_bars && ctx->signal_loss_action != SIGNAL_LOSS_NONE) {
1100+
av_log(avctx, AV_LOG_ERROR, "options draw_bars and signal_loss_action are mutually exclusive\n");
1101+
return AVERROR(EINVAL);
1102+
}
10771103
ctx->audio_depth = cctx->audio_depth;
10781104
if (cctx->raw_format > 0 && (unsigned int)cctx->raw_format < FF_ARRAY_ELEMS(decklink_raw_format_map))
10791105
ctx->raw_format = decklink_raw_format_map[cctx->raw_format];

libavdevice/decklink_dec_c.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,16 @@ static const AVOption options[] = {
9595
{ "reference", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_REFERENCE}, 0, 0, DEC, .unit = "pts_source"},
9696
{ "wallclock", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_WALLCLOCK}, 0, 0, DEC, .unit = "pts_source"},
9797
{ "abs_wallclock", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_ABS_WALLCLOCK}, 0, 0, DEC, .unit = "pts_source"},
98-
{ "draw_bars", "draw bars on signal loss" , OFFSET(draw_bars), AV_OPT_TYPE_BOOL, { .i64 = 1}, 0, 1, DEC },
98+
{ "draw_bars", "use option signal_loss_action instead" , OFFSET(draw_bars), AV_OPT_TYPE_BOOL, { .i64 = 1}, 0, 1, DEC | AV_OPT_FLAG_DEPRECATED },
9999
{ "queue_size", "input queue buffer size", OFFSET(queue_size), AV_OPT_TYPE_INT64, { .i64 = (1024 * 1024 * 1024)}, 0, INT64_MAX, DEC },
100100
{ "audio_depth", "audio bitdepth (16 or 32)", OFFSET(audio_depth), AV_OPT_TYPE_INT, { .i64 = 16}, 16, 32, DEC },
101101
{ "decklink_copyts", "copy timestamps, do not remove the initial offset", OFFSET(copyts), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, DEC },
102102
{ "timestamp_align", "capture start time alignment (in seconds)", OFFSET(timestamp_align), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT_MAX, DEC },
103103
{ "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 },
104+
{ "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, .unit = "signal_loss_action" },
105+
{ "none", "do not do anything (usually leads to black frames)", 0, AV_OPT_TYPE_CONST, { .i64 = SIGNAL_LOSS_NONE }, 0, 0, DEC, .unit = "signal_loss_action"},
106+
{ "bars", "draw color bars (only supported for 8-bit signals)", 0, AV_OPT_TYPE_CONST, { .i64 = SIGNAL_LOSS_BARS }, 0, 0, DEC, .unit = "signal_loss_action"},
107+
{ "repeat", "repeat the last video frame", 0, AV_OPT_TYPE_CONST, { .i64 = SIGNAL_LOSS_REPEAT }, 0, 0, DEC, .unit = "signal_loss_action"},
104108
{ NULL },
105109
};
106110

libavdevice/version.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
#include "version_major.h"
3131

3232
#define LIBAVDEVICE_VERSION_MINOR 2
33-
#define LIBAVDEVICE_VERSION_MICRO 100
33+
#define LIBAVDEVICE_VERSION_MICRO 101
3434

3535
#define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \
3636
LIBAVDEVICE_VERSION_MINOR, \

0 commit comments

Comments
 (0)