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