dvb_si/descriptors/extension/
audio_preselection.rs1use super::*;
3
4impl<'a> ExtensionBodyDef<'a> for AudioPreselection<'a> {
5 const TAG_EXTENSION: u8 = 0x19;
6 const NAME: &'static str = "AUDIO_PRESELECTION";
7}
8#[derive(Debug, Clone, PartialEq, Eq)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize))]
11#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
12pub struct AudioPreselection<'a> {
13 pub preselections: Vec<Preselection<'a>>,
15}
16
17#[derive(Debug, Clone, PartialEq, Eq)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize))]
21#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
22pub struct Preselection<'a> {
23 pub preselection_id: u8,
25 pub audio_rendering_indication: u8,
27 pub audio_description: bool,
29 pub spoken_subtitles: bool,
31 pub dialogue_enhancement: bool,
33 pub interactivity_enabled: bool,
35 pub language_code: Option<LangCode>,
37 pub message_id: Option<u8>,
39 pub aux_component_tags: Option<&'a [u8]>,
41 pub future_extension: Option<&'a [u8]>,
43}
44
45impl<'a> Parse<'a> for AudioPreselection<'a> {
46 type Error = crate::error::Error;
47 fn parse(sel: &'a [u8]) -> Result<Self> {
48 if sel.is_empty() {
49 return Err(Error::BufferTooShort {
50 need: 1,
51 have: sel.len(),
52 what: "audio_preselection body",
53 });
54 }
55 let num_preselections = sel[0] >> 3;
56 let mut pos = 1;
57 let mut preselections = Vec::with_capacity(num_preselections as usize);
58 for _ in 0..num_preselections {
59 if pos + 2 > sel.len() {
60 return Err(Error::BufferTooShort {
61 need: pos + 2,
62 have: sel.len(),
63 what: "audio_preselection body",
64 });
65 }
66 let byte_a = sel[pos];
67 let byte_b = sel[pos + 1];
68 pos += 2;
69 let preselection_id = byte_a >> 3;
70 let audio_rendering_indication = byte_a & 0x07;
71 let audio_description = (byte_b >> 7) & 1 != 0;
72 let spoken_subtitles = (byte_b >> 6) & 1 != 0;
73 let dialogue_enhancement = (byte_b >> 5) & 1 != 0;
74 let interactivity_enabled = (byte_b >> 4) & 1 != 0;
75 let language_code_present = (byte_b >> 3) & 1 != 0;
76 let text_label_present = (byte_b >> 2) & 1 != 0;
77 let multi_stream_info_present = (byte_b >> 1) & 1 != 0;
78 let future_extension = byte_b & 1 != 0;
79
80 let language_code = if language_code_present {
81 if pos + ISO_639_LEN > sel.len() {
82 return Err(Error::BufferTooShort {
83 need: pos + ISO_639_LEN,
84 have: sel.len(),
85 what: "audio_preselection body",
86 });
87 }
88 let lc = LangCode([sel[pos], sel[pos + 1], sel[pos + 2]]);
89 pos += ISO_639_LEN;
90 Some(lc)
91 } else {
92 None
93 };
94
95 let message_id = if text_label_present {
96 if pos >= sel.len() {
97 return Err(Error::BufferTooShort {
98 need: pos + 1,
99 have: sel.len(),
100 what: "audio_preselection body",
101 });
102 }
103 let id = sel[pos];
104 pos += 1;
105 Some(id)
106 } else {
107 None
108 };
109
110 let aux_component_tags = if multi_stream_info_present {
111 if pos >= sel.len() {
112 return Err(Error::BufferTooShort {
113 need: pos + 1,
114 have: sel.len(),
115 what: "audio_preselection body",
116 });
117 }
118 let num_aux = sel[pos] >> 5;
119 pos += 1;
120 if pos + num_aux as usize > sel.len() {
121 return Err(Error::BufferTooShort {
122 need: pos + num_aux as usize,
123 have: sel.len(),
124 what: "audio_preselection body",
125 });
126 }
127 let tags = &sel[pos..pos + num_aux as usize];
128 pos += num_aux as usize;
129 Some(tags)
130 } else {
131 None
132 };
133
134 let future_ext = if future_extension {
135 if pos >= sel.len() {
136 return Err(Error::BufferTooShort {
137 need: pos + 1,
138 have: sel.len(),
139 what: "audio_preselection body",
140 });
141 }
142 let ext_len = (sel[pos] & 0x1F) as usize;
143 pos += 1;
144 if pos + ext_len > sel.len() {
145 return Err(Error::BufferTooShort {
146 need: pos + ext_len,
147 have: sel.len(),
148 what: "audio_preselection body",
149 });
150 }
151 let ext = &sel[pos..pos + ext_len];
152 pos += ext_len;
153 Some(ext)
154 } else {
155 None
156 };
157
158 preselections.push(Preselection {
159 preselection_id,
160 audio_rendering_indication,
161 audio_description,
162 spoken_subtitles,
163 dialogue_enhancement,
164 interactivity_enabled,
165 language_code,
166 message_id,
167 aux_component_tags,
168 future_extension: future_ext,
169 });
170 }
171 Ok(AudioPreselection { preselections })
172 }
173}
174
175impl Serialize for AudioPreselection<'_> {
176 type Error = crate::error::Error;
177 fn serialized_len(&self) -> usize {
178 let body: usize = self
179 .preselections
180 .iter()
181 .map(|p| {
182 2 + p.language_code.map_or(0, |_| ISO_639_LEN)
183 + p.message_id.map_or(0, |_| 1)
184 + p.aux_component_tags.map_or(0, |t| 1 + t.len())
185 + p.future_extension.map_or(0, |e| 1 + e.len())
186 })
187 .sum();
188 1 + body
189 }
190 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
191 let len = self.serialized_len();
192 if buf.len() < len {
193 return Err(Error::OutputBufferTooSmall {
194 need: len,
195 have: buf.len(),
196 });
197 }
198 buf[0] = ((self.preselections.len() as u8) & 0x1F) << 3;
199 let mut p = 1;
200 for s in &self.preselections {
201 buf[p] = ((s.preselection_id & 0x1F) << 3) | (s.audio_rendering_indication & 0x07);
202 buf[p + 1] = (u8::from(s.audio_description) << 7)
203 | (u8::from(s.spoken_subtitles) << 6)
204 | (u8::from(s.dialogue_enhancement) << 5)
205 | (u8::from(s.interactivity_enabled) << 4)
206 | (u8::from(s.language_code.is_some()) << 3)
207 | (u8::from(s.message_id.is_some()) << 2)
208 | (u8::from(s.aux_component_tags.is_some()) << 1)
209 | u8::from(s.future_extension.is_some());
210 p += 2;
211 if let Some(ref lc) = s.language_code {
212 buf[p..p + ISO_639_LEN].copy_from_slice(&lc.0);
213 p += ISO_639_LEN;
214 }
215 if let Some(id) = s.message_id {
216 buf[p] = id;
217 p += 1;
218 }
219 if let Some(tags) = s.aux_component_tags {
220 buf[p] = ((tags.len() as u8) & 0x07) << 5;
221 p += 1;
222 buf[p..p + tags.len()].copy_from_slice(tags);
223 p += tags.len();
224 }
225 if let Some(ext) = s.future_extension {
226 buf[p] = ext.len() as u8 & 0x1F;
227 p += 1;
228 buf[p..p + ext.len()].copy_from_slice(ext);
229 p += ext.len();
230 }
231 }
232 Ok(len)
233 }
234}
235
236#[cfg(test)]
237mod tests {
238 use super::*;
239 use crate::descriptors::extension::test_support::*;
240 use crate::descriptors::extension::{ExtensionBody, ExtensionDescriptor};
241 use crate::text::LangCode;
242
243 #[test]
244 fn parse_structured_round_trip_two_preselections() {
245 let num_pre = 0x02 << 3;
246 let pre0_a = (1 << 3) | 2; let pre0_b = (1 << 6) | (1 << 4); let pre1_a = (2 << 3) | 3; let pre1_b = (1 << 7) | (1 << 5) | (1 << 3) | (1 << 2) | (1 << 1) | 1;
251 let lang = b"foo";
252 let msg_id = 0xABu8;
253 let aux_tags: &[u8] = &[0x01, 0x02];
254 let aux_byte = ((aux_tags.len() as u8) & 0x07) << 5;
255 let fut_ext: &[u8] = &[0x25, 0x89, 0x63, 0x21, 0x47];
256 let fut_byte = fut_ext.len() as u8 & 0x1F;
257
258 let mut sel = vec![num_pre];
259 sel.push(pre0_a);
260 sel.push(pre0_b);
261 sel.push(pre1_a);
262 sel.push(pre1_b);
263 sel.extend_from_slice(lang);
264 sel.push(msg_id);
265 sel.push(aux_byte);
266 sel.extend_from_slice(aux_tags);
267 sel.push(fut_byte);
268 sel.extend_from_slice(fut_ext);
269
270 let bytes = wrap(0x19, &sel);
271 let d = ExtensionDescriptor::parse(&bytes).unwrap();
272 match &d.body {
273 ExtensionBody::AudioPreselection(b) => {
274 assert_eq!(b.preselections.len(), 2);
275
276 let p0 = &b.preselections[0];
277 assert_eq!(p0.preselection_id, 1);
278 assert_eq!(p0.audio_rendering_indication, 2);
279 assert!(!p0.audio_description);
280 assert!(p0.spoken_subtitles);
281 assert!(!p0.dialogue_enhancement);
282 assert!(p0.interactivity_enabled);
283 assert_eq!(p0.language_code, None);
284 assert_eq!(p0.message_id, None);
285 assert_eq!(p0.aux_component_tags, None);
286 assert_eq!(p0.future_extension, None);
287
288 let p1 = &b.preselections[1];
289 assert_eq!(p1.preselection_id, 2);
290 assert_eq!(p1.audio_rendering_indication, 3);
291 assert!(p1.audio_description);
292 assert!(!p1.spoken_subtitles);
293 assert!(p1.dialogue_enhancement);
294 assert!(!p1.interactivity_enabled);
295 assert_eq!(p1.language_code, Some(LangCode(*b"foo")));
296 assert_eq!(p1.message_id, Some(0xAB));
297 assert_eq!(p1.aux_component_tags, Some(aux_tags as &[u8]));
298 assert_eq!(p1.future_extension, Some(fut_ext as &[u8]));
299 }
300 other => panic!("expected AudioPreselection, got {other:?}"),
301 }
302 round_trip(&d);
303 }
304
305 #[test]
306 fn tsduck_byte_exact_test_015() {
307 let hex = "7f1319100a5013af666f6fab400102052589632147";
311 let bytes = from_hex(hex);
312 let d = ExtensionDescriptor::parse(&bytes).unwrap_or_else(|e| panic!("parse {hex}: {e:?}"));
313 assert_eq!(
314 d.kind(),
315 Some(super::super::ExtensionTag::AudioPreselection)
316 );
317 match &d.body {
318 ExtensionBody::AudioPreselection(b) => {
319 assert_eq!(b.preselections.len(), 2);
320
321 let p0 = &b.preselections[0];
322 assert_eq!(p0.preselection_id, 1);
323 assert_eq!(p0.audio_rendering_indication, 2);
324 assert!(!p0.audio_description);
325 assert!(p0.spoken_subtitles);
326 assert!(!p0.dialogue_enhancement);
327 assert!(p0.interactivity_enabled);
328 assert_eq!(p0.language_code, None);
329 assert_eq!(p0.message_id, None);
330 assert_eq!(p0.aux_component_tags, None);
331 assert_eq!(p0.future_extension, None);
332
333 let p1 = &b.preselections[1];
334 assert_eq!(p1.preselection_id, 2);
335 assert_eq!(p1.audio_rendering_indication, 3);
336 assert!(p1.audio_description);
337 assert!(!p1.spoken_subtitles);
338 assert!(p1.dialogue_enhancement);
339 assert!(!p1.interactivity_enabled);
340 assert_eq!(p1.language_code, Some(LangCode(*b"foo")));
341 assert_eq!(p1.message_id, Some(0xAB));
342 assert_eq!(p1.aux_component_tags, Some(&[0x01u8, 0x02u8][..]));
343 assert_eq!(
344 p1.future_extension,
345 Some(&[0x25u8, 0x89, 0x63, 0x21, 0x47][..])
346 );
347 }
348 other => panic!("expected AudioPreselection, got {other:?}"),
349 }
350 round_trip(&d);
351 }
352}