Message ID | 20180109011658.72370-8-dheitmueller@ltnglobal.com |
---|---|
State | New |
Headers | show |
On Mon, 8 Jan 2018, 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 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@gmail.com> > and Aaron Levinson <alevinsn_dev@levland.net> > > Signed-off-by: Devin Heitmueller <dheitmueller@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}. > > +@item enable_scte_104 You can loose the "enable_" from the name if you want, some other boolean options don't have it. I don't mind either way. > +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 As long as only SCTE is supported, you can define this to 1... > + > 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) I'd rather call this setup_data_streams. > +{ > + 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; > + } > + } You might just simply save the scte_stream_id in the context, I don't quite see what might be the benefit of dynamically finding the stream. > + 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"}, AV_OPT_TYPE_BOOL > { 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, \ > -- Regards, Marton
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}. +@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, \
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@gmail.com> and Aaron Levinson <alevinsn_dev@levland.net> Signed-off-by: Devin Heitmueller <dheitmueller@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(-)