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

Unified · Split

7 files
  1. doc/outdevs.texi +5 −0
  2. libavdevice/decklink_common.cpp +16 −0
  3. libavdevice/decklink_common.h +4 −0
  4. libavdevice/decklink_common_c.h +1 −0
  5. libavdevice/decklink_enc.cpp +93 −1
  6. libavdevice/decklink_enc_c.c +1 −0
  7. libavdevice/version.h +1 −1
doc/outdevs.texi+5−0
@@ -235,6 +235,11 @@ Enable SMPTE Level A mode on the used output. · 234 unmodified lines
235Must be @samp{unset}, @samp{true} or @samp{false}.235Must be @samp{unset}, @samp{true} or @samp{false}.
236Defaults to @option{unset}.236Defaults to @option{unset}.
237 237
238@item vanc_queue_size
239Sets maximum output buffer size in bytes for VANC data. If the buffering reaches this value,
240outgoing VANC data will be dropped.
241Defaults to @samp{1048576}.
242
238@end table243@end table
239 244
240@subsection Examples245@subsection Examples
libavdevice/decklink_common.cpp+16−0
@@ -484,6 +484,22 @@ int ff_decklink_packet_queue_get(DecklinkPacketQueue *q, AVPacket *pkt, int bloc · 483 unmodified lines
484 return ret;484 return ret;
485}485}
486 486
487int64_t ff_decklink_packet_queue_peekpts(DecklinkPacketQueue *q)
488{
489 PacketListEntry *pkt1;
490 int64_t pts = -1;
491
492 pthread_mutex_lock(&q->mutex);
493 pkt1 = q->pkt_list.head;
494 if (pkt1) {
495 pts = pkt1->pkt.pts;
496 }
497 pthread_mutex_unlock(&q->mutex);
498
499 return pts;
500}
501
502
487int ff_decklink_list_devices(AVFormatContext *avctx,503int ff_decklink_list_devices(AVFormatContext *avctx,
488 struct AVDeviceInfoList *device_list,504 struct AVDeviceInfoList *device_list,
489 int show_inputs, int show_outputs)505 int show_inputs, int show_outputs)
libavdevice/decklink_common.h+4−0
@@ -115,6 +115,9 @@ struct decklink_ctx { · 114 unmodified lines
115 115
116 CCFifo cc_fifo; ///< closed captions116 CCFifo cc_fifo; ///< closed captions
117 117
118 /* Output VANC queue */
119 DecklinkPacketQueue vanc_queue;
120
118 /* Streams present */121 /* Streams present */
119 int audio;122 int audio;
120 int video;123 int video;
@@ -241,5 +244,6 @@ void ff_decklink_packet_queue_end(DecklinkPacketQueue *q); · 120 unmodified lines
241unsigned long long ff_decklink_packet_queue_size(DecklinkPacketQueue *q);244unsigned long long ff_decklink_packet_queue_size(DecklinkPacketQueue *q);
242int ff_decklink_packet_queue_put(DecklinkPacketQueue *q, AVPacket *pkt);245int ff_decklink_packet_queue_put(DecklinkPacketQueue *q, AVPacket *pkt);
243int ff_decklink_packet_queue_get(DecklinkPacketQueue *q, AVPacket *pkt, int block);246int ff_decklink_packet_queue_get(DecklinkPacketQueue *q, AVPacket *pkt, int block);
247int64_t ff_decklink_packet_queue_peekpts(DecklinkPacketQueue *q);
244 248
245#endif /* AVDEVICE_DECKLINK_COMMON_H */249#endif /* AVDEVICE_DECKLINK_COMMON_H */
libavdevice/decklink_common_c.h+1−0
@@ -63,6 +63,7 @@ struct decklink_cctx { · 62 unmodified lines
63 char *format_code;63 char *format_code;
64 int raw_format;64 int raw_format;
65 int64_t queue_size;65 int64_t queue_size;
66 int64_t vanc_queue_size;
66 int copyts;67 int copyts;
67 int64_t timestamp_align;68 int64_t timestamp_align;
68 int timing_offset;69 int timing_offset;
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
libavdevice/decklink_enc_c.c+1−0
@@ -32,6 +32,7 @@ static const AVOption options[] = { · 31 unmodified lines
32 { "list_devices", "use ffmpeg -sinks decklink instead", OFFSET(list_devices), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC | AV_OPT_FLAG_DEPRECATED},32 { "list_devices", "use ffmpeg -sinks decklink instead", OFFSET(list_devices), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC | AV_OPT_FLAG_DEPRECATED},
33 { "list_formats", "list supported formats" , OFFSET(list_formats), AV_OPT_TYPE_INT , { .i64 = 0 }, 0, 1, ENC },33 { "list_formats", "list supported formats" , OFFSET(list_formats), AV_OPT_TYPE_INT , { .i64 = 0 }, 0, 1, ENC },
34 { "preroll" , "video preroll in seconds", OFFSET(preroll ), AV_OPT_TYPE_DOUBLE, { .dbl = 0.5 }, 0, 5, ENC },34 { "preroll" , "video preroll in seconds", OFFSET(preroll ), AV_OPT_TYPE_DOUBLE, { .dbl = 0.5 }, 0, 5, ENC },
35 { "vanc_queue_size", "VANC queue buffer size", OFFSET(vanc_queue_size), AV_OPT_TYPE_INT64, { .i64 = (1024 * 1024)}, 0, INT64_MAX, ENC },
35#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0b00000036#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0b000000
36 { "duplex_mode" , "duplex mode" , OFFSET(duplex_mode ), AV_OPT_TYPE_INT , { .i64 = 0 }, 0, 5, ENC, "duplex_mode"},37 { "duplex_mode" , "duplex mode" , OFFSET(duplex_mode ), AV_OPT_TYPE_INT , { .i64 = 0 }, 0, 5, ENC, "duplex_mode"},
37#else38#else
libavdevice/version.h+1−1
@@ -30,7 +30,7 @@ · 29 unmodified lines
30#include "version_major.h"30#include "version_major.h"
31 31
32#define LIBAVDEVICE_VERSION_MINOR 232#define LIBAVDEVICE_VERSION_MINOR 2
33#define LIBAVDEVICE_VERSION_MICRO 10033#define LIBAVDEVICE_VERSION_MICRO 101
34 34
35#define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \35#define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \
36 LIBAVDEVICE_VERSION_MINOR, \36 LIBAVDEVICE_VERSION_MINOR, \

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