[FFmpeg-devel] [PATCH 07/11] decklink: Add support for SCTE-104 to decklink capture
Devin Heitmueller
dheitmueller at ltnglobal.com
Tue Jan 9 03:16:54 EET 2018
Make use of libklvanc to parse SCTE-104 packets and announce them
as a new stream. Right now we just pass the payload straight
through, but once this is hooked into libklscte35 we'll be able
to generate SCTE-35 messages in the MPEG TS stream.
Note that this feature needs to be explicitly enabled by the user
through the "-enable_scte_104" option, since we cannot autodetect
the presence of SCTE-104 (because unlike with 708/AFD messages are
not set except when trigger occurs, thus the stream wouldn't get
created during the read_header phase).
Updated to reflect feedback from Derek Buitenhuis <derek.buitenhuis at gmail.com>
and Aaron Levinson <alevinsn_dev at levland.net>
Signed-off-by: Devin Heitmueller <dheitmueller at ltnglobal.com>
---
doc/indevs.texi | 4 +++
libavcodec/avcodec.h | 1 +
libavcodec/codec_desc.c | 6 ++++
libavdevice/decklink_common.h | 6 ++++
libavdevice/decklink_common_c.h | 1 +
libavdevice/decklink_dec.cpp | 61 ++++++++++++++++++++++++++++++++++++++++-
libavdevice/decklink_dec_c.c | 1 +
libavdevice/version.h | 2 +-
8 files changed, 80 insertions(+), 2 deletions(-)
diff --git a/doc/indevs.texi b/doc/indevs.texi
index 4760d70..63dfbd4 100644
--- a/doc/indevs.texi
+++ b/doc/indevs.texi
@@ -323,6 +323,10 @@ Defaults to @samp{1073741824}.
Sets the audio sample bit depth. Must be @samp{16} or @samp{32}.
Defaults to @samp{16}.
+ at item enable_scte_104
+If set to @samp{true}, enables capture of SCTE-104 packets over SDI and
+creation of the corresponding stream at startup. Defaults to @samp{false}.
+
@end table
@subsection Examples
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 5fa028e..c61b8a1 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -668,6 +668,7 @@ enum AVCodecID {
AV_CODEC_ID_TTF = 0x18000,
AV_CODEC_ID_SCTE_35, ///< Contain timestamp estimated through PCR of program stream.
+ AV_CODEC_ID_SCTE_104,
AV_CODEC_ID_BINTEXT = 0x18800,
AV_CODEC_ID_XBIN,
AV_CODEC_ID_IDF,
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index c3688de..e198985 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -3103,6 +3103,12 @@ static const AVCodecDescriptor codec_descriptors[] = {
.name = "scte_35",
.long_name = NULL_IF_CONFIG_SMALL("SCTE 35 Message Queue"),
},
+ {
+ .id = AV_CODEC_ID_SCTE_104,
+ .type = AVMEDIA_TYPE_DATA,
+ .name = "scte_104",
+ .long_name = NULL_IF_CONFIG_SMALL("SCTE 104 Digital Program Insertion"),
+ },
/* deprecated codec ids */
};
diff --git a/libavdevice/decklink_common.h b/libavdevice/decklink_common.h
index b262780..ffc0d17 100644
--- a/libavdevice/decklink_common.h
+++ b/libavdevice/decklink_common.h
@@ -41,6 +41,10 @@
Actual number for any particular model of card may be lower */
#define DECKLINK_MAX_AUDIO_CHANNELS 32
+/* This isn't actually tied to the Blackmagic hardware - it's an arbitrary
+ number used to size the array of streams */
+#define DECKLINK_MAX_DATA_STREAMS 16
+
class decklink_output_callback;
class decklink_input_callback;
@@ -92,6 +96,8 @@ struct decklink_ctx {
unsigned int dropped;
AVStream *audio_st[DECKLINK_MAX_AUDIO_CHANNELS];
int num_audio_streams;
+ AVStream *data_st[DECKLINK_MAX_DATA_STREAMS];
+ int num_data_streams;
AVStream *video_st;
AVStream *teletext_st;
uint16_t cdp_sequence_num;
diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_c.h
index 3a21bae..3f22094 100644
--- a/libavdevice/decklink_common_c.h
+++ b/libavdevice/decklink_common_c.h
@@ -58,6 +58,7 @@ struct decklink_cctx {
char *format_code;
int raw_format;
int64_t queue_size;
+ int enable_scte_104;
};
#endif /* AVDEVICE_DECKLINK_COMMON_C_H */
diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp
index bab3588..1074dc7 100644
--- a/libavdevice/decklink_dec.cpp
+++ b/libavdevice/decklink_dec.cpp
@@ -674,6 +674,30 @@ error:
return ret;
}
+static int setup_data(AVFormatContext *avctx)
+{
+ struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data;
+ struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
+ AVStream *st;
+
+ if (cctx->enable_scte_104) {
+ st = avformat_new_stream(avctx, NULL);
+ if (!st) {
+ av_log(avctx, AV_LOG_ERROR, "Cannot add data stream\n");
+ return AVERROR(ENOMEM);
+ }
+ st->codecpar->codec_type = AVMEDIA_TYPE_DATA;
+ st->time_base.den = ctx->bmd_tb_den;
+ st->time_base.num = ctx->bmd_tb_num;
+ st->codecpar->codec_id = AV_CODEC_ID_SCTE_104;
+ avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */
+ ctx->data_st[ctx->num_data_streams] = st;
+ ctx->num_data_streams++;
+ }
+
+ return 0;
+}
+
#if CONFIG_LIBKLVANC
/* VANC Callbacks */
struct vanc_cb_ctx {
@@ -733,12 +757,44 @@ static int cb_EIA_708B(void *callback_context, struct klvanc_context_s *ctx,
return 0;
}
+static int cb_SCTE_104(void *callback_context, struct klvanc_context_s *ctx,
+ struct klvanc_packet_scte_104_s *pkt)
+{
+ struct vanc_cb_ctx *cb_ctx = (struct vanc_cb_ctx *)callback_context;
+ decklink_cctx *decklink_cctx = (struct decklink_cctx *)cb_ctx->avctx->priv_data;
+ struct decklink_ctx *decklink_ctx = (struct decklink_ctx *)decklink_cctx->ctx;
+ AVPacket avpkt;
+ av_init_packet(&avpkt);
+
+ avpkt.stream_index = -1;
+ for (int i = 0; i < decklink_ctx->num_data_streams; i++) {
+ if (decklink_ctx->data_st[i]->codecpar->codec_id = AV_CODEC_ID_SCTE_104) {
+ avpkt.stream_index = decklink_ctx->data_st[i]->index;
+ break;
+ }
+ }
+ if (avpkt.stream_index == -1) {
+ /* SCTE-104 packet received but forwarding is disabled */
+ return 0;
+ }
+
+ avpkt.pts = cb_ctx->pkt->pts;
+ avpkt.dts = cb_ctx->pkt->dts;
+ avpkt.data = pkt->payload;
+ avpkt.size = pkt->payloadLengthBytes;
+ if (avpacket_queue_put(&decklink_ctx->queue, &avpkt) < 0) {
+ ++decklink_ctx->dropped;
+ }
+
+ return 0;
+}
+
static struct klvanc_callbacks_s callbacks =
{
cb_AFD,
cb_EIA_708B,
NULL,
- NULL,
+ cb_SCTE_104,
NULL,
NULL,
};
@@ -1289,6 +1345,9 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx)
ctx->teletext_st = st;
}
+ /* Setup streams. */
+ setup_data(avctx);
+
if (cctx->audio_mode == AUDIO_MODE_BUNDLED) {
av_log(avctx, AV_LOG_VERBOSE, "Using %d input audio channels\n", ctx->audio_st[0]->codecpar->channels);
result = ctx->dli->EnableAudioInput(bmdAudioSampleRate48kHz,
diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c
index fe8e9fd..35895fb 100644
--- a/libavdevice/decklink_dec_c.c
+++ b/libavdevice/decklink_dec_c.c
@@ -76,6 +76,7 @@ static const AVOption options[] = {
{ "draw_bars", "draw bars on signal loss" , OFFSET(draw_bars), AV_OPT_TYPE_BOOL, { .i64 = 1}, 0, 1, DEC },
{ "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 },
+ { "enable_scte_104", "capture SCTE-104 VANC", OFFSET(enable_scte_104), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, DEC, "enable_scte_104"},
{ NULL },
};
diff --git a/libavdevice/version.h b/libavdevice/version.h
index 364404d..0d4477f 100644
--- a/libavdevice/version.h
+++ b/libavdevice/version.h
@@ -29,7 +29,7 @@
#define LIBAVDEVICE_VERSION_MAJOR 58
#define LIBAVDEVICE_VERSION_MINOR 0
-#define LIBAVDEVICE_VERSION_MICRO 100
+#define LIBAVDEVICE_VERSION_MICRO 101
#define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \
LIBAVDEVICE_VERSION_MINOR, \
--
1.8.3.1
More information about the ffmpeg-devel
mailing list