[FFmpeg-devel] [PATCH 7/8] decklink: Add support for SCTE-104 to decklink capture
Aaron Levinson
alevinsn_dev at levland.net
Sat Dec 30 10:11:01 EET 2017
On 12/29/2017 10:12 AM, Devin Heitmueller wrote:
> 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 hoooked into libklscte35 we'll be able
"hoooked" -> "hooked"
> 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>
>
> Signed-off-by: Devin Heitmueller <dheitmueller at ltnglobal.com>
> ---
> 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 +-
> 7 files changed, 76 insertions(+), 2 deletions(-)
>
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index 4f7b6df09d..2b4a0bd669 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 c3688de1d6..e198985bb4 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 06b241029e..4d2052ea79 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 02011ed53b..cb73ec990b 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 86db6d8fbd..f3f0d989bf 100644
> --- a/libavdevice/decklink_dec.cpp
> +++ b/libavdevice/decklink_dec.cpp
> @@ -672,6 +672,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;
I wonder if there is any reason to set time_base here. Aren't the
triggers relatively infrequent?
> + 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 {
> @@ -731,12 +755,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,
> };
> @@ -1285,6 +1341,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_DISCRETE) {
> 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 d3d8c848cf..122da08fa1 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 364404d65e..0d4477f82e 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, \
>
Aaron Levinson
More information about the ffmpeg-devel
mailing list