Skip to main content

dvb_si/descriptors/
metadata.rs

1//! Metadata Descriptor — ISO/IEC 13818-1 §2.6.60, Table 2-89 (tag 0x26).
2//!
3//! Carries metadata for a program or elementary stream. The DSM-CC block is
4//! conditional on `DSM-CC_flag`; the decoder-config block is one of several
5//! variants selected by `decoder_config_flags` (001/011/100/101|110).
6
7use super::descriptor_body;
8use crate::descriptors::decoder_config_flags::DecoderConfigFlags;
9use crate::descriptors::metadata_format::MetadataFormat;
10use crate::error::{Error, Result};
11use dvb_common::{Parse, Serialize};
12
13/// Descriptor tag for metadata_descriptor.
14pub const TAG: u8 = 0x26;
15const HEADER_LEN: usize = 2;
16
17/// Decoder configuration carried in this descriptor (decoder_config_flags == 0b001).
18#[derive(Debug, Clone, PartialEq, Eq)]
19#[cfg_attr(feature = "serde", derive(serde::Serialize))]
20pub struct DecoderConfigInDescriptor<'a> {
21    /// Opaque decoder config bytes.
22    #[cfg_attr(feature = "serde", serde(borrow))]
23    pub decoder_config: &'a [u8],
24}
25
26/// Decoder configuration carried in a DSM-CC carousel (decoder_config_flags == 0b011).
27#[derive(Debug, Clone, PartialEq, Eq)]
28#[cfg_attr(feature = "serde", derive(serde::Serialize))]
29pub struct DecoderConfigDsmcc<'a> {
30    /// Opaque dec_config_identification_record bytes.
31    #[cfg_attr(feature = "serde", serde(borrow))]
32    pub dec_config_identification: &'a [u8],
33}
34
35/// Decoder configuration carried in another metadata service (decoder_config_flags == 0b100).
36#[derive(Debug, Clone, PartialEq, Eq)]
37#[cfg_attr(feature = "serde", derive(serde::Serialize))]
38pub struct DecoderConfigOtherService {
39    /// Decoder config metadata service ID.
40    pub decoder_config_metadata_service_id: u8,
41}
42
43/// Reserved data block (decoder_config_flags == 0b101 or 0b110).
44#[derive(Debug, Clone, PartialEq, Eq)]
45#[cfg_attr(feature = "serde", derive(serde::Serialize))]
46pub struct ReservedData<'a> {
47    /// Opaque reserved data bytes.
48    #[cfg_attr(feature = "serde", serde(borrow))]
49    pub data: &'a [u8],
50}
51
52/// All decoder-config variants, selected by decoder_config_flags.
53#[derive(Debug, Clone, PartialEq, Eq)]
54#[cfg_attr(feature = "serde", derive(serde::Serialize))]
55#[non_exhaustive]
56pub enum DecoderConfig<'a> {
57    /// No decoder config needed (0b000).
58    None,
59    /// Carried in this descriptor (0b001).
60    InDescriptor(DecoderConfigInDescriptor<'a>),
61    /// Carried in same metadata service (0b010, no data).
62    SameService,
63    /// Carried in DSM-CC carousel (0b011).
64    DsmccCarousel(DecoderConfigDsmcc<'a>),
65    /// Carried in another metadata service (0b100).
66    OtherService(DecoderConfigOtherService),
67    /// Reserved data (0b101|0b110).
68    ReservedData(ReservedData<'a>),
69    /// Privately defined (0b111, no data).
70    Private,
71}
72
73/// Metadata Descriptor.
74#[derive(Debug, Clone, PartialEq, Eq)]
75#[cfg_attr(feature = "serde", derive(serde::Serialize))]
76#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
77pub struct MetadataDescriptor<'a> {
78    /// Metadata application format (u16; Table 2-84).
79    pub metadata_application_format: u16,
80    /// Metadata application format identifier — present when `metadata_application_format == 0xFFFF`.
81    pub metadata_application_format_identifier: Option<u32>,
82    /// Metadata format (Table 2-87).
83    pub metadata_format: MetadataFormat,
84    /// Metadata format identifier — present when `metadata_format == 0xFF`.
85    pub metadata_format_identifier: Option<u32>,
86    /// Metadata service ID.
87    pub metadata_service_id: u8,
88    /// Decoder config flags (Table 2-90, 3-bit).
89    pub decoder_config_flags: DecoderConfigFlags,
90    /// DSM-CC service identification flag.
91    pub dsmcc_flag: bool,
92    /// DSM-CC service identification — present when `dsmcc_flag` is true.
93    #[cfg_attr(feature = "serde", serde(borrow))]
94    pub service_identification: Option<&'a [u8]>,
95    /// Decoder configuration block.
96    pub decoder_config: DecoderConfig<'a>,
97    /// Trailing private data bytes.
98    #[cfg_attr(feature = "serde", serde(borrow))]
99    pub private_data: &'a [u8],
100}
101
102impl<'a> Parse<'a> for MetadataDescriptor<'a> {
103    type Error = crate::error::Error;
104
105    fn parse(bytes: &'a [u8]) -> Result<Self> {
106        let body = descriptor_body(
107            bytes,
108            TAG,
109            "MetadataDescriptor",
110            "unexpected tag for metadata_descriptor",
111        )?;
112
113        // Minimum: metadata_application_format(2) + metadata_format(1) + metadata_service_id(1) + flags(1) = 5
114        if body.len() < 5 {
115            return Err(Error::InvalidDescriptor {
116                tag: TAG,
117                reason: "metadata_descriptor too short (< 5 body bytes)",
118            });
119        }
120
121        let metadata_application_format = u16::from_be_bytes([body[0], body[1]]);
122        let mut pos = 2;
123
124        let metadata_application_format_identifier = if metadata_application_format == 0xFFFF {
125            if body.len() < pos + 4 {
126                return Err(Error::InvalidDescriptor {
127                    tag: TAG,
128                    reason:
129                        "metadata_descriptor too short for metadata_application_format_identifier",
130                });
131            }
132            let id = u32::from_be_bytes([body[pos], body[pos + 1], body[pos + 2], body[pos + 3]]);
133            pos += 4;
134            Some(id)
135        } else {
136            None
137        };
138
139        if body.len() < pos + 1 {
140            return Err(Error::InvalidDescriptor {
141                tag: TAG,
142                reason: "metadata_descriptor too short for metadata_format",
143            });
144        }
145        let metadata_format = MetadataFormat::from_u8(body[pos]);
146        pos += 1;
147
148        let metadata_format_identifier = if body[pos - 1] == 0xFF {
149            if body.len() < pos + 4 {
150                return Err(Error::InvalidDescriptor {
151                    tag: TAG,
152                    reason: "metadata_descriptor too short for metadata_format_identifier",
153                });
154            }
155            let id = u32::from_be_bytes([body[pos], body[pos + 1], body[pos + 2], body[pos + 3]]);
156            pos += 4;
157            Some(id)
158        } else {
159            None
160        };
161
162        if body.len() < pos + 2 {
163            return Err(Error::InvalidDescriptor {
164                tag: TAG,
165                reason: "metadata_descriptor too short for service_id + flags",
166            });
167        }
168        let metadata_service_id = body[pos];
169        pos += 1;
170
171        let flags = body[pos];
172        let decoder_config_raw = (flags & 0xE0) >> 5;
173        let decoder_config_flags = DecoderConfigFlags::from_u8(decoder_config_raw);
174        let dsmcc_flag = (flags & 0x10) != 0;
175        let _reserved = flags & 0x0F;
176        pos += 1;
177
178        let (service_identification, mut pos) = if dsmcc_flag {
179            if body.len() < pos + 1 {
180                return Err(Error::InvalidDescriptor {
181                    tag: TAG,
182                    reason: "metadata_descriptor too short for service_identification_length",
183                });
184            }
185            let si_len = body[pos] as usize;
186            pos += 1;
187            if body.len() < pos + si_len {
188                return Err(Error::InvalidDescriptor {
189                    tag: TAG,
190                    reason: "metadata_descriptor too short for service_identification_record",
191                });
192            }
193            let si = &body[pos..pos + si_len];
194            pos += si_len;
195            (Some(si), pos)
196        } else {
197            (None, pos)
198        };
199
200        let decoder_config = match decoder_config_raw {
201            0 => DecoderConfig::None,
202            1 => {
203                if body.len() < pos + 1 {
204                    return Err(Error::InvalidDescriptor {
205                        tag: TAG,
206                        reason: "metadata_descriptor too short for decoder_config_length",
207                    });
208                }
209                let dc_len = body[pos] as usize;
210                pos += 1;
211                if body.len() < pos + dc_len {
212                    return Err(Error::InvalidDescriptor {
213                        tag: TAG,
214                        reason: "metadata_descriptor too short for decoder_config bytes",
215                    });
216                }
217                let dc = &body[pos..pos + dc_len];
218                pos += dc_len;
219                DecoderConfig::InDescriptor(DecoderConfigInDescriptor { decoder_config: dc })
220            }
221            2 => DecoderConfig::SameService,
222            3 => {
223                if body.len() < pos + 1 {
224                    return Err(Error::InvalidDescriptor {
225                        tag: TAG,
226                        reason: "metadata_descriptor too short for dec_config_identification_record_length",
227                    });
228                }
229                let dci_len = body[pos] as usize;
230                pos += 1;
231                if body.len() < pos + dci_len {
232                    return Err(Error::InvalidDescriptor {
233                        tag: TAG,
234                        reason:
235                            "metadata_descriptor too short for dec_config_identification_record",
236                    });
237                }
238                let dci = &body[pos..pos + dci_len];
239                pos += dci_len;
240                DecoderConfig::DsmccCarousel(DecoderConfigDsmcc {
241                    dec_config_identification: dci,
242                })
243            }
244            4 => {
245                if body.len() < pos + 1 {
246                    return Err(Error::InvalidDescriptor {
247                        tag: TAG,
248                        reason:
249                            "metadata_descriptor too short for decoder_config_metadata_service_id",
250                    });
251                }
252                let dcm = body[pos];
253                pos += 1;
254                DecoderConfig::OtherService(DecoderConfigOtherService {
255                    decoder_config_metadata_service_id: dcm,
256                })
257            }
258            5 | 6 => {
259                if body.len() < pos + 1 {
260                    return Err(Error::InvalidDescriptor {
261                        tag: TAG,
262                        reason: "metadata_descriptor too short for reserved_data_length",
263                    });
264                }
265                let rd_len = body[pos] as usize;
266                pos += 1;
267                if body.len() < pos + rd_len {
268                    return Err(Error::InvalidDescriptor {
269                        tag: TAG,
270                        reason: "metadata_descriptor too short for reserved_data",
271                    });
272                }
273                let rd = &body[pos..pos + rd_len];
274                pos += rd_len;
275                DecoderConfig::ReservedData(ReservedData { data: rd })
276            }
277            _ => DecoderConfig::Private,
278        };
279
280        let private_data = &body[pos..];
281
282        Ok(Self {
283            metadata_application_format,
284            metadata_application_format_identifier,
285            metadata_format,
286            metadata_format_identifier,
287            metadata_service_id,
288            decoder_config_flags,
289            dsmcc_flag,
290            service_identification,
291            decoder_config,
292            private_data,
293        })
294    }
295}
296
297impl Serialize for MetadataDescriptor<'_> {
298    type Error = crate::error::Error;
299
300    fn serialized_len(&self) -> usize {
301        let mut len: usize = HEADER_LEN + 5; // metadata_application_format(2) + metadata_format(1) + service_id(1) + flags(1)
302        if self.metadata_application_format_identifier.is_some() {
303            len += 4;
304        }
305        if self.metadata_format_identifier.is_some() {
306            len += 4;
307        }
308        if let Some(si) = self.service_identification {
309            len += 1 + si.len();
310        }
311        match &self.decoder_config {
312            DecoderConfig::InDescriptor(d) => len += 1 + d.decoder_config.len(),
313            DecoderConfig::DsmccCarousel(d) => len += 1 + d.dec_config_identification.len(),
314            DecoderConfig::OtherService(_) => len += 1,
315            DecoderConfig::ReservedData(d) => len += 1 + d.data.len(),
316            DecoderConfig::None | DecoderConfig::SameService | DecoderConfig::Private => {}
317        }
318        len += self.private_data.len();
319        len
320    }
321
322    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
323        let len = self.serialized_len();
324        if buf.len() < len {
325            return Err(Error::OutputBufferTooSmall {
326                need: len,
327                have: buf.len(),
328            });
329        }
330        buf[0] = TAG;
331        buf[1] = (len - HEADER_LEN) as u8;
332
333        buf[HEADER_LEN] = (self.metadata_application_format >> 8) as u8;
334        buf[HEADER_LEN + 1] = self.metadata_application_format as u8;
335        let mut pos = HEADER_LEN + 2;
336
337        if let Some(id) = self.metadata_application_format_identifier {
338            buf[pos..pos + 4].copy_from_slice(&id.to_be_bytes());
339            pos += 4;
340        }
341
342        buf[pos] = self.metadata_format.to_u8();
343        pos += 1;
344
345        if let Some(id) = self.metadata_format_identifier {
346            buf[pos..pos + 4].copy_from_slice(&id.to_be_bytes());
347            pos += 4;
348        }
349
350        buf[pos] = self.metadata_service_id;
351        pos += 1;
352
353        let mut flags = (self.decoder_config_flags.to_u8() & 0x07) << 5;
354        if self.dsmcc_flag {
355            flags |= 0x10;
356        }
357        buf[pos] = flags;
358        pos += 1;
359
360        if let Some(si) = self.service_identification {
361            buf[pos] = si.len() as u8;
362            pos += 1;
363            buf[pos..pos + si.len()].copy_from_slice(si);
364            pos += si.len();
365        }
366
367        match &self.decoder_config {
368            DecoderConfig::InDescriptor(d) => {
369                buf[pos] = d.decoder_config.len() as u8;
370                pos += 1;
371                buf[pos..pos + d.decoder_config.len()].copy_from_slice(d.decoder_config);
372                pos += d.decoder_config.len();
373            }
374            DecoderConfig::DsmccCarousel(d) => {
375                buf[pos] = d.dec_config_identification.len() as u8;
376                pos += 1;
377                buf[pos..pos + d.dec_config_identification.len()]
378                    .copy_from_slice(d.dec_config_identification);
379                pos += d.dec_config_identification.len();
380            }
381            DecoderConfig::OtherService(d) => {
382                buf[pos] = d.decoder_config_metadata_service_id;
383                pos += 1;
384            }
385            DecoderConfig::ReservedData(d) => {
386                buf[pos] = d.data.len() as u8;
387                pos += 1;
388                buf[pos..pos + d.data.len()].copy_from_slice(d.data);
389                pos += d.data.len();
390            }
391            DecoderConfig::None | DecoderConfig::SameService | DecoderConfig::Private => {}
392        }
393
394        buf[pos..pos + self.private_data.len()].copy_from_slice(self.private_data);
395        Ok(len)
396    }
397}
398
399impl<'a> crate::traits::DescriptorDef<'a> for MetadataDescriptor<'a> {
400    const TAG: u8 = TAG;
401    const NAME: &'static str = "METADATA";
402}
403
404#[cfg(test)]
405mod tests {
406    use super::*;
407
408    fn serialize_round_trip(d: &MetadataDescriptor<'_>) {
409        let mut buf = vec![0u8; d.serialized_len()];
410        let written = d.serialize_into(&mut buf).unwrap();
411        assert_eq!(written, d.serialized_len());
412        let reparsed = MetadataDescriptor::parse(&buf).unwrap();
413        assert_eq!(*d, reparsed, "round-trip mismatch");
414    }
415
416    #[test]
417    fn round_trip_decoder_config_none() {
418        let d = MetadataDescriptor {
419            metadata_application_format: 0x0010,
420            metadata_application_format_identifier: None,
421            metadata_format: MetadataFormat::TeM,
422            metadata_format_identifier: None,
423            metadata_service_id: 5,
424            decoder_config_flags: DecoderConfigFlags::None,
425            dsmcc_flag: false,
426            service_identification: None,
427            decoder_config: DecoderConfig::None,
428            private_data: &[],
429        };
430        serialize_round_trip(&d);
431    }
432
433    #[test]
434    fn round_trip_decoder_config_in_descriptor() {
435        let d = MetadataDescriptor {
436            metadata_application_format: 0x0011,
437            metadata_application_format_identifier: None,
438            metadata_format: MetadataFormat::BiM,
439            metadata_format_identifier: None,
440            metadata_service_id: 3,
441            decoder_config_flags: DecoderConfigFlags::InDescriptor,
442            dsmcc_flag: false,
443            service_identification: None,
444            decoder_config: DecoderConfig::InDescriptor(DecoderConfigInDescriptor {
445                decoder_config: &[0x01, 0x02, 0x03],
446            }),
447            private_data: &[0xFF],
448        };
449        serialize_round_trip(&d);
450    }
451
452    #[test]
453    fn round_trip_decoder_config_same_service() {
454        let d = MetadataDescriptor {
455            metadata_application_format: 0x0100,
456            metadata_application_format_identifier: None,
457            metadata_format: MetadataFormat::AppFormat,
458            metadata_format_identifier: None,
459            metadata_service_id: 1,
460            decoder_config_flags: DecoderConfigFlags::SameService,
461            dsmcc_flag: true,
462            service_identification: Some(&[0xAA, 0xBB]),
463            decoder_config: DecoderConfig::SameService,
464            private_data: &[],
465        };
466        serialize_round_trip(&d);
467    }
468
469    #[test]
470    fn round_trip_decoder_config_dsmcc() {
471        let d = MetadataDescriptor {
472            metadata_application_format: 0x0010,
473            metadata_application_format_identifier: None,
474            metadata_format: MetadataFormat::Reserved1(0x30),
475            metadata_format_identifier: None,
476            metadata_service_id: 7,
477            decoder_config_flags: DecoderConfigFlags::DsmccCarousel,
478            dsmcc_flag: false,
479            service_identification: None,
480            decoder_config: DecoderConfig::DsmccCarousel(DecoderConfigDsmcc {
481                dec_config_identification: &[0x11, 0x22, 0x33, 0x44],
482            }),
483            private_data: &[],
484        };
485        serialize_round_trip(&d);
486    }
487
488    #[test]
489    fn round_trip_decoder_config_other_service() {
490        let d = MetadataDescriptor {
491            metadata_application_format: 0x0010,
492            metadata_application_format_identifier: None,
493            metadata_format: MetadataFormat::Private(0x50),
494            metadata_format_identifier: None,
495            metadata_service_id: 2,
496            decoder_config_flags: DecoderConfigFlags::OtherService,
497            dsmcc_flag: false,
498            service_identification: None,
499            decoder_config: DecoderConfig::OtherService(DecoderConfigOtherService {
500                decoder_config_metadata_service_id: 99,
501            }),
502            private_data: &[],
503        };
504        serialize_round_trip(&d);
505    }
506
507    #[test]
508    fn round_trip_decoder_config_reserved_data() {
509        let d = MetadataDescriptor {
510            metadata_application_format: 0x0010,
511            metadata_application_format_identifier: None,
512            metadata_format: MetadataFormat::Identifier,
513            metadata_format_identifier: Some(0xDEADBEEF),
514            metadata_service_id: 4,
515            decoder_config_flags: DecoderConfigFlags::Reserved(5),
516            dsmcc_flag: false,
517            service_identification: None,
518            decoder_config: DecoderConfig::ReservedData(ReservedData {
519                data: &[0x99, 0x88, 0x77],
520            }),
521            private_data: &[],
522        };
523        serialize_round_trip(&d);
524    }
525
526    #[test]
527    fn round_trip_decoder_config_private() {
528        let d = MetadataDescriptor {
529            metadata_application_format: 0x0010,
530            metadata_application_format_identifier: None,
531            metadata_format: MetadataFormat::TeM,
532            metadata_format_identifier: None,
533            metadata_service_id: 6,
534            decoder_config_flags: DecoderConfigFlags::Private,
535            dsmcc_flag: false,
536            service_identification: None,
537            decoder_config: DecoderConfig::Private,
538            private_data: &[0x01],
539        };
540        serialize_round_trip(&d);
541    }
542
543    #[test]
544    fn round_trip_with_ffff_and_ff() {
545        let d = MetadataDescriptor {
546            metadata_application_format: 0xFFFF,
547            metadata_application_format_identifier: Some(0x11223344),
548            metadata_format: MetadataFormat::Identifier,
549            metadata_format_identifier: Some(0x55667788),
550            metadata_service_id: 8,
551            decoder_config_flags: DecoderConfigFlags::None,
552            dsmcc_flag: true,
553            service_identification: Some(&[0xCA, 0xFE]),
554            decoder_config: DecoderConfig::None,
555            private_data: &[],
556        };
557        serialize_round_trip(&d);
558    }
559
560    #[test]
561    fn parse_rejects_wrong_tag() {
562        let err = MetadataDescriptor::parse(&[0x02, 5, 0, 0, 0, 0, 0]).unwrap_err();
563        assert!(matches!(err, Error::InvalidDescriptor { tag: 0x02, .. }));
564    }
565
566    #[test]
567    fn parse_rejects_too_short() {
568        let err = MetadataDescriptor::parse(&[TAG, 0]).unwrap_err();
569        assert!(matches!(err, Error::InvalidDescriptor { tag: TAG, .. }));
570    }
571}