libavformat/matroska: Support smpte 2094-50 metadata

Add support for parsing and muxing smpte 2094-50 metadata. It will
be stored as an ITUT-T35 message in the BlockAdditional element with
an AddId type of 4 (which is reserved for ITUT-T35 in the matroska
spec).

https://www.matroska.org/technical/codec_specs.html#itu-t35-metadata

Signed-off-by: Vignesh Venkatasubramanian <vigneshv@google.com>
This commit is contained in:
Vignesh Venkat
2026-04-14 15:12:10 -07:00
committed by James Almer
parent c1b19ee69f
commit 7faa6ee2aa
7 changed files with 69 additions and 8 deletions

View File

@@ -2,6 +2,9 @@ The last version increases of all libraries were on 2025-03-28
API changes, most recent first: API changes, most recent first:
2026-04-xx - xxxxxxxxxx - lavc 60.30.100 - packet.h
Add AV_PKT_DATA_DYNAMIC_HDR_SMPTE_2094_APP5 side data type.
2026-04-09 - 6ba6db4f19 - lavu 60.30.100 - hdr_dynamic_metadata.h frame.h 2026-04-09 - 6ba6db4f19 - lavu 60.30.100 - hdr_dynamic_metadata.h frame.h
Add AVDynamicHDRSmpte2094App5 struct and functions. Add AVDynamicHDRSmpte2094App5 struct and functions.
Add AV_FRAME_DATA_DYNAMIC_HDR_SMPTE_2094_APP5 side data type. Add AV_FRAME_DATA_DYNAMIC_HDR_SMPTE_2094_APP5 side data type.

View File

