use super::*;
impl<'a> ExtensionBodyDef<'a> for DtsUhd<'a> {
const TAG_EXTENSION: u8 = 0x21;
const NAME: &'static str = "DTS_UHD";
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
pub struct DtsUhd<'a> {
pub decoder_profile_code: u8,
pub frame_duration_code: FrameDurationCode,
pub max_payload_code: MaxPayloadCode,
pub dts_reserved: u8,
pub stream_index: u8,
#[cfg_attr(feature = "serde", serde(borrow))]
pub codec_selector: &'a [u8],
}
impl DtsUhd<'_> {
#[must_use]
pub fn decoder_profile(&self) -> u8 {
self.decoder_profile_code + 2
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub enum FrameDurationCode {
Samples512,
Samples1024,
Samples2048,
Samples4096,
}
impl FrameDurationCode {
#[must_use]
pub fn from_u8(v: u8) -> Self {
match v {
0 => FrameDurationCode::Samples512,
1 => FrameDurationCode::Samples1024,
2 => FrameDurationCode::Samples2048,
3 => FrameDurationCode::Samples4096,
_ => FrameDurationCode::Samples4096, }
}
#[must_use]
pub const fn to_u8(self) -> u8 {
match self {
FrameDurationCode::Samples512 => 0,
FrameDurationCode::Samples1024 => 1,
FrameDurationCode::Samples2048 => 2,
FrameDurationCode::Samples4096 => 3,
}
}
#[must_use]
pub fn name(self) -> &'static str {
match self {
FrameDurationCode::Samples512 => "512 samples",
FrameDurationCode::Samples1024 => "1 024 samples",
FrameDurationCode::Samples2048 => "2 048 samples",
FrameDurationCode::Samples4096 => "4 096 samples",
}
}
}
dvb_common::impl_spec_display!(FrameDurationCode);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub enum MaxPayloadCode {
Byte2048,
Byte4096,
Byte8192,
Byte16384,
Byte32768,
Byte65536,
Byte131072,
Reserved(u8),
}
impl MaxPayloadCode {
#[must_use]
pub fn from_u8(v: u8) -> Self {
match v {
0 => MaxPayloadCode::Byte2048,
1 => MaxPayloadCode::Byte4096,
2 => MaxPayloadCode::Byte8192,
3 => MaxPayloadCode::Byte16384,
4 => MaxPayloadCode::Byte32768,
5 => MaxPayloadCode::Byte65536,
6 => MaxPayloadCode::Byte131072,
other => MaxPayloadCode::Reserved(other),
}
}
#[must_use]
pub const fn to_u8(self) -> u8 {
match self {
MaxPayloadCode::Byte2048 => 0,
MaxPayloadCode::Byte4096 => 1,
MaxPayloadCode::Byte8192 => 2,
MaxPayloadCode::Byte16384 => 3,
MaxPayloadCode::Byte32768 => 4,
MaxPayloadCode::Byte65536 => 5,
MaxPayloadCode::Byte131072 => 6,
MaxPayloadCode::Reserved(v) => v,
}
}
#[must_use]
pub fn name(self) -> &'static str {
match self {
MaxPayloadCode::Byte2048 => "2 048 byte",
MaxPayloadCode::Byte4096 => "4 096 byte",
MaxPayloadCode::Byte8192 => "8 192 byte",
MaxPayloadCode::Byte16384 => "16 384 byte",
MaxPayloadCode::Byte32768 => "32 768 byte",
MaxPayloadCode::Byte65536 => "65 536 byte",
MaxPayloadCode::Byte131072 => "131 072 byte",
MaxPayloadCode::Reserved(_) => "reserved for future use",
}
}
}
dvb_common::impl_spec_display!(MaxPayloadCode, Reserved);
const DTS_UHD_FIXED_LEN: usize = 2;
impl<'a> Parse<'a> for DtsUhd<'a> {
type Error = crate::error::Error;
fn parse(sel: &'a [u8]) -> Result<Self> {
if sel.len() < DTS_UHD_FIXED_LEN {
return Err(Error::BufferTooShort {
need: DTS_UHD_FIXED_LEN,
have: sel.len(),
what: "DTS-UHD descriptor body",
});
}
let decoder_profile_code = (sel[0] >> 2) & 0x3F;
let frame_duration_code = FrameDurationCode::from_u8(sel[0] & 0x03);
let max_payload_code = MaxPayloadCode::from_u8((sel[1] >> 5) & 0x07);
let dts_reserved = (sel[1] >> 3) & 0x03;
let stream_index = sel[1] & 0x07;
Ok(DtsUhd {
decoder_profile_code,
frame_duration_code,
max_payload_code,
dts_reserved,
stream_index,
codec_selector: &sel[DTS_UHD_FIXED_LEN..],
})
}
}
impl Serialize for DtsUhd<'_> {
type Error = crate::error::Error;
fn serialized_len(&self) -> usize {
DTS_UHD_FIXED_LEN + self.codec_selector.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] = (self.decoder_profile_code << 2) | (self.frame_duration_code.to_u8() & 0x03);
buf[1] = (self.max_payload_code.to_u8() << 5)
| ((self.dts_reserved & 0x03) << 3)
| (self.stream_index & 0x07);
buf[DTS_UHD_FIXED_LEN..len].copy_from_slice(self.codec_selector);
Ok(len)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::descriptors::extension::test_support::*;
use crate::descriptors::extension::{ExtensionBody, ExtensionDescriptor};
#[test]
fn decodes_frame_duration_code() {
assert_eq!(FrameDurationCode::from_u8(0).name(), "512 samples");
assert_eq!(FrameDurationCode::from_u8(2).name(), "2 048 samples");
}
#[test]
fn decodes_max_payload_code() {
assert_eq!(MaxPayloadCode::from_u8(4).name(), "32 768 byte");
}
#[test]
fn parse_dts_uhd_structured() {
let sel = [0x06, 0x43, 0xAB, 0xCD];
let bytes = wrap(0x21, &sel);
let d = ExtensionDescriptor::parse(&bytes).unwrap();
match &d.body {
ExtensionBody::DtsUhd(b) => {
assert_eq!(b.decoder_profile_code, 1);
assert_eq!(b.decoder_profile(), 3);
assert_eq!(b.frame_duration_code, FrameDurationCode::Samples2048);
assert_eq!(b.max_payload_code, MaxPayloadCode::Byte8192);
assert_eq!(b.dts_reserved, 0);
assert_eq!(b.stream_index, 3);
assert_eq!(b.codec_selector, &[0xAB, 0xCD]);
}
other => panic!("expected DtsUhd, got {other:?}"),
}
round_trip(&d);
}
#[test]
fn parse_dts_uhd_no_codec_selector() {
let sel = [0x06, 0x43];
let bytes = wrap(0x21, &sel);
let d = ExtensionDescriptor::parse(&bytes).unwrap();
match &d.body {
ExtensionBody::DtsUhd(b) => {
assert!(b.codec_selector.is_empty());
}
other => panic!("expected DtsUhd, got {other:?}"),
}
round_trip(&d);
}
}