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 crate::error::{Error, Result};
14use crate::traits::Descriptor;
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, serde::Deserialize))]
34pub struct TimeSliceFecIdentifierDescriptor<'a> {
35    /// 1-bit time_slicing flag (1 = time slicing used).
36    pub time_slicing: bool,
37    /// 2-bit mpe_fec algorithm selector (Table 41: 0=none, 1=RS(255,191,64)).
38    pub mpe_fec: u8,
39    /// 3-bit frame_size code (Table 42).
40    pub frame_size: u8,
41    /// 8-bit max_burst_duration.
42    pub max_burst_duration: u8,
43    /// 4-bit max_average_rate code (Table 43).
44    pub max_average_rate: u8,
45    /// 4-bit time_slice_fec_id.
46    pub time_slice_fec_id: u8,
47    /// Trailing id_selector bytes.
48    #[cfg_attr(feature = "serde", serde(borrow))]
49    pub id_selector: &'a [u8],
50}
51
52impl<'a> Parse<'a> for TimeSliceFecIdentifierDescriptor<'a> {
53    type Error = crate::error::Error;
54    fn parse(bytes: &'a [u8]) -> Result<Self> {
55        if bytes.len() < HEADER_LEN {
56            return Err(Error::BufferTooShort {
57                need: HEADER_LEN,
58                have: bytes.len(),
59                what: "TimeSliceFecIdentifierDescriptor header",
60            });
61        }
62        if bytes[0] != TAG {
63            return Err(Error::InvalidDescriptor {
64                tag: bytes[0],
65                reason: "unexpected tag for time_slice_fec_identifier_descriptor",
66            });
67        }
68        let length = bytes[1] as usize;
69        let end = HEADER_LEN + length;
70        if bytes.len() < end {
71            return Err(Error::BufferTooShort {
72                need: end,
73                have: bytes.len(),
74                what: "TimeSliceFecIdentifierDescriptor body",
75            });
76        }
77        if length < FIXED_LEN {
78            return Err(Error::InvalidDescriptor {
79                tag: TAG,
80                reason: "time_slice_fec_identifier_descriptor body shorter than 3 bytes",
81            });
82        }
83        let body = &bytes[HEADER_LEN..end];
84        let b0 = body[0];
85        let time_slicing = (b0 & 0x80) != 0;
86        let mpe_fec = (b0 >> 5) & MPE_FEC_MAX;
87        // reserved_for_future_use(2) at bits 4..3 ignored on parse.
88        let frame_size = b0 & FRAME_SIZE_MAX;
89        let max_burst_duration = body[1];
90        let max_average_rate = (body[2] >> 4) & MAX_AVERAGE_RATE_MAX;
91        let time_slice_fec_id = body[2] & TIME_SLICE_FEC_ID_MAX;
92        let id_selector = &body[FIXED_LEN..];
93        Ok(Self {
94            time_slicing,
95            mpe_fec,
96            frame_size,
97            max_burst_duration,
98            max_average_rate,
99            time_slice_fec_id,
100            id_selector,
101        })
102    }
103}
104
105impl Serialize for TimeSliceFecIdentifierDescriptor<'_> {
106    type Error = crate::error::Error;
107    fn serialized_len(&self) -> usize {
108        HEADER_LEN + FIXED_LEN + self.id_selector.len()
109    }
110
111    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
112        if self.mpe_fec > MPE_FEC_MAX {
113            return Err(Error::InvalidDescriptor {
114                tag: TAG,
115                reason: "mpe_fec exceeds 2 bits",
116            });
117        }
118        if self.frame_size > FRAME_SIZE_MAX {
119            return Err(Error::InvalidDescriptor {
120                tag: TAG,
121                reason: "frame_size exceeds 3 bits",
122            });
123        }
124        if self.max_average_rate > MAX_AVERAGE_RATE_MAX {
125            return Err(Error::InvalidDescriptor {
126                tag: TAG,
127                reason: "max_average_rate exceeds 4 bits",
128            });
129        }
130        if self.time_slice_fec_id > TIME_SLICE_FEC_ID_MAX {
131            return Err(Error::InvalidDescriptor {
132                tag: TAG,
133                reason: "time_slice_fec_id exceeds 4 bits",
134            });
135        }
136        if FIXED_LEN + self.id_selector.len() > u8::MAX as usize {
137            return Err(Error::InvalidDescriptor {
138                tag: TAG,
139                reason: "time_slice_fec_identifier_descriptor body exceeds 255 bytes",
140            });
141        }
142        let len = self.serialized_len();
143        if buf.len() < len {
144            return Err(Error::OutputBufferTooSmall {
145                need: len,
146                have: buf.len(),
147            });
148        }
149        buf[0] = TAG;
150        buf[1] = (FIXED_LEN + self.id_selector.len()) as u8;
151        // reserved_for_future_use(2) emitted as 1s.
152        buf[2] = (u8::from(self.time_slicing) << 7)
153            | ((self.mpe_fec & MPE_FEC_MAX) << 5)
154            | 0x18
155            | (self.frame_size & FRAME_SIZE_MAX);
156        buf[3] = self.max_burst_duration;
157        buf[4] = ((self.max_average_rate & MAX_AVERAGE_RATE_MAX) << 4)
158            | (self.time_slice_fec_id & TIME_SLICE_FEC_ID_MAX);
159        buf[HEADER_LEN + FIXED_LEN..len].copy_from_slice(self.id_selector);
160        Ok(len)
161    }
162}
163
164impl<'a> Descriptor<'a> for TimeSliceFecIdentifierDescriptor<'a> {
165    const TAG: u8 = TAG;
166    fn descriptor_length(&self) -> u8 {
167        (FIXED_LEN + self.id_selector.len()) as u8
168    }
169}
170
171impl<'a> crate::traits::DescriptorDef<'a> for TimeSliceFecIdentifierDescriptor<'a> {
172    const TAG: u8 = TAG;
173    const NAME: &'static str = "TIME_SLICE_FEC_IDENTIFIER";
174}
175
176#[cfg(test)]
177mod tests {
178    use super::*;
179
180    #[test]
181    fn parse_no_id_selector() {
182        // time_slicing=1, mpe_fec=1, frame_size=3, reserved=11, burst=0x2A,
183        // max_average_rate=5, time_slice_fec_id=0xA.
184        let b0 = 0x80 | (1 << 5) | 0x18 | 0x03;
185        let bytes = [TAG, 3, b0, 0x2A, (5 << 4) | 0x0A];
186        let d = TimeSliceFecIdentifierDescriptor::parse(&bytes).unwrap();
187        assert!(d.time_slicing);
188        assert_eq!(d.mpe_fec, 1);
189        assert_eq!(d.frame_size, 3);
190        assert_eq!(d.max_burst_duration, 0x2A);
191        assert_eq!(d.max_average_rate, 5);
192        assert_eq!(d.time_slice_fec_id, 0xA);
193        assert!(d.id_selector.is_empty());
194    }
195
196    #[test]
197    fn parse_with_id_selector() {
198        let bytes = [TAG, 5, 0x00, 0x00, 0x00, 0xAA, 0xBB];
199        let d = TimeSliceFecIdentifierDescriptor::parse(&bytes).unwrap();
200        assert!(!d.time_slicing);
201        assert_eq!(d.id_selector, &[0xAA, 0xBB]);
202    }
203
204    #[test]
205    fn parse_rejects_wrong_tag() {
206        assert!(matches!(
207            TimeSliceFecIdentifierDescriptor::parse(&[0x78, 3, 0, 0, 0]).unwrap_err(),
208            Error::InvalidDescriptor { tag: 0x78, .. }
209        ));
210    }
211
212    #[test]
213    fn parse_rejects_body_too_short() {
214        let bytes = [TAG, 2, 0, 0];
215        assert!(matches!(
216            TimeSliceFecIdentifierDescriptor::parse(&bytes).unwrap_err(),
217            Error::InvalidDescriptor { .. }
218        ));
219    }
220
221    #[test]
222    fn parse_rejects_length_overrunning_buffer() {
223        let bytes = [TAG, 5, 0, 0, 0];
224        assert!(matches!(
225            TimeSliceFecIdentifierDescriptor::parse(&bytes).unwrap_err(),
226            Error::BufferTooShort { .. }
227        ));
228    }
229
230    #[test]
231    fn serialize_round_trip() {
232        let d = TimeSliceFecIdentifierDescriptor {
233            time_slicing: true,
234            mpe_fec: 1,
235            frame_size: 2,
236            max_burst_duration: 0x10,
237            max_average_rate: 6,
238            time_slice_fec_id: 0,
239            id_selector: &[0x01, 0x02, 0x03],
240        };
241        let mut buf = vec![0u8; d.serialized_len()];
242        d.serialize_into(&mut buf).unwrap();
243        assert_eq!(TimeSliceFecIdentifierDescriptor::parse(&buf).unwrap(), d);
244    }
245
246    #[test]
247    fn serialize_rejects_frame_size_over_range() {
248        let d = TimeSliceFecIdentifierDescriptor {
249            time_slicing: false,
250            mpe_fec: 0,
251            frame_size: 0x08,
252            max_burst_duration: 0,
253            max_average_rate: 0,
254            time_slice_fec_id: 0,
255            id_selector: &[],
256        };
257        let mut buf = vec![0u8; d.serialized_len()];
258        assert!(matches!(
259            d.serialize_into(&mut buf).unwrap_err(),
260            Error::InvalidDescriptor { .. }
261        ));
262    }
263
264    #[cfg(feature = "serde")]
265    #[test]
266    fn serde_serializes_to_stable_json() {
267        // Borrowed `&[u8]` cannot deserialize from a JSON number array, so we
268        // assert the Serialize impl is wired and emits stable JSON.
269        let d = TimeSliceFecIdentifierDescriptor {
270            time_slicing: true,
271            mpe_fec: 1,
272            frame_size: 3,
273            max_burst_duration: 0x44,
274            max_average_rate: 7,
275            time_slice_fec_id: 0xF,
276            id_selector: &[0xDE, 0xAD],
277        };
278        let j = serde_json::to_string(&d).unwrap();
279        // Valid, re-parseable JSON (key order is map-defined, so we do not
280        // assert byte-for-byte string stability).
281        let _v: serde_json::Value = serde_json::from_str(&j).unwrap();
282        assert!(j.contains("time_slice_fec_id"));
283    }
284}