@@ -1542,12 +1542,13 @@ int ff_decode_frame_props_from_pkt(const AVCodecContext *avctx,
AVFrame *frame, const AVPacket *pkt) AVFrame *frame, const AVPacket *pkt)
{ {
static const SideDataMap sd[] = { static const SideDataMap sd[] = {
{ AV_PKT_DATA_A53_CC, AV_FRAME_DATA_A53_CC }, { AV_PKT_DATA_A53_CC, AV_FRAME_DATA_A53_CC },
{ AV_PKT_DATA_AFD, AV_FRAME_DATA_AFD }, { AV_PKT_DATA_AFD, AV_FRAME_DATA_AFD },
{ AV_PKT_DATA_DYNAMIC_HDR10_PLUS, AV_FRAME_DATA_DYNAMIC_HDR_PLUS }, { AV_PKT_DATA_DYNAMIC_HDR10_PLUS, AV_FRAME_DATA_DYNAMIC_HDR_PLUS },
{ AV_PKT_DATA_S12M_TIMECODE, AV_FRAME_DATA_S12M_TIMECODE }, { AV_PKT_DATA_DYNAMIC_HDR_SMPTE_2094_APP5, AV_FRAME_DATA_DYNAMIC_HDR_SMPTE_2094_APP5 },
{ AV_PKT_DATA_SKIP_SAMPLES, AV_FRAME_DATA_SKIP_SAMPLES }, { AV_PKT_DATA_S12M_TIMECODE, AV_FRAME_DATA_S12M_TIMECODE },
{ AV_PKT_DATA_LCEVC, AV_FRAME_DATA_LCEVC }, { AV_PKT_DATA_SKIP_SAMPLES, AV_FRAME_DATA_SKIP_SAMPLES },
{ AV_PKT_DATA_LCEVC, AV_FRAME_DATA_LCEVC },
{ AV_PKT_DATA_NB } { AV_PKT_DATA_NB }
}; };

View File

@@ -301,6 +301,7 @@ const char *av_packet_side_data_name(enum AVPacketSideDataType type)
case AV_PKT_DATA_DOVI_CONF: return "DOVI configuration record"; case AV_PKT_DATA_DOVI_CONF: return "DOVI configuration record";
case AV_PKT_DATA_S12M_TIMECODE: return "SMPTE ST 12-1:2014 timecode"; case AV_PKT_DATA_S12M_TIMECODE: return "SMPTE ST 12-1:2014 timecode";
case AV_PKT_DATA_DYNAMIC_HDR10_PLUS: return "HDR10+ Dynamic Metadata (SMPTE 2094-40)"; case AV_PKT_DATA_DYNAMIC_HDR10_PLUS: return "HDR10+ Dynamic Metadata (SMPTE 2094-40)";
case AV_PKT_DATA_DYNAMIC_HDR_SMPTE_2094_APP5:return "HDR Dynamic Metadata (SMPTE 2094-50)";
case AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT:return "Ambient viewing environment"; case AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT:return "Ambient viewing environment";
case AV_PKT_DATA_IAMF_MIX_GAIN_PARAM: return "IAMF Mix Gain Parameter Data"; case AV_PKT_DATA_IAMF_MIX_GAIN_PARAM: return "IAMF Mix Gain Parameter Data";
case AV_PKT_DATA_IAMF_DEMIXING_INFO_PARAM: return "IAMF Demixing Info Parameter Data"; case AV_PKT_DATA_IAMF_DEMIXING_INFO_PARAM: return "IAMF Demixing Info Parameter Data";

View File

@@ -368,6 +368,13 @@ enum AVPacketSideDataType {
*/ */
AV_PKT_DATA_EXIF, AV_PKT_DATA_EXIF,
/**
* HDR dynamic metadata associated with a video frame. The payload is an
* AVDynamicHDRSmpte2094App5 type and contains information for color volume
* transform as specified in the SMPTE 2094-50 standard.
*/
AV_PKT_DATA_DYNAMIC_HDR_SMPTE_2094_APP5,
/** /**
* The number of side data types. * The number of side data types.
* This is not part of the public API/ABI in the sense that it may * This is not part of the public API/ABI in the sense that it may

View File

@@ -29,8 +29,8 @@
#include "version_major.h" #include "version_major.h"
#define LIBAVCODEC_VERSION_MINOR 29 #define LIBAVCODEC_VERSION_MINOR 30
#define LIBAVCODEC_VERSION_MICRO 101 #define LIBAVCODEC_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \ LIBAVCODEC_VERSION_MINOR, \

View File

@@ -3964,6 +3964,31 @@ static int matroska_parse_block_additional(MatroskaDemuxContext *matroska,
break; break;
} }
case ITU_T_T35_PROVIDER_CODE_SMPTE: {
AVDynamicHDRSmpte2094App5 *hdr_smpte_2094_app5;
size_t hdr_smpte_2094_app5_size;
provider_oriented_code = bytestream2_get_be16u(&bc);
if (provider_oriented_code != 1)
break; // ignore
hdr_smpte_2094_app5 = av_dynamic_hdr_smpte2094_app5_alloc(&hdr_smpte_2094_app5_size);
if (!hdr_smpte_2094_app5_size)
return AVERROR(ENOMEM);
if ((res = av_dynamic_hdr_smpte2094_app5_from_t35(hdr_smpte_2094_app5,
bc.buffer,
bytestream2_get_bytes_left(&bc))) < 0 ||
(res = av_packet_add_side_data(pkt,
AV_PKT_DATA_DYNAMIC_HDR_SMPTE_2094_APP5,
(uint8_t *)hdr_smpte_2094_app5,
hdr_smpte_2094_app5_size)) < 0) {
av_free(hdr_smpte_2094_app5);
return res;
}
break;
}
default: default:
break; break;
} }

View File

@@ -2939,6 +2939,30 @@ static int mkv_write_block(void *logctx, MatroskaMuxContext *mkv,
track->max_blockaddid = FFMAX(track->max_blockaddid, track->max_blockaddid = FFMAX(track->max_blockaddid,
MATROSKA_BLOCK_ADD_ID_ITU_T_T35); MATROSKA_BLOCK_ADD_ID_ITU_T_T35);
} }
side_data = av_packet_get_side_data(pkt,
AV_PKT_DATA_DYNAMIC_HDR_SMPTE_2094_APP5,
&side_data_size);
if (side_data && side_data_size) {
// The maximum possible payload size for SMPTE_2094_APP5 metadata is
// 855 bytes. So it will fit into the t35_buf which is of size
// 6 + AV_HDR_PLUS_MAX_PAYLOAD_SIZE = 913.
uint8_t *payload = t35_buf;
size_t payload_size = sizeof(t35_buf) - 5;
bytestream_put_byte(&payload, ITU_T_T35_COUNTRY_CODE_US);
bytestream_put_be16(&payload, ITU_T_T35_PROVIDER_CODE_SMPTE);
bytestream_put_be16(&payload, 0x01); // provider_oriented_code
ret = av_dynamic_hdr_smpte2094_app5_to_t35((AVDynamicHDRSmpte2094App5 *)side_data,
&payload, &payload_size);
if (ret < 0)
return ret;
mkv_write_blockadditional(&writer, t35_buf, payload_size + 5,
MATROSKA_BLOCK_ADD_ID_ITU_T_T35);
track->max_blockaddid = FFMAX(track->max_blockaddid,
MATROSKA_BLOCK_ADD_ID_ITU_T_T35);
}
} }
ebml_writer_close_or_discard_master(&writer); ebml_writer_close_or_discard_master(&writer);