diff --git a/symphonia-format-mkv/src/codecs.rs b/symphonia-format-mkv/src/codecs.rs index ee9a4144..359456ee 100644 --- a/symphonia-format-mkv/src/codecs.rs +++ b/symphonia-format-mkv/src/codecs.rs @@ -138,6 +138,12 @@ fn make_video_codec_params( codec_params.add_extra_data(VideoExtraData { id: extra_data_id, data: codec_private }); } + for block in track.block_addition_mappings { + if let Some(extra_data) = block.extra_data { + codec_params.add_extra_data(extra_data); + } + } + Ok(Some(CodecParameters::Video(codec_params))) } diff --git a/symphonia-format-mkv/src/element_ids.rs b/symphonia-format-mkv/src/element_ids.rs index 858c36ff..11de6d08 100644 --- a/symphonia-format-mkv/src/element_ids.rs +++ b/symphonia-format-mkv/src/element_ids.rs @@ -53,7 +53,9 @@ pub enum ElementType { BlockAdditions, BlockMore, BlockAddId, + BlockAddIdType, BlockAdditional, + BlockAdditionMapping, BlockDuration, ReferenceBlock, DiscardPadding, @@ -93,6 +95,7 @@ pub enum ElementType { DisplayHeight, DisplayUnit, AspectRatioType, + DolbyVisionConfiguration, Audio, SamplingFrequency, OutputSamplingFrequency, @@ -218,7 +221,9 @@ lazy_static! { elems.insert(0x75A1, (Type::Master, ElementType::BlockAdditions)); elems.insert(0xA6, (Type::Master, ElementType::BlockMore)); elems.insert(0xEE, (Type::Unsigned, ElementType::BlockAddId)); + elems.insert(0x41E7, (Type::String, ElementType::BlockAddIdType)); elems.insert(0xA5, (Type::Binary, ElementType::BlockAdditional)); + elems.insert(0x41E4, (Type::Binary, ElementType::BlockAdditionMapping)); elems.insert(0x9B, (Type::Unsigned, ElementType::BlockDuration)); elems.insert(0xFB, (Type::Signed, ElementType::ReferenceBlock)); elems.insert(0x75A2, (Type::Signed, ElementType::DiscardPadding)); @@ -258,6 +263,7 @@ lazy_static! { elems.insert(0x54BA, (Type::Unsigned, ElementType::DisplayHeight)); elems.insert(0x54B2, (Type::Unsigned, ElementType::DisplayUnit)); elems.insert(0x54B3, (Type::Unsigned, ElementType::AspectRatioType)); + elems.insert(0x41ED, (Type::Binary, ElementType::DolbyVisionConfiguration)); elems.insert(0xE1, (Type::Master, ElementType::Audio)); elems.insert(0xB5, (Type::Float, ElementType::SamplingFrequency)); elems.insert(0x78B5, (Type::Float, ElementType::OutputSamplingFrequency)); diff --git a/symphonia-format-mkv/src/segment.rs b/symphonia-format-mkv/src/segment.rs index a0c84eab..b35b53ea 100644 --- a/symphonia-format-mkv/src/segment.rs +++ b/symphonia-format-mkv/src/segment.rs @@ -5,6 +5,10 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. +use symphonia_core::codecs::video::well_known::extra_data::{ + VIDEO_EXTRA_DATA_ID_DOLBY_VISION_CONFIG, VIDEO_EXTRA_DATA_ID_DOLBY_VISION_EL_HEVC, +}; +use symphonia_core::codecs::video::VideoExtraData; use symphonia_core::errors::{Error, Result}; use symphonia_core::io::{BufReader, ReadBytes}; use symphonia_core::meta::{MetadataBuilder, MetadataRevision, Tag, Value}; @@ -21,6 +25,7 @@ pub(crate) struct TrackElement { pub(crate) language: Option, pub(crate) codec_id: String, pub(crate) codec_private: Option>, + pub(crate) block_addition_mappings: Vec, pub(crate) audio: Option, pub(crate) video: Option, pub(crate) default_duration: Option, @@ -36,6 +41,7 @@ impl Element for TrackElement { let mut audio = None; let mut video = None; let mut codec_private = None; + let mut block_addition_mappings = Vec::new(); let mut codec_id = None; let mut default_duration = None; @@ -63,6 +69,9 @@ impl Element for TrackElement { ElementType::Video => { video = Some(it.read_element_data()?); } + ElementType::BlockAdditionMapping => { + block_addition_mappings.push(it.read_element_data()?); + } ElementType::DefaultDuration => { default_duration = Some(it.read_u64()?); } @@ -78,6 +87,7 @@ impl Element for TrackElement { language, codec_id: codec_id.ok_or(Error::DecodeError("mkv: missing codec id"))?, codec_private, + block_addition_mappings, audio, video, default_duration, @@ -166,6 +176,51 @@ impl Element for VideoElement { } } +#[derive(Debug)] +pub(crate) struct BlockAdditionMappingElement { + pub(crate) extra_data: Option, +} + +impl Element for BlockAdditionMappingElement { + const ID: ElementType = ElementType::BlockAdditionMapping; + + fn read(reader: &mut B, header: ElementHeader) -> Result { + // There can be many BlockAdditionMapping elements with DolbyVisionConfiguration in a single track + // BlockAddIdType FourCC string allows to determine the type of DolbyVisionConfiguration extra data + let mut extra_data = None; + let mut block_add_id_type = String::new(); + + let mut it = header.children(reader); + while let Some(header) = it.read_header()? { + match header.etype { + ElementType::BlockAddIdType => { + block_add_id_type = it.read_string()?; + } + ElementType::DolbyVisionConfiguration => match block_add_id_type.as_str() { + "dvcC" | "dvvC" => { + extra_data = Some(VideoExtraData { + id: VIDEO_EXTRA_DATA_ID_DOLBY_VISION_CONFIG, + data: it.read_boxed_slice()?, + }); + } + "hvcE" => { + extra_data = Some(VideoExtraData { + id: VIDEO_EXTRA_DATA_ID_DOLBY_VISION_EL_HEVC, + data: it.read_boxed_slice()?, + }); + } + _ => {} + }, + other => { + log::debug!("ignored element {:?}", other); + } + } + } + + Ok(Self { extra_data }) + } +} + #[derive(Debug)] pub(crate) struct SeekHeadElement { pub(crate) seeks: Box<[SeekElement]>,