Skip to main content

dvb_si/descriptors/
time_slice_fec_identifier.rs

1//! Time Slice and FEC Identifier Descriptor — ETSI EN 301 192 §9.5 Table 40 /
2//! ETSI TS 102 772 §6.2 Table 4 (tag 0x77).
3//!
4//! Carried in the INT / PMT to describe DVB-H time-slicing and MPE-FEC for an
5//! elementary stream. Per en_301_192.md "Table 40" (PDF p. 53) and
6//! ts_102_772_mpe_ifec.md "Table 4 — Time Slice and FEC identifier descriptor"
7//! (PDF p. 19) the fixed 3-byte head is:
8//!   byte0: time_slicing(1) + mpe_fec(2) + reserved_for_future_use(2) + frame_size(3)
9//!   byte1: max_burst_duration(8)
10//!   byte2: max_average_rate(4) + time_slice_fec_id(4)
11//! followed by `id_selector_byte` for the remainder of the descriptor.
12
13use super::descriptor_body;
14use crate::error::{Error, Result};
15use dvb_common::{Parse, Serialize};
16
17/// Descriptor tag for time_slice_fec_identifier_descriptor.
18pub const TAG: u8 = 0x77;
19const HEADER_LEN: usize = 2;
20const FIXED_LEN: usize = 3;
21
22/// Largest representable 2-bit mpe_fec.
23const MPE_FEC_MAX: u8 = 0x03;
24/// Largest representable 3-bit frame_size.
25const FRAME_SIZE_MAX: u8 = 0x07;
26/// Largest representable 4-bit max_average_rate.
27const MAX_AVERAGE_RATE_MAX: u8 = 0x0F;
28/// Largest representable 4-bit time_slice_fec_id.
29const TIME_SLICE_FEC_ID_MAX: u8 = 0x0F;
30
31/// Time Slice and FEC Identifier Descriptor.
32#[derive(Debug, Clone, PartialEq, Eq)]
33#[cfg_attr(feature = "serde", derive(serde::Serialize))]
34#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
35pub struct TimeSliceFecIdentifierDescriptor<'a> {
36    /// 1-bit time_slicing flag (1 = time slicing used).
37    pub time_slicing: bool,
38    /// 2-bit mpe_fec algorithm selector (Table 41: 0=none, 1=RS(255,191,64)).
39    pub mpe_fec: u8,
40    /// 3-bit frame_size code (Table 42).
41    pub frame_size: u8,
42    /// 8-bit max_burst_duration.
43    pub max_burst_duration: u8,
44    /// 4-bit max_average_rate code (Table 43).
45    pub max_average_rate: u8,
46    /// 4-bit time_slice_fec_id.
47    pub time_slice_fec_id: u8,
48    /// Trailing id_selector bytes.
49    /// Kept raw deliberately; interpretation is registry-dependent per
50    /// EN 301 192 / TS 102 772.
51    pub id_selector: &'a [u8],
52}
53
54impl<'a> Parse<'a> for TimeSliceFecIdentifierDescriptor<'a> {
55    type Error = crate::error::Error;
56    fn parse(bytes: &'a [u8]) -> Result<Self> {
57        let body = descriptor_body(
58            bytes,
59            TAG,
60            "TimeSliceFecIdentifierDescriptor",
61            "unexpected tag for time_slice_fec_identifier_descriptor",
62        )?;
63        if body.len() < FIXED_LEN {
64            return Err(Error::InvalidDescriptor {
65                tag: TAG,
66                reason: "time_slice_fec_identifier_descriptor body shorter than 3 bytes",
67            });
68        }
69        let b0 = body[0];
70        let time_slicing = (b0 & 0x80) != 0;
71        let mpe_fec = (b0 >> 5) & MPE_FEC_MAX;
72        // reserved_for_future_use(2) at bits 4..3 ignored on parse.
73        let frame_size = b0 & FRAME_SIZE_MAX;
74        let max_burst_duration = body[1];
75        let max_average_rate = (body[2] >> 4) & MAX_AVERAGE_RATE_MAX;
76        let time_slice_fec_id = body[2] & TIME_SLICE_FEC_ID_MAX;
77        let id_selector = &body[FIXED_LEN..];
78        Ok(Self {
79            time_slicing,
80            mpe_fec,
81            frame_size,
82            max_burst_duration,
83            max_average_rate,
84            time_slice_fec_id,
85            id_selector,
86        })
87    }
88}
89
90impl Serialize for TimeSliceFecIdentifierDescriptor<'_> {
91    type Error = crate::error::Error;
92    fn serialized_len(&self) -> usize {
93        HEADER_LEN + FIXED_LEN + self.id_selector.len()
94    }
95
96    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
97        if self.mpe_fec > MPE_FEC_MAX {
98            return Err(Error::InvalidDescriptor {
99                tag: TAG,
100                reason: "mpe_fec exceeds 2 bits",
101            });
102        }
103        if self.frame_size > FRAME_SIZE_MAX {
104            return Err(Error::InvalidDescriptor {
105                tag: TAG,
106                reason: "frame_size exceeds 3 bits",
107            });
108        }
109        if self.max_average_rate > MAX_AVERAGE_RATE_MAX {
110            return Err(Error::InvalidDescriptor {
111                tag: TAG,
112                reason: "max_average_rate exceeds 4 bits",
113            });
114        }
115        if self.time_slice_fec_id > TIME_SLICE_FEC_ID_MAX {
116            return Err(Error::InvalidDescriptor {
117                tag: TAG,
118                reason: "time_slice_fec_id exceeds 4 bits",
119            });
120        }
121        if FIXED_LEN + self.id_selector.len() > u8::MAX as usize {
122            return Err(Error::InvalidDescriptor {
123                tag: TAG,
124                reason: "time_slice_fec_identifier_descriptor body exceeds 255 bytes",
125            });
126        }
127        let len = self.serialized_len();
128        if buf.len() < len {
129            return Err(Error::OutputBufferTooSmall {
130                need: len,
131                have: buf.len(),
132            });
133        }
134        buf[0] = TAG;
135        buf[1] = (FIXED_LEN + self.id_selector.len()) as u8;
136        // reserved_for_future_use(2) emitted as 1s.
137        buf[2] = (u8::from(self.time_slicing) << 7)
138            | ((self.mpe_fec & MPE_FEC_MAX) << 5)
139            | 0x18
140            | (self.frame_size & FRAME_SIZE_MAX);
141        buf[3] = self.max_burst_duration;
142        buf[4] = ((self.max_average_rate & MAX_AVERAGE_RATE_MAX) << 4)
143            | (self.time_slice_fec_id & TIME_SLICE_FEC_ID_MAX);
144        buf[HEADER_LEN + FIXED_LEN..len].copy_from_slice(self.id_selector);
145        Ok(len)
146    }
147}
148impl<'a> crate::traits::DescriptorDef<'a> for TimeSliceFecIdentifierDescriptor<'a> {
149    const TAG: u8 = TAG;
150    const NAME: &'static str = "TIME_SLICE_FEC_IDENTIFIER";
151}
152
153#[cfg(test)]
154mod tests {
155    use super::*;
156
157    #[test]
158    fn parse_no_id_selector() {
159        // time_slicing=1, mpe_fec=1, frame_size=3, reserved=11, burst=0x2A,
160        // max_average_rate=5, time_slice_fec_id=0xA.
161        let b0 = 0x80 | (1 << 5) | 0x18 | 0x03;
162        let bytes = [TAG, 3, b0, 0x2A, (5 << 4) | 0x0A];
163        let d = TimeSliceFecIdentifierDescriptor::parse(&bytes).unwrap();
164        assert!(d.time_slicing);
165        assert_eq!(d.mpe_fec, 1);
166        assert_eq!(d.frame_size, 3);
167        assert_eq!(d.max_burst_duration, 0x2A);
168        assert_eq!(d.max_average_rate, 5);
169        assert_eq!(d.time_slice_fec_id, 0xA);
170        assert!(d.id_selector.is_empty());
171    }
172
173    #[test]
174    fn parse_with_id_selector() {
175        let bytes = [TAG, 5, 0x00, 0x00, 0x00, 0xAA, 0xBB];
176        let d = TimeSliceFecIdentifierDescriptor::parse(&bytes).unwrap();
177        assert!(!d.time_slicing);
178        assert_eq!(d.id_selector, &[0xAA, 0xBB]);
179    }
180
181    #[test]
182    fn parse_rejects_wrong_tag() {
183        assert!(matches!(
184            TimeSliceFecIdentifierDescriptor::parse(&[0x78, 3, 0, 0, 0]).unwrap_err(),
185            Error::InvalidDescriptor { tag: 0x78, .. }
186        ));
187    }
188
189    #[test]
190    fn parse_rejects_body_too_short() {
191        let bytes = [TAG, 2, 0, 0];
192        assert!(matches!(
193            TimeSliceFecIdentifierDescriptor::parse(&bytes).unwrap_err(),
194            Error::InvalidDescriptor { .. }
195        ));
196    }
197
198    #[test]
199    fn parse_rejects_length_overrunning_buffer() {
200        let bytes = [TAG, 5, 0, 0, 0];
201        assert!(matches!(
202            TimeSliceFecIdentifierDescriptor::parse(&bytes).unwrap_err(),
203            Error::BufferTooShort { .. }
204        ));
205    }
206
207    #[test]
208    fn serialize_round_trip() {
209        let d = TimeSliceFecIdentifierDescriptor {
210            time_slicing: true,
211            mpe_fec: 1,
212            frame_size: 2,
213            max_burst_duration: 0x10,
214            max_average_rate: 6,
215            time_slice_fec_id: 0,
216            id_selector: &[0x01, 0x02, 0x03],
217        };
218        let mut buf = vec![0u8; d.serialized_len()];
219        d.serialize_into(&mut buf).unwrap();
220        assert_eq!(TimeSliceFecIdentifierDescriptor::parse(&buf).unwrap(), d);
221    }
222
223    #[test]
224    fn serialize_rejects_frame_size_over_range() {
225        let d = TimeSliceFecIdentifierDescriptor {
226            time_slicing: false,
227            mpe_fec: 0,
228            frame_size: 0x08,
229            max_burst_duration: 0,
230            max_average_rate: 0,
231            time_slice_fec_id: 0,
232            id_selector: &[],
233        };
234        let mut buf = vec![0u8; d.serialized_len()];
235        assert!(matches!(
236            d.serialize_into(&mut buf).unwrap_err(),
237            Error::InvalidDescriptor { .. }
238        ));
239    }
240
241    #[cfg(feature = "serde")]
242    #[test]
243    fn serde_serializes_to_stable_json() {
244        // Borrowed `&[u8]` cannot deserialize from a JSON number array, so we
245        // assert the Serialize impl is wired and emits stable JSON.
246        let d = TimeSliceFecIdentifierDescriptor {
247            time_slicing: true,
248            mpe_fec: 1,
249            frame_size: 3,
250            max_burst_duration: 0x44,
251            max_average_rate: 7,
252            time_slice_fec_id: 0xF,
253            id_selector: &[0xDE, 0xAD],
254        };
255        let j = serde_json::to_string(&d).unwrap();
256        // Valid, re-parseable JSON (key order is map-defined, so we do not
257        // assert byte-for-byte string stability).
258        let _v: serde_json::Value = serde_json::from_str(&j).unwrap();
259        assert!(j.contains("time_slice_fec_id"));
260    }
261}