avdevice/decklink_enc: Add support for output of Active Format Description (AFD)

Implement support for including AFD in decklink output when putting
out 10-bit VANC data.

Updated to reflect feedback in 2018 from Marton Balint <cus@passwd.hu>,
Carl Eugen Hoyos <ceffmpeg@gmail.com> and Aaron Levinson
<alevinsn_dev@levland.net>.  Also includes fixes to set the AR field
based on the SAR, as well as now sending the AFD info in both fields
for interlaced formats.

Signed-off-by: Devin Heitmueller <dheitmueller@ltnglobal.com>
Signed-off-by: Marton Balint <cus@passwd.hu>
This commit is contained in:
Devin Heitmueller 2023-03-27 15:58:10 -04:00 committed by Marton Balint
parent 88da4b5fcd
commit 33ef8778e0
1 changed files with 88 additions and 2 deletions

View File

@ -367,8 +367,93 @@ static void construct_cc(AVFormatContext *avctx, struct decklink_ctx *ctx,
}
}
/* See SMPTE ST 2016-3:2009 */
static void construct_afd(AVFormatContext *avctx, struct decklink_ctx *ctx,
AVPacket *pkt, struct klvanc_line_set_s *vanc_lines,
AVStream *st)
{
struct klvanc_packet_afd_s *afd = NULL;
uint16_t *afd_words = NULL;
uint16_t len;
size_t size;
int f1_line = 12, f2_line = 0, ret;
const uint8_t *data = av_packet_get_side_data(pkt, AV_PKT_DATA_AFD, &size);
if (!data || size == 0)
return;
ret = klvanc_create_AFD(&afd);
if (ret)
return;
ret = klvanc_set_AFD_val(afd, data[0]);
if (ret) {
av_log(avctx, AV_LOG_ERROR, "Invalid AFD value specified: %d\n",
data[0]);
klvanc_destroy_AFD(afd);
return;
}
/* Compute the AR flag based on the DAR (see ST 2016-1:2009 Sec 9.1). Note, we treat
anything below 1.4 as 4:3 (as opposed to the standard 1.33), because there are lots
of streams in the field that aren't *exactly* 4:3 but a tiny bit larger after doing
the math... */
if (av_cmp_q((AVRational) {st->codecpar->width * st->codecpar->sample_aspect_ratio.num,
st->codecpar->height * st->codecpar->sample_aspect_ratio.den}, (AVRational) {14, 10}) == 1)
afd->aspectRatio = ASPECT_16x9;
else
afd->aspectRatio = ASPECT_4x3;
ret = klvanc_convert_AFD_to_words(afd, &afd_words, &len);
if (ret) {
av_log(avctx, AV_LOG_ERROR, "Failed converting AFD packet to words\n");
goto out;
}
ret = klvanc_line_insert(ctx->vanc_ctx, vanc_lines, afd_words, len, f1_line, 0);
if (ret) {
av_log(avctx, AV_LOG_ERROR, "VANC line insertion failed\n");
goto out;
}
/* For interlaced video, insert into both fields. Switching lines for field 2
derived from SMPTE RP 168:2009, Sec 6, Table 2. */
switch (ctx->bmd_mode) {
case bmdModeNTSC:
case bmdModeNTSC2398:
f2_line = 273 - 10 + f1_line;
break;
case bmdModePAL:
f2_line = 319 - 6 + f1_line;
break;
case bmdModeHD1080i50:
case bmdModeHD1080i5994:
case bmdModeHD1080i6000:
f2_line = 569 - 7 + f1_line;
break;
default:
f2_line = 0;
break;
}
if (f2_line > 0) {
ret = klvanc_line_insert(ctx->vanc_ctx, vanc_lines, afd_words, len, f2_line, 0);
if (ret) {
av_log(avctx, AV_LOG_ERROR, "VANC line insertion failed\n");
goto out;
}
}
out:
if (afd)
klvanc_destroy_AFD(afd);
if (afd_words)
free(afd_words);
}
static int decklink_construct_vanc(AVFormatContext *avctx, struct decklink_ctx *ctx,
AVPacket *pkt, decklink_frame *frame)
AVPacket *pkt, decklink_frame *frame,
AVStream *st)
{
struct klvanc_line_set_s vanc_lines = { 0 };
int ret = 0, i;
@ -377,6 +462,7 @@ static int decklink_construct_vanc(AVFormatContext *avctx, struct decklink_ctx *
return 0;
construct_cc(avctx, ctx, pkt, &vanc_lines);
construct_afd(avctx, ctx, pkt, &vanc_lines, st);
IDeckLinkVideoFrameAncillary *vanc;
int result = ctx->dlo->CreateAncillaryData(bmdFormat10BitYUV, &vanc);
@ -468,7 +554,7 @@ static int decklink_write_video_packet(AVFormatContext *avctx, AVPacket *pkt)
frame = new decklink_frame(ctx, avpacket, st->codecpar->codec_id, ctx->bmd_height, ctx->bmd_width);
#if CONFIG_LIBKLVANC
if (decklink_construct_vanc(avctx, ctx, pkt, frame))
if (decklink_construct_vanc(avctx, ctx, pkt, frame, st))
av_log(avctx, AV_LOG_ERROR, "Failed to construct VANC\n");
#endif
}