use super::*;
use alloc::vec::Vec;
impl<'a> ExtensionBodyDef<'a> for DtsHd<'a> {
const TAG_EXTENSION: u8 = 0x0E;
const NAME: &'static str = "DTS_HD";
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
pub struct DtsHd<'a> {
pub substream_core_flag: bool,
pub substream_0_flag: bool,
pub substream_1_flag: bool,
pub substream_2_flag: bool,
pub substream_3_flag: bool,
pub reserved: u8,
pub substreams: Vec<SubstreamInfo>,
#[cfg_attr(feature = "serde", serde(borrow))]
pub additional_info: &'a [u8],
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct SubstreamInfo {
pub channel_count: u8,
pub lfe_flag: bool,
pub sampling_frequency: SamplingFrequency,
pub sample_resolution: bool,
pub reserved: u8,
pub assets: Vec<AssetInfo>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct AssetInfo {
pub asset_construction: u8,
pub vbr_flag: bool,
pub post_encode_br_scaling_flag: bool,
pub component_type_flag: bool,
pub language_code_flag: bool,
pub bit_rate_or_scaled: u16,
pub reserved: u8,
pub component_type: Option<u8>,
pub iso_639_language_code: Option<LangCode>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
#[repr(u8)]
pub enum SamplingFrequency {
Khz8 = 0,
Khz16 = 1,
Khz32 = 2,
Khz64 = 3,
Khz128 = 4,
Khz22_05 = 5,
Khz44_1 = 6,
Khz88_2 = 7,
Khz176_4 = 8,
Khz352_8 = 9,
Khz12 = 10,
Khz24 = 11,
Khz48 = 12,
Khz96 = 13,
Khz192 = 14,
Khz348 = 15,
}
impl SamplingFrequency {
#[must_use]
pub fn from_u8(v: u8) -> Self {
match v {
0 => SamplingFrequency::Khz8,
1 => SamplingFrequency::Khz16,
2 => SamplingFrequency::Khz32,
3 => SamplingFrequency::Khz64,
4 => SamplingFrequency::Khz128,
5 => SamplingFrequency::Khz22_05,
6 => SamplingFrequency::Khz44_1,
7 => SamplingFrequency::Khz88_2,
8 => SamplingFrequency::Khz176_4,
9 => SamplingFrequency::Khz352_8,
10 => SamplingFrequency::Khz12,
11 => SamplingFrequency::Khz24,
12 => SamplingFrequency::Khz48,
13 => SamplingFrequency::Khz96,
14 => SamplingFrequency::Khz192,
15 => SamplingFrequency::Khz348,
_ => SamplingFrequency::Khz48, }
}
#[must_use]
pub const fn to_u8(self) -> u8 {
self as u8
}
#[must_use]
pub fn name(self) -> &'static str {
match self {
SamplingFrequency::Khz8 => "8 kHz",
SamplingFrequency::Khz16 => "16 kHz",
SamplingFrequency::Khz32 => "32 kHz",
SamplingFrequency::Khz64 => "64 kHz",
SamplingFrequency::Khz128 => "128 kHz",
SamplingFrequency::Khz22_05 => "22,05 kHz",
SamplingFrequency::Khz44_1 => "44,1 kHz",
SamplingFrequency::Khz88_2 => "88,2 kHz",
SamplingFrequency::Khz176_4 => "176,4 kHz",
SamplingFrequency::Khz352_8 => "352,8 kHz",
SamplingFrequency::Khz12 => "12 kHz",
SamplingFrequency::Khz24 => "24 kHz",
SamplingFrequency::Khz48 => "48 kHz",
SamplingFrequency::Khz96 => "96 kHz",
SamplingFrequency::Khz192 => "192 kHz",
SamplingFrequency::Khz348 => "348 kHz",
}
}
}
dvb_common::impl_spec_display!(SamplingFrequency);
const MAX_CHANNEL_COUNT: u8 = 0x1F;
const MAX_BIT_RATE: u16 = 0x1FFF;
const SUBSTREAM_HEADER_LEN: usize = 3;
const ASSET_FIXED_LEN: usize = 3;
impl Serialize for SubstreamInfo {
type Error = crate::error::Error;
fn serialized_len(&self) -> usize {
let payload_len: usize = self
.assets
.iter()
.map(|a| {
ASSET_FIXED_LEN
+ usize::from(a.component_type_flag)
+ usize::from(a.language_code_flag) * ISO_639_LEN
})
.sum();
SUBSTREAM_HEADER_LEN + payload_len
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
let payload_len = self.serialized_len() - SUBSTREAM_HEADER_LEN;
let substream_length = payload_len;
if substream_length > 0xFF {
return Err(Error::ValueOutOfRange {
field: "substream_length",
reason: "substream payload exceeds 255 bytes",
});
}
if self.channel_count > MAX_CHANNEL_COUNT {
return Err(Error::ValueOutOfRange {
field: "channel_count",
reason: "exceeds 5-bit field",
});
}
buf[0] = substream_length as u8;
let num_assets = self.assets.len();
if num_assets == 0 {
return Err(Error::ValueOutOfRange {
field: "num_assets",
reason: "substream must have at least 1 asset",
});
}
let na = (num_assets - 1) as u8;
buf[1] = (na << 5) | (self.channel_count & MAX_CHANNEL_COUNT);
buf[2] = ((u8::from(self.lfe_flag)) << 7)
| ((self.sampling_frequency.to_u8() & 0x0F) << 3)
| ((u8::from(self.sample_resolution)) << 2)
| (self.reserved & 0x03);
let mut pos = SUBSTREAM_HEADER_LEN;
for a in &self.assets {
if a.bit_rate_or_scaled > MAX_BIT_RATE {
return Err(Error::ValueOutOfRange {
field: "bit_rate_or_scaled",
reason: "exceeds 13-bit field",
});
}
buf[pos] = (a.asset_construction << 3)
| ((u8::from(a.vbr_flag)) << 2)
| ((u8::from(a.post_encode_br_scaling_flag)) << 1)
| u8::from(a.component_type_flag);
buf[pos + 1] =
(u8::from(a.language_code_flag) << 7) | ((a.bit_rate_or_scaled >> 6) as u8 & 0x7F);
buf[pos + 2] = ((a.bit_rate_or_scaled as u8 & 0x3F) << 2) | (a.reserved & 0x03);
pos += ASSET_FIXED_LEN;
if a.component_type_flag {
buf[pos] = a.component_type.unwrap_or(0);
pos += 1;
}
if a.language_code_flag {
buf[pos..pos + ISO_639_LEN]
.copy_from_slice(&a.iso_639_language_code.unwrap_or(LangCode(*b" ")).0);
pos += ISO_639_LEN;
}
}
Ok(pos)
}
}
impl<'a> Parse<'a> for DtsHd<'a> {
type Error = crate::error::Error;
fn parse(sel: &'a [u8]) -> Result<Self> {
let first = *sel.first().ok_or(Error::BufferTooShort {
need: 1,
have: 0,
what: "DTS-HD descriptor body",
})?;
let substream_core_flag = (first & 0x80) != 0;
let substream_0_flag = (first & 0x40) != 0;
let substream_1_flag = (first & 0x20) != 0;
let substream_2_flag = (first & 0x10) != 0;
let substream_3_flag = (first & 0x08) != 0;
let reserved = first & 0x07;
let flags = [
substream_core_flag,
substream_0_flag,
substream_1_flag,
substream_2_flag,
substream_3_flag,
];
let num_substreams = flags.iter().filter(|&&f| f).count();
let mut pos = 1;
let mut substreams = Vec::with_capacity(num_substreams);
for &present in &flags {
if !present {
continue;
}
let si = parse_substream_info(sel, &mut pos)?;
substreams.push(si);
}
Ok(DtsHd {
substream_core_flag,
substream_0_flag,
substream_1_flag,
substream_2_flag,
substream_3_flag,
reserved,
substreams,
additional_info: &sel[pos..],
})
}
}
fn parse_substream_info(sel: &[u8], pos: &mut usize) -> Result<SubstreamInfo> {
let need = *pos + SUBSTREAM_HEADER_LEN;
if sel.len() < need {
return Err(Error::BufferTooShort {
need,
have: sel.len(),
what: "substream_info header",
});
}
let substream_length = sel[*pos] as usize;
*pos += 1;
let end = *pos + substream_length;
if sel.len() < end {
return Err(Error::BufferTooShort {
need: end,
have: sel.len(),
what: "substream_info body",
});
}
let num_assets = ((sel[*pos] >> 5) & 0x07) as usize + 1;
let channel_count = sel[*pos] & 0x1F;
*pos += 1;
let lfe_flag = (sel[*pos] & 0x80) != 0;
let sampling_frequency = SamplingFrequency::from_u8((sel[*pos] >> 3) & 0x0F);
let sample_resolution = (sel[*pos] & 0x04) != 0;
let s_reserved = sel[*pos] & 0x03;
*pos += 1;
let mut assets = Vec::with_capacity(num_assets);
for _ in 0..num_assets {
let a = parse_asset_info(sel, pos)?;
assets.push(a);
}
Ok(SubstreamInfo {
channel_count,
lfe_flag,
sampling_frequency,
sample_resolution,
reserved: s_reserved,
assets,
})
}
fn parse_asset_info(sel: &[u8], pos: &mut usize) -> Result<AssetInfo> {
let need = *pos + ASSET_FIXED_LEN;
if sel.len() < need {
return Err(Error::BufferTooShort {
need,
have: sel.len(),
what: "asset_info",
});
}
let asset_construction = (sel[*pos] >> 3) & 0x1F;
let vbr_flag = (sel[*pos] & 0x04) != 0;
let post_encode_br_scaling_flag = (sel[*pos] & 0x02) != 0;
let component_type_flag = (sel[*pos] & 0x01) != 0;
*pos += 1;
let language_code_flag = (sel[*pos] & 0x80) != 0;
let bit_rate_or_scaled = ((u16::from(sel[*pos] & 0x7F)) << 6) | (u16::from(sel[*pos + 1]) >> 2);
*pos += 1;
let a_reserved = sel[*pos] & 0x03;
*pos += 1;
let component_type = if component_type_flag {
let ct = *sel.get(*pos).ok_or(Error::BufferTooShort {
need: *pos + 1,
have: sel.len(),
what: "asset_info component_type",
})?;
*pos += 1;
Some(ct)
} else {
None
};
let iso_639_language_code = if language_code_flag {
let need_lang = *pos + ISO_639_LEN;
let lang_bytes = sel.get(*pos..need_lang).ok_or(Error::BufferTooShort {
need: need_lang,
have: sel.len(),
what: "asset_info ISO_639_language_code",
})?;
*pos += ISO_639_LEN;
Some(LangCode([lang_bytes[0], lang_bytes[1], lang_bytes[2]]))
} else {
None
};
Ok(AssetInfo {
asset_construction,
vbr_flag,
post_encode_br_scaling_flag,
component_type_flag,
language_code_flag,
bit_rate_or_scaled,
reserved: a_reserved,
component_type,
iso_639_language_code,
})
}
impl Serialize for DtsHd<'_> {
type Error = crate::error::Error;
fn serialized_len(&self) -> usize {
1 + self
.substreams
.iter()
.map(|s| s.serialized_len())
.sum::<usize>()
+ self.additional_info.len()
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
let len = self.serialized_len();
if buf.len() < len {
return Err(Error::OutputBufferTooSmall {
need: len,
have: buf.len(),
});
}
buf[0] = ((u8::from(self.substream_core_flag)) << 7)
| ((u8::from(self.substream_0_flag)) << 6)
| ((u8::from(self.substream_1_flag)) << 5)
| ((u8::from(self.substream_2_flag)) << 4)
| ((u8::from(self.substream_3_flag)) << 3)
| (self.reserved & 0x07);
let flags = [
self.substream_core_flag,
self.substream_0_flag,
self.substream_1_flag,
self.substream_2_flag,
self.substream_3_flag,
];
let mut pos = 1;
let mut si = 0;
for &present in &flags {
if !present {
continue;
}
if si >= self.substreams.len() {
return Err(Error::ValueOutOfRange {
field: "DTS-HD substreams",
reason: "fewer substreams than flags indicate",
});
}
let written = self.substreams[si].serialize_into(&mut buf[pos..])?;
pos += written;
si += 1;
}
if si != self.substreams.len() {
return Err(Error::ValueOutOfRange {
field: "DTS-HD substreams",
reason: "more substreams than flags indicate",
});
}
buf[pos..len].copy_from_slice(self.additional_info);
Ok(len)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::descriptors::extension::test_support::*;
use crate::descriptors::extension::{ExtensionBody, ExtensionDescriptor};
#[test]
fn decodes_sampling_frequency() {
assert_eq!(SamplingFrequency::from_u8(12).name(), "48 kHz");
assert_eq!(SamplingFrequency::from_u8(0).name(), "8 kHz");
}
#[test]
fn parse_dts_hd_core_only() {
let sel = [
0x87, 0x06, 0x06, 0xE7, 0x09, 0x8B, 0xCF, 0x42, b'e', b'n', b'g', ];
let bytes = wrap(0x0E, &sel);
let d = ExtensionDescriptor::parse(&bytes).unwrap();
match &d.body {
ExtensionBody::DtsHd(b) => {
assert!(b.substream_core_flag);
assert!(!b.substream_0_flag);
assert!(!b.substream_1_flag);
assert!(!b.substream_2_flag);
assert!(!b.substream_3_flag);
assert_eq!(b.reserved, 7);
assert_eq!(b.substreams.len(), 1);
let s = &b.substreams[0];
assert_eq!(s.channel_count, 6);
assert!(s.lfe_flag);
assert_eq!(s.sampling_frequency, SamplingFrequency::Khz48);
assert!(s.sample_resolution);
assert_eq!(s.reserved, 3);
assert_eq!(s.assets.len(), 1);
let a = &s.assets[0];
assert_eq!(a.asset_construction, 1);
assert!(!a.vbr_flag);
assert!(!a.post_encode_br_scaling_flag);
assert!(a.component_type_flag);
assert!(a.language_code_flag);
assert_eq!(a.bit_rate_or_scaled, 755);
assert_eq!(a.reserved, 3);
assert_eq!(a.component_type, Some(0x42));
assert_eq!(a.iso_639_language_code, Some(LangCode(*b"eng")));
assert!(b.additional_info.is_empty());
}
other => panic!("expected DtsHd, got {other:?}"),
}
round_trip(&d);
}
#[test]
fn parse_dts_hd_flags_only() {
let sel = [0x00];
let bytes = wrap(0x0E, &sel);
let d = ExtensionDescriptor::parse(&bytes).unwrap();
match &d.body {
ExtensionBody::DtsHd(b) => {
assert!(!b.substream_core_flag);
assert!(b.substreams.is_empty());
}
other => panic!("expected DtsHd, got {other:?}"),
}
round_trip(&d);
}
}