History

avdevice/decklink_enc: add support for SMPTE 2038 VANC packet output

Support decoding and embedding VANC packets delivered via SMPTE 2038 into the SDI output. We leverage an intermediate queue because data packets are announced separately from video but we need to embed the data into the video frame when it is output. Note that this patch has some additional abstraction for data streams in general as opposed to just SMPTE 2038 packets. This is because subsequent patches will introduce support for other data codecs. Thanks to Marton Balint for review/feedback.

Devin Heitmueller committed 3 years ago

Commit ac424721 parent e7d800f7 files · +121 −2Browse files

Showing the changes to libavdevice/decklink_enc.cpp (1 of 7 files). Show all

Unified · Split

libavdevice/decklink_enc.cpp+93−1
@@ -345,6 +345,25 @@ static int decklink_setup_subtitle(AVFormatContext *avctx, AVStream *st) · 344 unmodified lines
345345 return ret;
346346 }
347347
348+static int decklink_setup_data(AVFormatContext *avctx, AVStream *st)
349+{
350+ int ret = -1;
351+
352+ switch(st->codecpar->codec_id) {
353+#if CONFIG_LIBKLVANC
354+ case AV_CODEC_ID_SMPTE_2038:
355+ /* No specific setup required */
356+ ret = 0;
357+ break;
358+#endif
359+ default:
360+ av_log(avctx, AV_LOG_ERROR, "Unsupported data codec specified\n");
361+ break;
362+ }
363+
364+ return ret;
365+}
366+
348367 av_cold int ff_decklink_write_trailer(AVFormatContext *avctx)
349368 {
350369 struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data;
@@ -370,6 +389,7 @@ av_cold int ff_decklink_write_trailer(AVFormatContext *avctx) · 19 unmodified lines
370389 #if CONFIG_LIBKLVANC
371390 klvanc_context_destroy(ctx->vanc_ctx);
372391 #endif
392+ ff_decklink_packet_queue_end(&ctx->vanc_queue);
373393
374394 ff_ccfifo_uninit(&ctx->cc_fifo);
375395 av_freep(&cctx->ctx);
@@ -552,6 +572,58 @@ static int decklink_construct_vanc(AVFormatContext *avctx, struct decklink_ctx * · 176 unmodified lines
552572 construct_cc(avctx, ctx, pkt, &vanc_lines);
553573 construct_afd(avctx, ctx, pkt, &vanc_lines, st);
554574
575+ /* See if there any pending data packets to process */
576+ while (ff_decklink_packet_queue_size(&ctx->vanc_queue) > 0) {
577+ AVStream *vanc_st;
578+ AVPacket vanc_pkt;
579+ int64_t pts;
580+
581+ pts = ff_decklink_packet_queue_peekpts(&ctx->vanc_queue);
582+ if (pts > ctx->last_pts) {
583+ /* We haven't gotten to the video frame we are supposed to inject
584+ the oldest VANC packet into yet, so leave it on the queue... */
585+ break;
586+ }
587+
588+ ret = ff_decklink_packet_queue_get(&ctx->vanc_queue, &vanc_pkt, 1);
589+ if (vanc_pkt.pts + 1 < ctx->last_pts) {
590+ av_log(avctx, AV_LOG_WARNING, "VANC packet too old, throwing away\n");
591+ av_packet_unref(&vanc_pkt);
592+ continue;
593+ }
594+
595+ vanc_st = avctx->streams[vanc_pkt.stream_index];
596+ if (vanc_st->codecpar->codec_id == AV_CODEC_ID_SMPTE_2038) {
597+ struct klvanc_smpte2038_anc_data_packet_s *pkt_2038 = NULL;
598+
599+ klvanc_smpte2038_parse_pes_payload(vanc_pkt.data, vanc_pkt.size, &pkt_2038);
600+ if (pkt_2038 == NULL) {
601+ av_log(avctx, AV_LOG_ERROR, "failed to decode SMPTE 2038 PES packet");
602+ av_packet_unref(&vanc_pkt);
603+ continue;
604+ }
605+ for (int i = 0; i < pkt_2038->lineCount; i++) {
606+ struct klvanc_smpte2038_anc_data_line_s *l = &pkt_2038->lines[i];
607+ uint16_t *vancWords = NULL;
608+ uint16_t vancWordCount;
609+
610+ if (klvanc_smpte2038_convert_line_to_words(l, &vancWords,
611+ &vancWordCount) < 0)
612+ break;
613+
614+ ret = klvanc_line_insert(ctx->vanc_ctx, &vanc_lines, vancWords,
615+ vancWordCount, l->line_number, 0);
616+ free(vancWords);
617+ if (ret != 0) {
618+ av_log(avctx, AV_LOG_ERROR, "VANC line insertion failed\n");
619+ break;
620+ }
621+ }
622+ klvanc_smpte2038_anc_data_packet_free(pkt_2038);
623+ }
624+ av_packet_unref(&vanc_pkt);
625+ }
626+
555627 IDeckLinkVideoFrameAncillary *vanc;
556628 int result = ctx->dlo->CreateAncillaryData(bmdFormat10BitYUV, &vanc);
557629 if (result != S_OK) {
@@ -750,6 +822,18 @@ static int decklink_write_subtitle_packet(AVFormatContext *avctx, AVPacket *pkt) · 192 unmodified lines
750822 return 0;
751823 }
752824
825+static int decklink_write_data_packet(AVFormatContext *avctx, AVPacket *pkt)
826+{
827+ struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data;
828+ struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
829+
830+ if (ff_decklink_packet_queue_put(&ctx->vanc_queue, pkt) < 0) {
831+ av_log(avctx, AV_LOG_WARNING, "Failed to queue DATA packet\n");
832+ }
833+
834+ return 0;
835+}
836+
753837 extern "C" {
754838
755839 av_cold int ff_decklink_write_header(AVFormatContext *avctx)
@@ -814,6 +898,9 @@ av_cold int ff_decklink_write_header(AVFormatContext *avctx) · 58 unmodified lines
814898 } else if (c->codec_type == AVMEDIA_TYPE_VIDEO) {
815899 if (decklink_setup_video(avctx, st))
816900 goto error;
901+ } else if (c->codec_type == AVMEDIA_TYPE_DATA) {
902+ if (decklink_setup_data(avctx, st))
903+ goto error;
817904 } else if (c->codec_type == AVMEDIA_TYPE_SUBTITLE) {
818905 if (decklink_setup_subtitle(avctx, st))
819906 goto error;
@@ -823,13 +910,16 @@ av_cold int ff_decklink_write_header(AVFormatContext *avctx) · 3 unmodified lines
823910 }
824911 }
825912
913+ /* Reconfigure the data/subtitle stream clocks to match the video */
826914 for (n = 0; n < avctx->nb_streams; n++) {
827915 AVStream *st = avctx->streams[n];
828916 AVCodecParameters *c = st->codecpar;
829917
830− if(c->codec_type == AVMEDIA_TYPE_SUBTITLE)
918+ if(c->codec_type == AVMEDIA_TYPE_DATA ||
919+ c->codec_type == AVMEDIA_TYPE_SUBTITLE)
831920 avpriv_set_pts_info(st, 64, ctx->bmd_tb_num, ctx->bmd_tb_den);
832921 }
922+ ff_decklink_packet_queue_init(avctx, &ctx->vanc_queue, cctx->vanc_queue_size);
833923
834924 ret = ff_ccfifo_init(&ctx->cc_fifo, av_make_q(ctx->bmd_tb_den, ctx->bmd_tb_num), avctx);
835925 if (ret < 0) {
@@ -852,6 +942,8 @@ int ff_decklink_write_packet(AVFormatContext *avctx, AVPacket *pkt) · 16 unmodified lines
852942 return decklink_write_video_packet(avctx, pkt);
853943 else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
854944 return decklink_write_audio_packet(avctx, pkt);
945+ else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA)
946+ return decklink_write_data_packet(avctx, pkt);
855947 else if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)
856948 return decklink_write_subtitle_packet(avctx, pkt);
857949

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t