dvb_si/descriptors/extension/
dts_uhd.rs1use super::*;
3
4impl<'a> ExtensionBodyDef<'a> for DtsUhd<'a> {
5 const TAG_EXTENSION: u8 = 0x21;
6 const NAME: &'static str = "DTS_UHD";
7}
8
9#[derive(Debug, Clone, PartialEq, Eq)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize))]
12#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
13pub struct DtsUhd<'a> {
14 pub decoder_profile_code: u8,
16 pub frame_duration_code: FrameDurationCode,
18 pub max_payload_code: MaxPayloadCode,
20 pub dts_reserved: u8,
22 pub stream_index: u8,
24 #[cfg_attr(feature = "serde", serde(borrow))]
26 pub codec_selector: &'a [u8],
27}
28
29impl DtsUhd<'_> {
30 #[must_use]
32 pub fn decoder_profile(&self) -> u8 {
33 self.decoder_profile_code + 2
34 }
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39#[cfg_attr(feature = "serde", derive(serde::Serialize))]
40#[non_exhaustive]
41pub enum FrameDurationCode {
42 Samples512,
44 Samples1024,
46 Samples2048,
48 Samples4096,
50}
51
52impl FrameDurationCode {
53 #[must_use]
55 pub fn from_u8(v: u8) -> Self {
56 match v {
57 0 => FrameDurationCode::Samples512,
58 1 => FrameDurationCode::Samples1024,
59 2 => FrameDurationCode::Samples2048,
60 3 => FrameDurationCode::Samples4096,
61 _ => FrameDurationCode::Samples4096, }
63 }
64
65 #[must_use]
67 pub const fn to_u8(self) -> u8 {
68 match self {
69 FrameDurationCode::Samples512 => 0,
70 FrameDurationCode::Samples1024 => 1,
71 FrameDurationCode::Samples2048 => 2,
72 FrameDurationCode::Samples4096 => 3,
73 }
74 }
75
76 #[must_use]
78 pub fn name(self) -> &'static str {
79 match self {
80 FrameDurationCode::Samples512 => "512 samples",
81 FrameDurationCode::Samples1024 => "1 024 samples",
82 FrameDurationCode::Samples2048 => "2 048 samples",
83 FrameDurationCode::Samples4096 => "4 096 samples",
84 }
85 }
86}
87dvb_common::impl_spec_display!(FrameDurationCode);
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq)]
91#[cfg_attr(feature = "serde", derive(serde::Serialize))]
92#[non_exhaustive]
93pub enum MaxPayloadCode {
94 Byte2048,
96 Byte4096,
98 Byte8192,
100 Byte16384,
102 Byte32768,
104 Byte65536,
106 Byte131072,
108 Reserved(u8),
110}
111
112impl MaxPayloadCode {
113 #[must_use]
115 pub fn from_u8(v: u8) -> Self {
116 match v {
117 0 => MaxPayloadCode::Byte2048,
118 1 => MaxPayloadCode::Byte4096,
119 2 => MaxPayloadCode::Byte8192,
120 3 => MaxPayloadCode::Byte16384,
121 4 => MaxPayloadCode::Byte32768,
122 5 => MaxPayloadCode::Byte65536,
123 6 => MaxPayloadCode::Byte131072,
124 other => MaxPayloadCode::Reserved(other),
125 }
126 }
127
128 #[must_use]
130 pub const fn to_u8(self) -> u8 {
131 match self {
132 MaxPayloadCode::Byte2048 => 0,
133 MaxPayloadCode::Byte4096 => 1,
134 MaxPayloadCode::Byte8192 => 2,
135 MaxPayloadCode::Byte16384 => 3,
136 MaxPayloadCode::Byte32768 => 4,
137 MaxPayloadCode::Byte65536 => 5,
138 MaxPayloadCode::Byte131072 => 6,
139 MaxPayloadCode::Reserved(v) => v,
140 }
141 }
142
143 #[must_use]
145 pub fn name(self) -> &'static str {
146 match self {
147 MaxPayloadCode::Byte2048 => "2 048 byte",
148 MaxPayloadCode::Byte4096 => "4 096 byte",
149 MaxPayloadCode::Byte8192 => "8 192 byte",
150 MaxPayloadCode::Byte16384 => "16 384 byte",
151 MaxPayloadCode::Byte32768 => "32 768 byte",
152 MaxPayloadCode::Byte65536 => "65 536 byte",
153 MaxPayloadCode::Byte131072 => "131 072 byte",
154 MaxPayloadCode::Reserved(_) => "reserved for future use",
155 }
156 }
157}
158dvb_common::impl_spec_display!(MaxPayloadCode, Reserved);
159
160const DTS_UHD_FIXED_LEN: usize = 2;
162
163impl<'a> Parse<'a> for DtsUhd<'a> {
164 type Error = crate::error::Error;
165 fn parse(sel: &'a [u8]) -> Result<Self> {
166 if sel.len() < DTS_UHD_FIXED_LEN {
167 return Err(Error::BufferTooShort {
168 need: DTS_UHD_FIXED_LEN,
169 have: sel.len(),
170 what: "DTS-UHD descriptor body",
171 });
172 }
173 let decoder_profile_code = (sel[0] >> 2) & 0x3F;
174 let frame_duration_code = FrameDurationCode::from_u8(sel[0] & 0x03);
175 let max_payload_code = MaxPayloadCode::from_u8((sel[1] >> 5) & 0x07);
176 let dts_reserved = (sel[1] >> 3) & 0x03;
177 let stream_index = sel[1] & 0x07;
178 Ok(DtsUhd {
179 decoder_profile_code,
180 frame_duration_code,
181 max_payload_code,
182 dts_reserved,
183 stream_index,
184 codec_selector: &sel[DTS_UHD_FIXED_LEN..],
185 })
186 }
187}
188
189impl Serialize for DtsUhd<'_> {
190 type Error = crate::error::Error;
191 fn serialized_len(&self) -> usize {
192 DTS_UHD_FIXED_LEN + self.codec_selector.len()
193 }
194 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
195 let len = self.serialized_len();
196 if buf.len() < len {
197 return Err(Error::OutputBufferTooSmall {
198 need: len,
199 have: buf.len(),
200 });
201 }
202 buf[0] = (self.decoder_profile_code << 2) | (self.frame_duration_code.to_u8() & 0x03);
203 buf[1] = (self.max_payload_code.to_u8() << 5)
204 | ((self.dts_reserved & 0x03) << 3)
205 | (self.stream_index & 0x07);
206 buf[DTS_UHD_FIXED_LEN..len].copy_from_slice(self.codec_selector);
207 Ok(len)
208 }
209}
210
211#[cfg(test)]
212mod tests {
213 use super::*;
214 use crate::descriptors::extension::test_support::*;
215 use crate::descriptors::extension::{ExtensionBody, ExtensionDescriptor};
216
217 #[test]
218 fn decodes_frame_duration_code() {
219 assert_eq!(FrameDurationCode::from_u8(0).name(), "512 samples");
220 assert_eq!(FrameDurationCode::from_u8(2).name(), "2 048 samples");
221 }
222
223 #[test]
224 fn decodes_max_payload_code() {
225 assert_eq!(MaxPayloadCode::from_u8(4).name(), "32 768 byte");
226 }
227
228 #[test]
229 fn parse_dts_uhd_structured() {
230 let sel = [0x06, 0x43, 0xAB, 0xCD];
232 let bytes = wrap(0x21, &sel);
233 let d = ExtensionDescriptor::parse(&bytes).unwrap();
234 match &d.body {
235 ExtensionBody::DtsUhd(b) => {
236 assert_eq!(b.decoder_profile_code, 1);
237 assert_eq!(b.decoder_profile(), 3);
238 assert_eq!(b.frame_duration_code, FrameDurationCode::Samples2048);
239 assert_eq!(b.max_payload_code, MaxPayloadCode::Byte8192);
240 assert_eq!(b.dts_reserved, 0);
241 assert_eq!(b.stream_index, 3);
242 assert_eq!(b.codec_selector, &[0xAB, 0xCD]);
243 }
244 other => panic!("expected DtsUhd, got {other:?}"),
245 }
246 round_trip(&d);
247 }
248
249 #[test]
250 fn parse_dts_uhd_no_codec_selector() {
251 let sel = [0x06, 0x43];
252 let bytes = wrap(0x21, &sel);
253 let d = ExtensionDescriptor::parse(&bytes).unwrap();
254 match &d.body {
255 ExtensionBody::DtsUhd(b) => {
256 assert!(b.codec_selector.is_empty());
257 }
258 other => panic!("expected DtsUhd, got {other:?}"),
259 }
260 round_trip(&d);
261 }
262}