From 767cf459e56c449e394da49b48212b5016dc949b Mon Sep 17 00:00:00 2001 From: quietvoid Date: Thu, 24 Jul 2025 09:53:05 -0400 Subject: [PATCH 1/5] dovi: support level 15 extension metadata block --- .../src/c_structs/extension_metadata.rs | 3 + .../rpu/extension_metadata/blocks/level15.rs | 92 ++++++++++ .../src/rpu/extension_metadata/blocks/mod.rs | 165 +++++++++--------- .../src/rpu/extension_metadata/cmv40.rs | 3 +- dolby_vision/src/rpu/vdr_dm_data.rs | 1 + 5 files changed, 185 insertions(+), 79 deletions(-) create mode 100644 dolby_vision/src/rpu/extension_metadata/blocks/level15.rs diff --git a/dolby_vision/src/c_structs/extension_metadata.rs b/dolby_vision/src/c_structs/extension_metadata.rs index d067ae6..e98b576 100644 --- a/dolby_vision/src/c_structs/extension_metadata.rs +++ b/dolby_vision/src/c_structs/extension_metadata.rs @@ -106,6 +106,9 @@ impl DmData { self.level11 = Box::into_raw(Box::new(b.clone())) as *const ExtMetadataBlockLevel11 } + ExtMetadataBlock::Level15(_) => { + // TODO + } ExtMetadataBlock::Level254(b) => { self.level254 = Box::into_raw(Box::new(b.clone())) as *const ExtMetadataBlockLevel254 diff --git a/dolby_vision/src/rpu/extension_metadata/blocks/level15.rs b/dolby_vision/src/rpu/extension_metadata/blocks/level15.rs new file mode 100644 index 0000000..ac98f17 --- /dev/null +++ b/dolby_vision/src/rpu/extension_metadata/blocks/level15.rs @@ -0,0 +1,92 @@ +use anyhow::{Result, ensure}; +use bitvec_helpers::{ + bitstream_io_reader::BsIoSliceReader, bitstream_io_writer::BitstreamIoWriter, +}; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +use super::{ExtMetadataBlock, ExtMetadataBlockInfo}; + +/// Consumer look metadata, Precision Rendering/Detail +#[repr(C)] +#[derive(Debug, Default, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +pub struct ExtMetadataBlockLevel15 { + pub confidence: u8, + pub precision_rendering_strength: u8, + pub d_local_contrast: u8, + pub d_brightness: u8, + pub d_saturation_plus_one: u8, + pub d_contrast_plus_one: u8, + + pub confidence_no_pr: u8, + pub d_brightness_no_pr: u8, + pub d_saturation_plus_one_no_pr: u8, + pub d_contrast_plus_one_no_pr: u8, + + /// 4 bits + pub revision: u8, + /// 4 bits + pub reserved: u8, +} + +impl ExtMetadataBlockLevel15 { + pub(crate) fn parse(reader: &mut BsIoSliceReader) -> Result { + let block = Self { + confidence: reader.read::<8, u8>()?, + precision_rendering_strength: reader.read::<8, u8>()?, + d_local_contrast: reader.read::<8, u8>()?, + d_brightness: reader.read::<8, u8>()?, + d_saturation_plus_one: reader.read::<8, u8>()?, + d_contrast_plus_one: reader.read::<8, u8>()?, + confidence_no_pr: reader.read::<8, u8>()?, + d_brightness_no_pr: reader.read::<8, u8>()?, + d_saturation_plus_one_no_pr: reader.read::<8, u8>()?, + d_contrast_plus_one_no_pr: reader.read::<8, u8>()?, + revision: reader.read::<4, u8>()?, + reserved: reader.read::<4, u8>()?, + }; + + Ok(ExtMetadataBlock::Level15(block)) + } + + pub fn write(&self, writer: &mut BitstreamIoWriter) -> Result<()> { + self.validate()?; + + writer.write::<8, u8>(self.confidence)?; + writer.write::<8, u8>(self.precision_rendering_strength)?; + writer.write::<8, u8>(self.d_local_contrast)?; + writer.write::<8, u8>(self.d_brightness)?; + writer.write::<8, u8>(self.d_saturation_plus_one)?; + writer.write::<8, u8>(self.d_contrast_plus_one)?; + writer.write::<8, u8>(self.confidence_no_pr)?; + writer.write::<8, u8>(self.d_brightness_no_pr)?; + writer.write::<8, u8>(self.d_saturation_plus_one_no_pr)?; + writer.write::<8, u8>(self.d_contrast_plus_one_no_pr)?; + writer.write::<4, u8>(self.revision)?; + writer.write::<4, u8>(self.reserved)?; + + Ok(()) + } + + pub fn validate(&self) -> Result<()> { + ensure!(self.reserved == 0); + + Ok(()) + } +} + +impl ExtMetadataBlockInfo for ExtMetadataBlockLevel15 { + fn level(&self) -> u8 { + 15 + } + + fn bytes_size(&self) -> u64 { + 11 + } + + fn required_bits(&self) -> u64 { + 11 * 8 + } +} diff --git a/dolby_vision/src/rpu/extension_metadata/blocks/mod.rs b/dolby_vision/src/rpu/extension_metadata/blocks/mod.rs index eac6e35..abed96c 100644 --- a/dolby_vision/src/rpu/extension_metadata/blocks/mod.rs +++ b/dolby_vision/src/rpu/extension_metadata/blocks/mod.rs @@ -9,6 +9,7 @@ use serde::{Deserialize, Serialize}; pub mod level1; pub mod level10; pub mod level11; +pub mod level15; pub mod level2; pub mod level254; pub mod level255; @@ -30,6 +31,7 @@ pub use level8::ExtMetadataBlockLevel8; pub use level9::ExtMetadataBlockLevel9; pub use level10::ExtMetadataBlockLevel10; pub use level11::ExtMetadataBlockLevel11; +pub use level15::ExtMetadataBlockLevel15; pub use level254::ExtMetadataBlockLevel254; pub use level255::ExtMetadataBlockLevel255; pub use reserved::ReservedExtMetadataBlock; @@ -52,6 +54,7 @@ pub enum ExtMetadataBlock { Level9(ExtMetadataBlockLevel9), Level10(ExtMetadataBlockLevel10), Level11(ExtMetadataBlockLevel11), + Level15(ExtMetadataBlockLevel15), Level254(ExtMetadataBlockLevel254), Level255(ExtMetadataBlockLevel255), Reserved(ReservedExtMetadataBlock), @@ -74,109 +77,115 @@ pub trait ExtMetadataBlockInfo { impl ExtMetadataBlock { pub fn length_bytes(&self) -> u64 { match self { - ExtMetadataBlock::Level1(b) => b.bytes_size(), - ExtMetadataBlock::Level2(b) => b.bytes_size(), - ExtMetadataBlock::Level3(b) => b.bytes_size(), - ExtMetadataBlock::Level4(b) => b.bytes_size(), - ExtMetadataBlock::Level5(b) => b.bytes_size(), - ExtMetadataBlock::Level6(b) => b.bytes_size(), - ExtMetadataBlock::Level8(b) => b.bytes_size(), - ExtMetadataBlock::Level9(b) => b.bytes_size(), - ExtMetadataBlock::Level10(b) => b.bytes_size(), - ExtMetadataBlock::Level11(b) => b.bytes_size(), - ExtMetadataBlock::Level254(b) => b.bytes_size(), - ExtMetadataBlock::Level255(b) => b.bytes_size(), - ExtMetadataBlock::Reserved(b) => b.bytes_size(), + Self::Level1(b) => b.bytes_size(), + Self::Level2(b) => b.bytes_size(), + Self::Level3(b) => b.bytes_size(), + Self::Level4(b) => b.bytes_size(), + Self::Level5(b) => b.bytes_size(), + Self::Level6(b) => b.bytes_size(), + Self::Level8(b) => b.bytes_size(), + Self::Level9(b) => b.bytes_size(), + Self::Level10(b) => b.bytes_size(), + Self::Level11(b) => b.bytes_size(), + Self::Level15(b) => b.bytes_size(), + Self::Level254(b) => b.bytes_size(), + Self::Level255(b) => b.bytes_size(), + Self::Reserved(b) => b.bytes_size(), } } pub fn length_bits(&self) -> u64 { match self { - ExtMetadataBlock::Level1(b) => b.bits_size(), - ExtMetadataBlock::Level2(b) => b.bits_size(), - ExtMetadataBlock::Level3(b) => b.bits_size(), - ExtMetadataBlock::Level4(b) => b.bits_size(), - ExtMetadataBlock::Level5(b) => b.bits_size(), - ExtMetadataBlock::Level6(b) => b.bits_size(), - ExtMetadataBlock::Level8(b) => b.bits_size(), - ExtMetadataBlock::Level9(b) => b.bits_size(), - ExtMetadataBlock::Level10(b) => b.bits_size(), - ExtMetadataBlock::Level11(b) => b.bits_size(), - ExtMetadataBlock::Level254(b) => b.bits_size(), - ExtMetadataBlock::Level255(b) => b.bits_size(), - ExtMetadataBlock::Reserved(b) => b.bits_size(), + Self::Level1(b) => b.bits_size(), + Self::Level2(b) => b.bits_size(), + Self::Level3(b) => b.bits_size(), + Self::Level4(b) => b.bits_size(), + Self::Level5(b) => b.bits_size(), + Self::Level6(b) => b.bits_size(), + Self::Level8(b) => b.bits_size(), + Self::Level9(b) => b.bits_size(), + Self::Level10(b) => b.bits_size(), + Self::Level11(b) => b.bits_size(), + Self::Level15(b) => b.bits_size(), + Self::Level254(b) => b.bits_size(), + Self::Level255(b) => b.bits_size(), + Self::Reserved(b) => b.bits_size(), } } pub fn required_bits(&self) -> u64 { match self { - ExtMetadataBlock::Level1(b) => b.required_bits(), - ExtMetadataBlock::Level2(b) => b.required_bits(), - ExtMetadataBlock::Level3(b) => b.required_bits(), - ExtMetadataBlock::Level4(b) => b.required_bits(), - ExtMetadataBlock::Level5(b) => b.required_bits(), - ExtMetadataBlock::Level6(b) => b.required_bits(), - ExtMetadataBlock::Level8(b) => b.required_bits(), - ExtMetadataBlock::Level9(b) => b.required_bits(), - ExtMetadataBlock::Level10(b) => b.required_bits(), - ExtMetadataBlock::Level11(b) => b.required_bits(), - ExtMetadataBlock::Level254(b) => b.required_bits(), - ExtMetadataBlock::Level255(b) => b.required_bits(), - ExtMetadataBlock::Reserved(b) => b.required_bits(), + Self::Level1(b) => b.required_bits(), + Self::Level2(b) => b.required_bits(), + Self::Level3(b) => b.required_bits(), + Self::Level4(b) => b.required_bits(), + Self::Level5(b) => b.required_bits(), + Self::Level6(b) => b.required_bits(), + Self::Level8(b) => b.required_bits(), + Self::Level9(b) => b.required_bits(), + Self::Level10(b) => b.required_bits(), + Self::Level11(b) => b.required_bits(), + Self::Level15(b) => b.required_bits(), + Self::Level254(b) => b.required_bits(), + Self::Level255(b) => b.required_bits(), + Self::Reserved(b) => b.required_bits(), } } pub fn level(&self) -> u8 { match self { - ExtMetadataBlock::Level1(b) => b.level(), - ExtMetadataBlock::Level2(b) => b.level(), - ExtMetadataBlock::Level3(b) => b.level(), - ExtMetadataBlock::Level4(b) => b.level(), - ExtMetadataBlock::Level5(b) => b.level(), - ExtMetadataBlock::Level6(b) => b.level(), - ExtMetadataBlock::Level8(b) => b.level(), - ExtMetadataBlock::Level9(b) => b.level(), - ExtMetadataBlock::Level10(b) => b.level(), - ExtMetadataBlock::Level11(b) => b.level(), - ExtMetadataBlock::Level254(b) => b.level(), - ExtMetadataBlock::Level255(b) => b.level(), - ExtMetadataBlock::Reserved(b) => b.level(), + Self::Level1(b) => b.level(), + Self::Level2(b) => b.level(), + Self::Level3(b) => b.level(), + Self::Level4(b) => b.level(), + Self::Level5(b) => b.level(), + Self::Level6(b) => b.level(), + Self::Level8(b) => b.level(), + Self::Level9(b) => b.level(), + Self::Level10(b) => b.level(), + Self::Level11(b) => b.level(), + Self::Level15(b) => b.level(), + Self::Level254(b) => b.level(), + Self::Level255(b) => b.level(), + Self::Reserved(b) => b.level(), } } pub fn sort_key(&self) -> (u8, u16) { match self { - ExtMetadataBlock::Level1(b) => b.sort_key(), - ExtMetadataBlock::Level2(b) => b.sort_key(), - ExtMetadataBlock::Level3(b) => b.sort_key(), - ExtMetadataBlock::Level4(b) => b.sort_key(), - ExtMetadataBlock::Level5(b) => b.sort_key(), - ExtMetadataBlock::Level6(b) => b.sort_key(), - ExtMetadataBlock::Level8(b) => b.sort_key(), - ExtMetadataBlock::Level9(b) => b.sort_key(), - ExtMetadataBlock::Level10(b) => b.sort_key(), - ExtMetadataBlock::Level11(b) => b.sort_key(), - ExtMetadataBlock::Level254(b) => b.sort_key(), - ExtMetadataBlock::Level255(b) => b.sort_key(), - ExtMetadataBlock::Reserved(b) => b.sort_key(), + Self::Level1(b) => b.sort_key(), + Self::Level2(b) => b.sort_key(), + Self::Level3(b) => b.sort_key(), + Self::Level4(b) => b.sort_key(), + Self::Level5(b) => b.sort_key(), + Self::Level6(b) => b.sort_key(), + Self::Level8(b) => b.sort_key(), + Self::Level9(b) => b.sort_key(), + Self::Level10(b) => b.sort_key(), + Self::Level11(b) => b.sort_key(), + Self::Level15(b) => b.sort_key(), + Self::Level254(b) => b.sort_key(), + Self::Level255(b) => b.sort_key(), + Self::Reserved(b) => b.sort_key(), } } pub fn write(&self, writer: &mut BitstreamIoWriter) -> Result<()> { match self { - ExtMetadataBlock::Level1(b) => b.write(writer), - ExtMetadataBlock::Level2(b) => b.write(writer), - ExtMetadataBlock::Level3(b) => b.write(writer), - ExtMetadataBlock::Level4(b) => b.write(writer), - ExtMetadataBlock::Level5(b) => b.write(writer), - ExtMetadataBlock::Level6(b) => b.write(writer), - ExtMetadataBlock::Level8(b) => b.write(writer), - ExtMetadataBlock::Level9(b) => b.write(writer), - ExtMetadataBlock::Level10(b) => b.write(writer), - ExtMetadataBlock::Level11(b) => b.write(writer), - ExtMetadataBlock::Level254(b) => b.write(writer), - ExtMetadataBlock::Level255(b) => b.write(writer), - ExtMetadataBlock::Reserved(b) => b.write(writer), + Self::Level1(b) => b.write(writer), + Self::Level2(b) => b.write(writer), + Self::Level3(b) => b.write(writer), + Self::Level4(b) => b.write(writer), + Self::Level5(b) => b.write(writer), + Self::Level6(b) => b.write(writer), + Self::Level8(b) => b.write(writer), + Self::Level9(b) => b.write(writer), + Self::Level10(b) => b.write(writer), + Self::Level11(b) => b.write(writer), + Self::Level15(b) => b.write(writer), + Self::Level254(b) => b.write(writer), + Self::Level255(b) => b.write(writer), + Self::Reserved(b) => b.write(writer), } } diff --git a/dolby_vision/src/rpu/extension_metadata/cmv40.rs b/dolby_vision/src/rpu/extension_metadata/cmv40.rs index f0a78aa..2770d72 100644 --- a/dolby_vision/src/rpu/extension_metadata/cmv40.rs +++ b/dolby_vision/src/rpu/extension_metadata/cmv40.rs @@ -16,7 +16,7 @@ pub struct CmV40DmData { impl WithExtMetadataBlocks for CmV40DmData { const VERSION: &'static str = "CM v4.0"; - const ALLOWED_BLOCK_LEVELS: &'static [u8] = &[3, 8, 9, 10, 11, 254]; + const ALLOWED_BLOCK_LEVELS: &'static [u8] = &[3, 8, 9, 10, 11, 15, 254]; fn with_blocks_allocation(num_ext_blocks: u64) -> Self { Self { @@ -51,6 +51,7 @@ impl WithExtMetadataBlocks for CmV40DmData { 9 => level9::ExtMetadataBlockLevel9::parse(reader, ext_block_length)?, 10 => level10::ExtMetadataBlockLevel10::parse(reader, ext_block_length)?, 11 => level11::ExtMetadataBlockLevel11::parse(reader)?, + 15 => level15::ExtMetadataBlockLevel15::parse(reader)?, 254 => level254::ExtMetadataBlockLevel254::parse(reader)?, 1 | 2 | 4 | 5 | 6 | 255 => bail!( "Invalid block level {} for {} RPU", diff --git a/dolby_vision/src/rpu/vdr_dm_data.rs b/dolby_vision/src/rpu/vdr_dm_data.rs index 03df8f2..f3974af 100644 --- a/dolby_vision/src/rpu/vdr_dm_data.rs +++ b/dolby_vision/src/rpu/vdr_dm_data.rs @@ -388,6 +388,7 @@ impl VdrDmData { } } ExtMetadataBlock::Level11(_) => self.replace_metadata_level(block), + ExtMetadataBlock::Level15(_) => self.replace_metadata_level(block), ExtMetadataBlock::Level254(_) => self.replace_metadata_level(block), ExtMetadataBlock::Level255(_) => self.replace_metadata_level(block), ExtMetadataBlock::Reserved(_) => bail!("Cannot replace specific reserved block"), From 31ba28dc1a9195f8b504279d8cbe24aa7431cc8a Mon Sep 17 00:00:00 2001 From: quietvoid Date: Thu, 24 Jul 2025 12:38:41 -0400 Subject: [PATCH 2/5] dovi: support level 16 extension metadata block --- .../src/c_structs/extension_metadata.rs | 3 + .../rpu/extension_metadata/blocks/level16.rs | 92 +++++++++++++++++++ .../src/rpu/extension_metadata/blocks/mod.rs | 9 ++ .../src/rpu/extension_metadata/cmv40.rs | 3 +- dolby_vision/src/rpu/vdr_dm_data.rs | 1 + 5 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 dolby_vision/src/rpu/extension_metadata/blocks/level16.rs diff --git a/dolby_vision/src/c_structs/extension_metadata.rs b/dolby_vision/src/c_structs/extension_metadata.rs index e98b576..6a58459 100644 --- a/dolby_vision/src/c_structs/extension_metadata.rs +++ b/dolby_vision/src/c_structs/extension_metadata.rs @@ -109,6 +109,9 @@ impl DmData { ExtMetadataBlock::Level15(_) => { // TODO } + ExtMetadataBlock::Level16(_) => { + // TODO + } ExtMetadataBlock::Level254(b) => { self.level254 = Box::into_raw(Box::new(b.clone())) as *const ExtMetadataBlockLevel254 diff --git a/dolby_vision/src/rpu/extension_metadata/blocks/level16.rs b/dolby_vision/src/rpu/extension_metadata/blocks/level16.rs new file mode 100644 index 0000000..179e591 --- /dev/null +++ b/dolby_vision/src/rpu/extension_metadata/blocks/level16.rs @@ -0,0 +1,92 @@ +use anyhow::{Result, ensure}; +use bitvec_helpers::{ + bitstream_io_reader::BsIoSliceReader, bitstream_io_writer::BitstreamIoWriter, +}; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +use super::{ExtMetadataBlock, ExtMetadataBlockInfo}; + +/// Local tone mapping metadata +#[repr(C)] +#[derive(Debug, Default, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +pub struct ExtMetadataBlockLevel16 { + pub revision: u8, + pub count: usize, + + pub params: Vec, +} + +#[repr(C)] +#[derive(Debug, Default, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +pub struct Level16Params { + pub contrast_target: u8, + pub precision_rendering_strength: u8, + pub d_local_contrast: u8, + pub max_d_brightness: u8, + pub max_d_saturation_plus_one: u8, +} + +impl ExtMetadataBlockLevel16 { + pub(crate) fn parse(reader: &mut BsIoSliceReader) -> Result { + let mut block = Self { + revision: reader.read::<4, u8>()?, + count: reader.read::<4, u8>()? as usize, + ..Default::default() + }; + + block.params.reserve(block.count); + + for _ in 0..block.count { + block.params.push(Level16Params { + contrast_target: reader.read::<8, u8>()?, + precision_rendering_strength: reader.read::<8, u8>()?, + d_local_contrast: reader.read::<8, u8>()?, + max_d_brightness: reader.read::<8, u8>()?, + max_d_saturation_plus_one: reader.read::<8, u8>()?, + }); + } + + Ok(ExtMetadataBlock::Level16(block)) + } + + pub fn write(&self, writer: &mut BitstreamIoWriter) -> Result<()> { + self.validate()?; + + writer.write::<4, u8>(self.revision)?; + writer.write::<4, u8>(self.count as u8)?; + + for params in &self.params { + writer.write::<8, u8>(params.contrast_target)?; + writer.write::<8, u8>(params.precision_rendering_strength)?; + writer.write::<8, u8>(params.d_local_contrast)?; + writer.write::<8, u8>(params.max_d_brightness)?; + writer.write::<8, u8>(params.max_d_saturation_plus_one)?; + } + + Ok(()) + } + + pub fn validate(&self) -> Result<()> { + ensure!(self.count == self.params.len()); + + Ok(()) + } +} + +impl ExtMetadataBlockInfo for ExtMetadataBlockLevel16 { + fn level(&self) -> u8 { + 16 + } + + fn bytes_size(&self) -> u64 { + 1 + (self.count as u64 * 5) + } + + fn required_bits(&self) -> u64 { + self.bytes_size() * 8 + } +} diff --git a/dolby_vision/src/rpu/extension_metadata/blocks/mod.rs b/dolby_vision/src/rpu/extension_metadata/blocks/mod.rs index abed96c..6c123d3 100644 --- a/dolby_vision/src/rpu/extension_metadata/blocks/mod.rs +++ b/dolby_vision/src/rpu/extension_metadata/blocks/mod.rs @@ -10,6 +10,7 @@ pub mod level1; pub mod level10; pub mod level11; pub mod level15; +pub mod level16; pub mod level2; pub mod level254; pub mod level255; @@ -32,6 +33,7 @@ pub use level9::ExtMetadataBlockLevel9; pub use level10::ExtMetadataBlockLevel10; pub use level11::ExtMetadataBlockLevel11; pub use level15::ExtMetadataBlockLevel15; +pub use level16::ExtMetadataBlockLevel16; pub use level254::ExtMetadataBlockLevel254; pub use level255::ExtMetadataBlockLevel255; pub use reserved::ReservedExtMetadataBlock; @@ -55,6 +57,7 @@ pub enum ExtMetadataBlock { Level10(ExtMetadataBlockLevel10), Level11(ExtMetadataBlockLevel11), Level15(ExtMetadataBlockLevel15), + Level16(ExtMetadataBlockLevel16), Level254(ExtMetadataBlockLevel254), Level255(ExtMetadataBlockLevel255), Reserved(ReservedExtMetadataBlock), @@ -88,6 +91,7 @@ impl ExtMetadataBlock { Self::Level10(b) => b.bytes_size(), Self::Level11(b) => b.bytes_size(), Self::Level15(b) => b.bytes_size(), + Self::Level16(b) => b.bytes_size(), Self::Level254(b) => b.bytes_size(), Self::Level255(b) => b.bytes_size(), Self::Reserved(b) => b.bytes_size(), @@ -107,6 +111,7 @@ impl ExtMetadataBlock { Self::Level10(b) => b.bits_size(), Self::Level11(b) => b.bits_size(), Self::Level15(b) => b.bits_size(), + Self::Level16(b) => b.bits_size(), Self::Level254(b) => b.bits_size(), Self::Level255(b) => b.bits_size(), Self::Reserved(b) => b.bits_size(), @@ -126,6 +131,7 @@ impl ExtMetadataBlock { Self::Level10(b) => b.required_bits(), Self::Level11(b) => b.required_bits(), Self::Level15(b) => b.required_bits(), + Self::Level16(b) => b.required_bits(), Self::Level254(b) => b.required_bits(), Self::Level255(b) => b.required_bits(), Self::Reserved(b) => b.required_bits(), @@ -145,6 +151,7 @@ impl ExtMetadataBlock { Self::Level10(b) => b.level(), Self::Level11(b) => b.level(), Self::Level15(b) => b.level(), + Self::Level16(b) => b.level(), Self::Level254(b) => b.level(), Self::Level255(b) => b.level(), Self::Reserved(b) => b.level(), @@ -164,6 +171,7 @@ impl ExtMetadataBlock { Self::Level10(b) => b.sort_key(), Self::Level11(b) => b.sort_key(), Self::Level15(b) => b.sort_key(), + Self::Level16(b) => b.sort_key(), Self::Level254(b) => b.sort_key(), Self::Level255(b) => b.sort_key(), Self::Reserved(b) => b.sort_key(), @@ -183,6 +191,7 @@ impl ExtMetadataBlock { Self::Level10(b) => b.write(writer), Self::Level11(b) => b.write(writer), Self::Level15(b) => b.write(writer), + Self::Level16(b) => b.write(writer), Self::Level254(b) => b.write(writer), Self::Level255(b) => b.write(writer), Self::Reserved(b) => b.write(writer), diff --git a/dolby_vision/src/rpu/extension_metadata/cmv40.rs b/dolby_vision/src/rpu/extension_metadata/cmv40.rs index 2770d72..1bb8f26 100644 --- a/dolby_vision/src/rpu/extension_metadata/cmv40.rs +++ b/dolby_vision/src/rpu/extension_metadata/cmv40.rs @@ -16,7 +16,7 @@ pub struct CmV40DmData { impl WithExtMetadataBlocks for CmV40DmData { const VERSION: &'static str = "CM v4.0"; - const ALLOWED_BLOCK_LEVELS: &'static [u8] = &[3, 8, 9, 10, 11, 15, 254]; + const ALLOWED_BLOCK_LEVELS: &'static [u8] = &[3, 8, 9, 10, 11, 15, 16, 254]; fn with_blocks_allocation(num_ext_blocks: u64) -> Self { Self { @@ -52,6 +52,7 @@ impl WithExtMetadataBlocks for CmV40DmData { 10 => level10::ExtMetadataBlockLevel10::parse(reader, ext_block_length)?, 11 => level11::ExtMetadataBlockLevel11::parse(reader)?, 15 => level15::ExtMetadataBlockLevel15::parse(reader)?, + 16 => level16::ExtMetadataBlockLevel16::parse(reader)?, 254 => level254::ExtMetadataBlockLevel254::parse(reader)?, 1 | 2 | 4 | 5 | 6 | 255 => bail!( "Invalid block level {} for {} RPU", diff --git a/dolby_vision/src/rpu/vdr_dm_data.rs b/dolby_vision/src/rpu/vdr_dm_data.rs index f3974af..e429676 100644 --- a/dolby_vision/src/rpu/vdr_dm_data.rs +++ b/dolby_vision/src/rpu/vdr_dm_data.rs @@ -389,6 +389,7 @@ impl VdrDmData { } ExtMetadataBlock::Level11(_) => self.replace_metadata_level(block), ExtMetadataBlock::Level15(_) => self.replace_metadata_level(block), + ExtMetadataBlock::Level16(_) => self.replace_metadata_level(block), ExtMetadataBlock::Level254(_) => self.replace_metadata_level(block), ExtMetadataBlock::Level255(_) => self.replace_metadata_level(block), ExtMetadataBlock::Reserved(_) => bail!("Cannot replace specific reserved block"), From 72deec11d94d8d4b717f538b1a1864540011b93e Mon Sep 17 00:00:00 2001 From: quietvoid Date: Thu, 24 Jul 2025 10:22:26 -0400 Subject: [PATCH 3/5] dovi: support level 17 extension metadata block --- .../src/c_structs/extension_metadata.rs | 3 + .../rpu/extension_metadata/blocks/level17.rs | 85 +++++++++++++++++++ .../src/rpu/extension_metadata/blocks/mod.rs | 9 ++ .../src/rpu/extension_metadata/cmv40.rs | 3 +- dolby_vision/src/rpu/vdr_dm_data.rs | 1 + 5 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 dolby_vision/src/rpu/extension_metadata/blocks/level17.rs diff --git a/dolby_vision/src/c_structs/extension_metadata.rs b/dolby_vision/src/c_structs/extension_metadata.rs index 6a58459..2a6e2b7 100644 --- a/dolby_vision/src/c_structs/extension_metadata.rs +++ b/dolby_vision/src/c_structs/extension_metadata.rs @@ -112,6 +112,9 @@ impl DmData { ExtMetadataBlock::Level16(_) => { // TODO } + ExtMetadataBlock::Level17(_) => { + // TODO + } ExtMetadataBlock::Level254(b) => { self.level254 = Box::into_raw(Box::new(b.clone())) as *const ExtMetadataBlockLevel254 diff --git a/dolby_vision/src/rpu/extension_metadata/blocks/level17.rs b/dolby_vision/src/rpu/extension_metadata/blocks/level17.rs new file mode 100644 index 0000000..8df75a8 --- /dev/null +++ b/dolby_vision/src/rpu/extension_metadata/blocks/level17.rs @@ -0,0 +1,85 @@ +use anyhow::Result; +use bitvec_helpers::{ + bitstream_io_reader::BsIoSliceReader, bitstream_io_writer::BitstreamIoWriter, +}; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +use super::{ExtMetadataBlock, ExtMetadataBlockInfo}; + +/// Up mapping metadata +#[repr(C)] +#[derive(Debug, Default, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +pub struct ExtMetadataBlockLevel17 { + pub mid_boost: u8, + pub highlight_stretch: u8, + pub shadow_drop: u8, + pub contrast_boost: u8, + pub saturation_boost: u8, + pub detail_boost: u8, + pub chroma_indicator: u8, + + /// 12 bits + pub intensity_indicator_pq: u16, + + /// 4 bits + pub revision: u8, + + pub chroma_lift: u8, +} + +impl ExtMetadataBlockLevel17 { + pub(crate) fn parse(reader: &mut BsIoSliceReader) -> Result { + let block = Self { + mid_boost: reader.read::<8, u8>()?, + highlight_stretch: reader.read::<8, u8>()?, + shadow_drop: reader.read::<8, u8>()?, + contrast_boost: reader.read::<8, u8>()?, + saturation_boost: reader.read::<8, u8>()?, + detail_boost: reader.read::<8, u8>()?, + chroma_indicator: reader.read::<8, u8>()?, + intensity_indicator_pq: reader.read::<12, u16>()?, + revision: reader.read::<4, u8>()?, + chroma_lift: reader.read::<8, u8>()?, + }; + + Ok(ExtMetadataBlock::Level17(block)) + } + + pub fn write(&self, writer: &mut BitstreamIoWriter) -> Result<()> { + self.validate()?; + + writer.write::<8, u8>(self.mid_boost)?; + writer.write::<8, u8>(self.highlight_stretch)?; + writer.write::<8, u8>(self.shadow_drop)?; + writer.write::<8, u8>(self.contrast_boost)?; + writer.write::<8, u8>(self.saturation_boost)?; + writer.write::<8, u8>(self.detail_boost)?; + writer.write::<8, u8>(self.chroma_indicator)?; + writer.write::<12, u16>(self.intensity_indicator_pq)?; + writer.write::<4, u8>(self.revision)?; + writer.write::<8, u8>(self.chroma_lift)?; + + Ok(()) + } + + pub fn validate(&self) -> Result<()> { + Ok(()) + } +} + +impl ExtMetadataBlockInfo for ExtMetadataBlockLevel17 { + fn level(&self) -> u8 { + 17 + } + + fn bytes_size(&self) -> u64 { + 10 + } + + fn required_bits(&self) -> u64 { + 80 + } +} diff --git a/dolby_vision/src/rpu/extension_metadata/blocks/mod.rs b/dolby_vision/src/rpu/extension_metadata/blocks/mod.rs index 6c123d3..4e406a1 100644 --- a/dolby_vision/src/rpu/extension_metadata/blocks/mod.rs +++ b/dolby_vision/src/rpu/extension_metadata/blocks/mod.rs @@ -11,6 +11,7 @@ pub mod level10; pub mod level11; pub mod level15; pub mod level16; +pub mod level17; pub mod level2; pub mod level254; pub mod level255; @@ -34,6 +35,7 @@ pub use level10::ExtMetadataBlockLevel10; pub use level11::ExtMetadataBlockLevel11; pub use level15::ExtMetadataBlockLevel15; pub use level16::ExtMetadataBlockLevel16; +pub use level17::ExtMetadataBlockLevel17; pub use level254::ExtMetadataBlockLevel254; pub use level255::ExtMetadataBlockLevel255; pub use reserved::ReservedExtMetadataBlock; @@ -58,6 +60,7 @@ pub enum ExtMetadataBlock { Level11(ExtMetadataBlockLevel11), Level15(ExtMetadataBlockLevel15), Level16(ExtMetadataBlockLevel16), + Level17(ExtMetadataBlockLevel17), Level254(ExtMetadataBlockLevel254), Level255(ExtMetadataBlockLevel255), Reserved(ReservedExtMetadataBlock), @@ -92,6 +95,7 @@ impl ExtMetadataBlock { Self::Level11(b) => b.bytes_size(), Self::Level15(b) => b.bytes_size(), Self::Level16(b) => b.bytes_size(), + Self::Level17(b) => b.bytes_size(), Self::Level254(b) => b.bytes_size(), Self::Level255(b) => b.bytes_size(), Self::Reserved(b) => b.bytes_size(), @@ -112,6 +116,7 @@ impl ExtMetadataBlock { Self::Level11(b) => b.bits_size(), Self::Level15(b) => b.bits_size(), Self::Level16(b) => b.bits_size(), + Self::Level17(b) => b.bits_size(), Self::Level254(b) => b.bits_size(), Self::Level255(b) => b.bits_size(), Self::Reserved(b) => b.bits_size(), @@ -132,6 +137,7 @@ impl ExtMetadataBlock { Self::Level11(b) => b.required_bits(), Self::Level15(b) => b.required_bits(), Self::Level16(b) => b.required_bits(), + Self::Level17(b) => b.required_bits(), Self::Level254(b) => b.required_bits(), Self::Level255(b) => b.required_bits(), Self::Reserved(b) => b.required_bits(), @@ -152,6 +158,7 @@ impl ExtMetadataBlock { Self::Level11(b) => b.level(), Self::Level15(b) => b.level(), Self::Level16(b) => b.level(), + Self::Level17(b) => b.level(), Self::Level254(b) => b.level(), Self::Level255(b) => b.level(), Self::Reserved(b) => b.level(), @@ -172,6 +179,7 @@ impl ExtMetadataBlock { Self::Level11(b) => b.sort_key(), Self::Level15(b) => b.sort_key(), Self::Level16(b) => b.sort_key(), + Self::Level17(b) => b.sort_key(), Self::Level254(b) => b.sort_key(), Self::Level255(b) => b.sort_key(), Self::Reserved(b) => b.sort_key(), @@ -192,6 +200,7 @@ impl ExtMetadataBlock { Self::Level11(b) => b.write(writer), Self::Level15(b) => b.write(writer), Self::Level16(b) => b.write(writer), + Self::Level17(b) => b.write(writer), Self::Level254(b) => b.write(writer), Self::Level255(b) => b.write(writer), Self::Reserved(b) => b.write(writer), diff --git a/dolby_vision/src/rpu/extension_metadata/cmv40.rs b/dolby_vision/src/rpu/extension_metadata/cmv40.rs index 1bb8f26..50d048b 100644 --- a/dolby_vision/src/rpu/extension_metadata/cmv40.rs +++ b/dolby_vision/src/rpu/extension_metadata/cmv40.rs @@ -16,7 +16,7 @@ pub struct CmV40DmData { impl WithExtMetadataBlocks for CmV40DmData { const VERSION: &'static str = "CM v4.0"; - const ALLOWED_BLOCK_LEVELS: &'static [u8] = &[3, 8, 9, 10, 11, 15, 16, 254]; + const ALLOWED_BLOCK_LEVELS: &'static [u8] = &[3, 8, 9, 10, 11, 15, 16, 17, 254]; fn with_blocks_allocation(num_ext_blocks: u64) -> Self { Self { @@ -53,6 +53,7 @@ impl WithExtMetadataBlocks for CmV40DmData { 11 => level11::ExtMetadataBlockLevel11::parse(reader)?, 15 => level15::ExtMetadataBlockLevel15::parse(reader)?, 16 => level16::ExtMetadataBlockLevel16::parse(reader)?, + 17 => level17::ExtMetadataBlockLevel17::parse(reader)?, 254 => level254::ExtMetadataBlockLevel254::parse(reader)?, 1 | 2 | 4 | 5 | 6 | 255 => bail!( "Invalid block level {} for {} RPU", diff --git a/dolby_vision/src/rpu/vdr_dm_data.rs b/dolby_vision/src/rpu/vdr_dm_data.rs index e429676..e05d0ee 100644 --- a/dolby_vision/src/rpu/vdr_dm_data.rs +++ b/dolby_vision/src/rpu/vdr_dm_data.rs @@ -390,6 +390,7 @@ impl VdrDmData { ExtMetadataBlock::Level11(_) => self.replace_metadata_level(block), ExtMetadataBlock::Level15(_) => self.replace_metadata_level(block), ExtMetadataBlock::Level16(_) => self.replace_metadata_level(block), + ExtMetadataBlock::Level17(_) => self.replace_metadata_level(block), ExtMetadataBlock::Level254(_) => self.replace_metadata_level(block), ExtMetadataBlock::Level255(_) => self.replace_metadata_level(block), ExtMetadataBlock::Reserved(_) => bail!("Cannot replace specific reserved block"), From 395c08743627275b2b0850e1fed440f1761c3c81 Mon Sep 17 00:00:00 2001 From: quietvoid Date: Thu, 24 Jul 2025 10:40:39 -0400 Subject: [PATCH 4/5] dovi: support level 18 extension metadata block --- .../src/c_structs/extension_metadata.rs | 3 + .../rpu/extension_metadata/blocks/level15.rs | 2 +- .../rpu/extension_metadata/blocks/level18.rs | 73 +++++++++++++++++++ .../src/rpu/extension_metadata/blocks/mod.rs | 9 +++ .../src/rpu/extension_metadata/cmv40.rs | 3 +- dolby_vision/src/rpu/vdr_dm_data.rs | 1 + 6 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 dolby_vision/src/rpu/extension_metadata/blocks/level18.rs diff --git a/dolby_vision/src/c_structs/extension_metadata.rs b/dolby_vision/src/c_structs/extension_metadata.rs index 2a6e2b7..b7aa1d8 100644 --- a/dolby_vision/src/c_structs/extension_metadata.rs +++ b/dolby_vision/src/c_structs/extension_metadata.rs @@ -115,6 +115,9 @@ impl DmData { ExtMetadataBlock::Level17(_) => { // TODO } + ExtMetadataBlock::Level18(_) => { + // TODO + } ExtMetadataBlock::Level254(b) => { self.level254 = Box::into_raw(Box::new(b.clone())) as *const ExtMetadataBlockLevel254 diff --git a/dolby_vision/src/rpu/extension_metadata/blocks/level15.rs b/dolby_vision/src/rpu/extension_metadata/blocks/level15.rs index ac98f17..6066500 100644 --- a/dolby_vision/src/rpu/extension_metadata/blocks/level15.rs +++ b/dolby_vision/src/rpu/extension_metadata/blocks/level15.rs @@ -87,6 +87,6 @@ impl ExtMetadataBlockInfo for ExtMetadataBlockLevel15 { } fn required_bits(&self) -> u64 { - 11 * 8 + 88 } } diff --git a/dolby_vision/src/rpu/extension_metadata/blocks/level18.rs b/dolby_vision/src/rpu/extension_metadata/blocks/level18.rs new file mode 100644 index 0000000..4b9db2a --- /dev/null +++ b/dolby_vision/src/rpu/extension_metadata/blocks/level18.rs @@ -0,0 +1,73 @@ +use anyhow::{Result, ensure}; +use bitvec_helpers::{ + bitstream_io_reader::BsIoSliceReader, bitstream_io_writer::BitstreamIoWriter, +}; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +use super::{ExtMetadataBlock, ExtMetadataBlockInfo}; + +/// Creative environment metadata +#[repr(C)] +#[derive(Debug, Default, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +pub struct ExtMetadataBlockLevel18 { + pub surround_luminance_pq: u16, + pub min_preserved_luminance_pq: u16, + pub adaptation_luminance_pq: u16, + pub max_preserved_luminance_pq: u16, + + /// 4 bits + pub revision: u8, + /// 4 bits + pub reserved: u8, +} + +impl ExtMetadataBlockLevel18 { + pub(crate) fn parse(reader: &mut BsIoSliceReader) -> Result { + let block = Self { + surround_luminance_pq: reader.read::<12, u16>()?, + min_preserved_luminance_pq: reader.read::<12, u16>()?, + adaptation_luminance_pq: reader.read::<12, u16>()?, + max_preserved_luminance_pq: reader.read::<12, u16>()?, + revision: reader.read::<4, u8>()?, + reserved: reader.read::<4, u8>()?, + }; + + Ok(ExtMetadataBlock::Level18(block)) + } + + pub fn write(&self, writer: &mut BitstreamIoWriter) -> Result<()> { + self.validate()?; + + writer.write::<12, u16>(self.surround_luminance_pq)?; + writer.write::<12, u16>(self.min_preserved_luminance_pq)?; + writer.write::<12, u16>(self.adaptation_luminance_pq)?; + writer.write::<12, u16>(self.max_preserved_luminance_pq)?; + writer.write::<4, u8>(self.revision)?; + writer.write::<4, u8>(self.reserved)?; + + Ok(()) + } + + pub fn validate(&self) -> Result<()> { + ensure!(self.reserved == 0); + + Ok(()) + } +} + +impl ExtMetadataBlockInfo for ExtMetadataBlockLevel18 { + fn level(&self) -> u8 { + 18 + } + + fn bytes_size(&self) -> u64 { + 7 + } + + fn required_bits(&self) -> u64 { + 56 + } +} diff --git a/dolby_vision/src/rpu/extension_metadata/blocks/mod.rs b/dolby_vision/src/rpu/extension_metadata/blocks/mod.rs index 4e406a1..1d6dcec 100644 --- a/dolby_vision/src/rpu/extension_metadata/blocks/mod.rs +++ b/dolby_vision/src/rpu/extension_metadata/blocks/mod.rs @@ -12,6 +12,7 @@ pub mod level11; pub mod level15; pub mod level16; pub mod level17; +pub mod level18; pub mod level2; pub mod level254; pub mod level255; @@ -36,6 +37,7 @@ pub use level11::ExtMetadataBlockLevel11; pub use level15::ExtMetadataBlockLevel15; pub use level16::ExtMetadataBlockLevel16; pub use level17::ExtMetadataBlockLevel17; +pub use level18::ExtMetadataBlockLevel18; pub use level254::ExtMetadataBlockLevel254; pub use level255::ExtMetadataBlockLevel255; pub use reserved::ReservedExtMetadataBlock; @@ -61,6 +63,7 @@ pub enum ExtMetadataBlock { Level15(ExtMetadataBlockLevel15), Level16(ExtMetadataBlockLevel16), Level17(ExtMetadataBlockLevel17), + Level18(ExtMetadataBlockLevel18), Level254(ExtMetadataBlockLevel254), Level255(ExtMetadataBlockLevel255), Reserved(ReservedExtMetadataBlock), @@ -96,6 +99,7 @@ impl ExtMetadataBlock { Self::Level15(b) => b.bytes_size(), Self::Level16(b) => b.bytes_size(), Self::Level17(b) => b.bytes_size(), + Self::Level18(b) => b.bytes_size(), Self::Level254(b) => b.bytes_size(), Self::Level255(b) => b.bytes_size(), Self::Reserved(b) => b.bytes_size(), @@ -117,6 +121,7 @@ impl ExtMetadataBlock { Self::Level15(b) => b.bits_size(), Self::Level16(b) => b.bits_size(), Self::Level17(b) => b.bits_size(), + Self::Level18(b) => b.bits_size(), Self::Level254(b) => b.bits_size(), Self::Level255(b) => b.bits_size(), Self::Reserved(b) => b.bits_size(), @@ -138,6 +143,7 @@ impl ExtMetadataBlock { Self::Level15(b) => b.required_bits(), Self::Level16(b) => b.required_bits(), Self::Level17(b) => b.required_bits(), + Self::Level18(b) => b.required_bits(), Self::Level254(b) => b.required_bits(), Self::Level255(b) => b.required_bits(), Self::Reserved(b) => b.required_bits(), @@ -159,6 +165,7 @@ impl ExtMetadataBlock { Self::Level15(b) => b.level(), Self::Level16(b) => b.level(), Self::Level17(b) => b.level(), + Self::Level18(b) => b.level(), Self::Level254(b) => b.level(), Self::Level255(b) => b.level(), Self::Reserved(b) => b.level(), @@ -180,6 +187,7 @@ impl ExtMetadataBlock { Self::Level15(b) => b.sort_key(), Self::Level16(b) => b.sort_key(), Self::Level17(b) => b.sort_key(), + Self::Level18(b) => b.sort_key(), Self::Level254(b) => b.sort_key(), Self::Level255(b) => b.sort_key(), Self::Reserved(b) => b.sort_key(), @@ -201,6 +209,7 @@ impl ExtMetadataBlock { Self::Level15(b) => b.write(writer), Self::Level16(b) => b.write(writer), Self::Level17(b) => b.write(writer), + Self::Level18(b) => b.write(writer), Self::Level254(b) => b.write(writer), Self::Level255(b) => b.write(writer), Self::Reserved(b) => b.write(writer), diff --git a/dolby_vision/src/rpu/extension_metadata/cmv40.rs b/dolby_vision/src/rpu/extension_metadata/cmv40.rs index 50d048b..66a6235 100644 --- a/dolby_vision/src/rpu/extension_metadata/cmv40.rs +++ b/dolby_vision/src/rpu/extension_metadata/cmv40.rs @@ -16,7 +16,7 @@ pub struct CmV40DmData { impl WithExtMetadataBlocks for CmV40DmData { const VERSION: &'static str = "CM v4.0"; - const ALLOWED_BLOCK_LEVELS: &'static [u8] = &[3, 8, 9, 10, 11, 15, 16, 17, 254]; + const ALLOWED_BLOCK_LEVELS: &'static [u8] = &[3, 8, 9, 10, 11, 15, 16, 17, 18, 254]; fn with_blocks_allocation(num_ext_blocks: u64) -> Self { Self { @@ -54,6 +54,7 @@ impl WithExtMetadataBlocks for CmV40DmData { 15 => level15::ExtMetadataBlockLevel15::parse(reader)?, 16 => level16::ExtMetadataBlockLevel16::parse(reader)?, 17 => level17::ExtMetadataBlockLevel17::parse(reader)?, + 18 => level18::ExtMetadataBlockLevel18::parse(reader)?, 254 => level254::ExtMetadataBlockLevel254::parse(reader)?, 1 | 2 | 4 | 5 | 6 | 255 => bail!( "Invalid block level {} for {} RPU", diff --git a/dolby_vision/src/rpu/vdr_dm_data.rs b/dolby_vision/src/rpu/vdr_dm_data.rs index e05d0ee..2a5703c 100644 --- a/dolby_vision/src/rpu/vdr_dm_data.rs +++ b/dolby_vision/src/rpu/vdr_dm_data.rs @@ -391,6 +391,7 @@ impl VdrDmData { ExtMetadataBlock::Level15(_) => self.replace_metadata_level(block), ExtMetadataBlock::Level16(_) => self.replace_metadata_level(block), ExtMetadataBlock::Level17(_) => self.replace_metadata_level(block), + ExtMetadataBlock::Level18(_) => self.replace_metadata_level(block), ExtMetadataBlock::Level254(_) => self.replace_metadata_level(block), ExtMetadataBlock::Level255(_) => self.replace_metadata_level(block), ExtMetadataBlock::Reserved(_) => bail!("Cannot replace specific reserved block"), From 976ba7712480f54d7dd35c2cfc6d068539d7364b Mon Sep 17 00:00:00 2001 From: quietvoid Date: Fri, 25 Jul 2025 09:17:42 -0400 Subject: [PATCH 5/5] Add test sample --- assets/tests/l15_to_l18.bin | Bin 0 -> 214 bytes src/tests/rpu.rs | 47 ++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 assets/tests/l15_to_l18.bin diff --git a/assets/tests/l15_to_l18.bin b/assets/tests/l15_to_l18.bin new file mode 100644 index 0000000000000000000000000000000000000000..00a64e4330eebe323fcc4a1de98da6f2678d91ce GIT binary patch literal 214 zcmZQzU|^Kw;N);fGz-XQu>ZmM{{a903k(b#3=C`y3=9qo3?>W=%uGPcxF{@vfjMqb zSpNKT8xMu0_$**x5CDoZ0F^-q#=}V}1`-KNA9Fki1ZtE@e!Bku2aqHLu`x0H;1d-v z;9!VIGGJ&3fXgr{9H?brP<-3K&*Wer!{ETez{JU*5y1g8_`rYv`270*`Rn(ezsT6c t6m#dVtgV9p5HKA{u=_7yU%&t7fnpZU;&zMA(=9vfA22A)2$*u90RSx*IzIpa literal 0 HcmV?d00001 diff --git a/src/tests/rpu.rs b/src/tests/rpu.rs index 2b6d197..48e1062 100644 --- a/src/tests/rpu.rs +++ b/src/tests/rpu.rs @@ -1134,3 +1134,50 @@ fn profile20_apple() -> Result<()> { Ok(()) } + +#[test] +fn l15_to_l18() -> Result<()> { + let (original_data, dovi_rpu) = _parse_file(PathBuf::from("./assets/tests/l15_to_l18.bin"))?; + assert_eq!(dovi_rpu.dovi_profile, 8); + let parsed_data = dovi_rpu.write_hevc_unspec62_nalu()?; + + assert_eq!(&original_data[4..], &parsed_data[2..]); + + let vdr_dm_data = dovi_rpu.vdr_dm_data.as_ref().unwrap(); + + let l15_meta = vdr_dm_data.get_block(15).unwrap(); + if let ExtMetadataBlock::Level15(b) = l15_meta { + assert_eq!(b.confidence, 244); + assert_eq!(b.precision_rendering_strength, 245); + assert_eq!(b.d_contrast_plus_one_no_pr, 253); + assert_eq!(b.revision, 1); + } + + let l16_meta = vdr_dm_data.get_block(16).unwrap(); + if let ExtMetadataBlock::Level16(b) = l16_meta { + assert_eq!(b.revision, 1); + assert_eq!(b.count, 2); + assert_eq!(b.params.len(), 2); + assert_eq!(b.params[0].max_d_saturation_plus_one, 234); + assert_eq!(b.params[1].precision_rendering_strength, 128); + } + + let l17_meta = vdr_dm_data.get_block(17).unwrap(); + if let ExtMetadataBlock::Level17(b) = l17_meta { + assert_eq!(b.mid_boost, 128); + assert_eq!(b.shadow_drop, 252); + assert_eq!(b.contrast_boost, 64); + assert_eq!(b.intensity_indicator_pq, 3696); + assert_eq!(b.revision, 1); + assert_eq!(b.chroma_lift, 204); + } + + let l18_meta = vdr_dm_data.get_block(18).unwrap(); + if let ExtMetadataBlock::Level18(b) = l18_meta { + assert_eq!(b.surround_luminance_pq, 3696); + assert_eq!(b.max_preserved_luminance_pq, 3699); + assert_eq!(b.revision, 1); + } + + Ok(()) +}