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
345 return ret;345 return ret;
346}346}
347 347
348static 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
348av_cold int ff_decklink_write_trailer(AVFormatContext *avctx)367av_cold int ff_decklink_write_trailer(AVFormatContext *avctx)
349{368{
350 struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data;369 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
370#if CONFIG_LIBKLVANC389#if CONFIG_LIBKLVANC
371 klvanc_context_destroy(ctx->vanc_ctx);390 klvanc_context_destroy(ctx->vanc_ctx);
372#endif391#endif
392 ff_decklink_packet_queue_end(&ctx->vanc_queue);
373 393
374 ff_ccfifo_uninit(&ctx->cc_fifo);394 ff_ccfifo_uninit(&ctx->cc_fifo);
375 av_freep(&cctx->ctx);395 av_freep(&cctx->ctx);
@@ -552,6 +572,58 @@ static int decklink_construct_vanc(AVFormatContext *avctx, struct decklink_ctx * · 176 unmodified lines
552 construct_cc(avctx, ctx, pkt, &vanc_lines);572 construct_cc(avctx, ctx, pkt, &vanc_lines);
553 construct_afd(avctx, ctx, pkt, &vanc_lines, st);573 construct_afd(avctx, ctx, pkt, &vanc_lines, st);
554 574
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
555 IDeckLinkVideoFrameAncillary *vanc;627 IDeckLinkVideoFrameAncillary *vanc;
556 int result = ctx->dlo->CreateAncillaryData(bmdFormat10BitYUV, &vanc);628 int result = ctx->dlo->CreateAncillaryData(bmdFormat10BitYUV, &vanc);
557 if (result != S_OK) {629 if (result != S_OK) {
@@ -750,6 +822,18 @@ static int decklink_write_subtitle_packet(AVFormatContext *avctx, AVPacket *pkt) · 192 unmodified lines
750 return 0;822 return 0;
751}823}
752 824
825static 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
753extern "C" {837extern "C" {
754 838
755av_cold int ff_decklink_write_header(AVFormatContext *avctx)839av_cold int ff_decklink_write_header(AVFormatContext *avctx)
@@ -814,6 +898,9 @@ av_cold int ff_decklink_write_header(AVFormatContext *avctx) · 58 unmodified lines
814 } else if (c->codec_type == AVMEDIA_TYPE_VIDEO) {898 } else if (c->codec_type == AVMEDIA_TYPE_VIDEO) {
815 if (decklink_setup_video(avctx, st))899 if (decklink_setup_video(avctx, st))
816 goto error;900 goto error;
901 } else if (c->codec_type == AVMEDIA_TYPE_DATA) {
902 if (decklink_setup_data(avctx, st))
903 goto error;
817 } else if (c->codec_type == AVMEDIA_TYPE_SUBTITLE) {904 } else if (c->codec_type == AVMEDIA_TYPE_SUBTITLE) {
818 if (decklink_setup_subtitle(avctx, st))905 if (decklink_setup_subtitle(avctx, st))
819 goto error;906 goto error;
@@ -823,13 +910,16 @@ av_cold int ff_decklink_write_header(AVFormatContext *avctx) · 3 unmodified lines
823 }910 }
824 }911 }
825 912
913 /* Reconfigure the data/subtitle stream clocks to match the video */
826 for (n = 0; n < avctx->nb_streams; n++) {914 for (n = 0; n < avctx->nb_streams; n++) {
827 AVStream *st = avctx->streams[n];915 AVStream *st = avctx->streams[n];
828 AVCodecParameters *c = st->codecpar;916 AVCodecParameters *c = st->codecpar;
829 917
830 if(c->codec_type == AVMEDIA_TYPE_SUBTITLE)918 if(c->codec_type == AVMEDIA_TYPE_DATA ||
919 c->codec_type == AVMEDIA_TYPE_SUBTITLE)
831 avpriv_set_pts_info(st, 64, ctx->bmd_tb_num, ctx->bmd_tb_den);920 avpriv_set_pts_info(st, 64, ctx->bmd_tb_num, ctx->bmd_tb_den);
832 }921 }
922 ff_decklink_packet_queue_init(avctx, &ctx->vanc_queue, cctx->vanc_queue_size);
833 923
834 ret = ff_ccfifo_init(&ctx->cc_fifo, av_make_q(ctx->bmd_tb_den, ctx->bmd_tb_num), avctx);924 ret = ff_ccfifo_init(&ctx->cc_fifo, av_make_q(ctx->bmd_tb_den, ctx->bmd_tb_num), avctx);
835 if (ret < 0) {925 if (ret < 0) {
@@ -852,6 +942,8 @@ int ff_decklink_write_packet(AVFormatContext *avctx, AVPacket *pkt) · 16 unmodified lines
852 return decklink_write_video_packet(avctx, pkt);942 return decklink_write_video_packet(avctx, pkt);
853 else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)943 else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
854 return decklink_write_audio_packet(avctx, pkt);944 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);
855 else if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)947 else if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)
856 return decklink_write_subtitle_packet(avctx, pkt);948 return decklink_write_subtitle_packet(avctx, pkt);
857 949

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