diff --git a/doc/indevs.texi b/doc/indevs.texi
index 734fc657523..cdf44a66382 100644
--- a/doc/indevs.texi
+++ b/doc/indevs.texi
@@ -396,6 +396,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.
+
+@item signal_loss_action
+Sets the action to take in the event of a signal loss. Accepts one of the
+following values:
+
+@table @option
+@item 1, none
+Do nothing on signal loss. This usually results in black frames.
+@item 2, bars
+Draw color bars on signal loss. Only supported for 8-bit input signals.
+@item 3, repeat
+Repeat the last video frame on signal loss.
+@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 c54a635876c..6b32dc2d09c 100644
--- a/libavdevice/decklink_common.h
+++ b/libavdevice/decklink_common.h
@@ -147,6 +147,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 671573853ba..1c2d08ea9fc 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 e211c9d3f4e..b8cdb7bd8e1 100644
--- a/libavdevice/decklink_dec_c.c
+++ b/libavdevice/decklink_dec_c.c
@@ -95,12 +95,16 @@ static const AVOption options[] = {
     { "reference",     NULL,                                          0,  AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_REFERENCE}, 0, 0, DEC, .unit = "pts_source"},
     { "wallclock",     NULL,                                          0,  AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_WALLCLOCK}, 0, 0, DEC, .unit = "pts_source"},
     { "abs_wallclock", NULL,                                          0,  AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_ABS_WALLCLOCK}, 0, 0, DEC, .unit = "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, .unit = "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, .unit = "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, .unit = "signal_loss_action"},
+    { "repeat", "repeat the last video frame", 0,  AV_OPT_TYPE_CONST, { .i64 = SIGNAL_LOSS_REPEAT }, 0, 0, DEC, .unit = "signal_loss_action"},
     { NULL },
 };
 
