Skip to main content

m2ts_packet/
adaptation_field.rs

1use bitfield_struct::bitfield;
2use bytes::Bytes;
3
4#[bitfield(u8, order = Msb)]
5pub struct AdaptationFieldFlags {
6    pub discontinuity_indicator: bool,
7    pub random_access_indicator: bool,
8    pub elementary_stream_priority_indicator: bool,
9    pub pcr_flag: bool,
10    pub opcr_flag: bool,
11    pub splicing_point_flag: bool,
12    pub transport_private_data_flag: bool,
13    pub adaptation_field_extension_flag: bool,
14}
15
16#[derive(Debug)]
17pub struct AdaptationField {
18    pub adaptation_field_length: u8,
19    pub flags: AdaptationFieldFlags,
20    /// 48 bit, Program clock reference, stored as 33 bits base, 6 bits reserved, 9 bits extension.  The value is calculated as base * 300 + extension.
21    pub program_clock_reference: Option<u64>, // u48
22    /// 48 bit, Original program clock reference, Helps when one TS is copied into another
23    pub original_program_clock_reference: Option<u64>, // u48
24    pub splice_countdown: Option<u8>,
25    // transport private data len: u8
26    pub transport_private_data: Bytes,
27    // Adaptation extension length: u8
28    pub adaptation_field_extension: Bytes,
29    // pub stuffing_bytes: Vec<u8>,
30}
31
32impl AdaptationField {
33    // data excludes the adaptation_field_length byte
34    pub fn from_bytes(data: Bytes) -> Option<Self> {
35        let adaption_field_length = data.len();
36        let mut index = 0;
37        let flags = AdaptationFieldFlags::from_bits(*data.get(index)?);
38        index += 1;
39
40        let program_clock_reference = if flags.pcr_flag() {
41            let pcr_bytes = data.get(index..index + 6)?;
42            let pcr_base = (u32::from_be_bytes(pcr_bytes[0..4].try_into().unwrap()) as u64) << 1
43                | (pcr_bytes[4] >> 7) as u64; // 33 bits
44            let pcr_extension = ((pcr_bytes[4] as u64) & 1) << 8 | pcr_bytes[5] as u64; // 9 bits
45            index += 6;
46            Some(pcr_base * 300 + pcr_extension)
47        } else {
48            None
49        };
50        let original_program_clock_reference = if flags.opcr_flag() {
51            let opcr_bytes = data.get(index..index + 6)?;
52            let opcr_base = (u32::from_be_bytes(opcr_bytes[0..4].try_into().unwrap()) as u64) << 1
53                | (opcr_bytes[4] >> 7) as u64; // 33 bits
54            let opcr_extension = ((opcr_bytes[4] as u64) & 1) << 8 | opcr_bytes[5] as u64; // 9 bits
55            index += 6;
56            Some(opcr_base * 300 + opcr_extension)
57        } else {
58            None
59        };
60        let splice_countdown = if flags.splicing_point_flag() {
61            let countdown = *data.get(index)?;
62            index += 1;
63            Some(countdown)
64        } else {
65            None
66        };
67        let transport_private_data = if flags.transport_private_data_flag() {
68            let len = *data.get(index)? as usize;
69            index += 1;
70            if index + len > data.len() {
71                return None;
72            }
73            let slice = data.slice(index..index + len);
74            index += len;
75            slice
76        } else {
77            Bytes::new()
78        };
79        let adaptation_field_extension = if flags.adaptation_field_extension_flag() {
80            let len = *data.get(index)? as usize;
81            index += 1;
82            if index + len > data.len() {
83                return None;
84            }
85            let slice = data.slice(index..index + len);
86            // index += len;
87            slice
88        } else {
89            Bytes::new()
90        };
91        Some(Self {
92            adaptation_field_length: adaption_field_length as u8,
93            flags,
94            program_clock_reference,
95            original_program_clock_reference,
96            splice_countdown,
97            transport_private_data,
98            adaptation_field_extension,
99        })
100    }
101    pub fn to_bytes(&self) -> Vec<u8> {
102        let mut data = Vec::with_capacity(self.adaptation_field_length as usize);
103        data.push(self.flags.into_bits());
104        if self.flags.pcr_flag() {
105            let pcr_base = self.program_clock_reference.unwrap() / 300;
106            let pcr_extension = self.program_clock_reference.unwrap() % 300;
107            let pcr_bytes = [
108                (pcr_base >> 25) as u8,
109                (pcr_base >> 17) as u8,
110                (pcr_base >> 9) as u8,
111                (pcr_base >> 1) as u8,
112                ((pcr_base & 1) << 7) as u8 | 0x7E | (pcr_extension >> 8) as u8,
113                (pcr_extension & 0xFF) as u8,
114            ];
115            data.extend_from_slice(&pcr_bytes);
116        }
117        if self.flags.opcr_flag() {
118            let opcr_base = self.original_program_clock_reference.unwrap() / 300;
119            let opcr_extension = self.original_program_clock_reference.unwrap() % 300;
120            let opcr_bytes = [
121                (opcr_base >> 25) as u8,
122                (opcr_base >> 17) as u8,
123                (opcr_base >> 9) as u8,
124                (opcr_base >> 1) as u8,
125                ((opcr_base & 1) << 7) as u8 | 0x7E | (opcr_extension >> 8) as u8,
126                (opcr_extension & 0xFF) as u8,
127            ];
128            data.extend_from_slice(&opcr_bytes);
129        }
130        if self.flags.splicing_point_flag() {
131            data.push(self.splice_countdown.unwrap_or_default());
132        }
133        if self.flags.transport_private_data_flag() {
134            data.push(self.transport_private_data.len() as u8);
135            data.extend_from_slice(&self.transport_private_data);
136        }
137        if self.flags.adaptation_field_extension_flag() {
138            data.push(self.adaptation_field_extension.len() as u8);
139            data.extend_from_slice(&self.adaptation_field_extension);
140        }
141
142        // add stuffing bytes if needed
143        while data.len() < self.adaptation_field_length as usize {
144            data.push(0xFF);
145        }
146        data
147    }
148}
149
150#[cfg(test)]
151mod tests {
152    use super::*;
153
154    #[allow(clippy::too_many_arguments)]
155    /// Helper: build a flags byte from individual bits (MSB order).
156    fn make_flags(
157        discontinuity: bool,
158        random_access: bool,
159        es_priority: bool,
160        pcr: bool,
161        opcr: bool,
162        splicing: bool,
163        private_data: bool,
164        extension: bool,
165    ) -> u8 {
166        (discontinuity as u8) << 7
167            | (random_access as u8) << 6
168            | (es_priority as u8) << 5
169            | (pcr as u8) << 4
170            | (opcr as u8) << 3
171            | (splicing as u8) << 2
172            | (private_data as u8) << 1
173            | extension as u8
174    }
175
176    /// Encode a PCR value (base, extension) into 6 bytes.
177    fn encode_pcr(base: u64, extension: u64) -> [u8; 6] {
178        [
179            (base >> 25) as u8,
180            (base >> 17) as u8,
181            (base >> 9) as u8,
182            (base >> 1) as u8,
183            ((base & 1) << 7) as u8 | 0x7E | (extension >> 8) as u8,
184            (extension & 0xFF) as u8,
185        ]
186    }
187
188    // ---------------------------------------------------------------
189    // from_bytes tests
190    // ---------------------------------------------------------------
191
192    #[test]
193    fn test_flags_only_no_optional_fields() {
194        // flags = 0x00 → nothing set
195        let data = Bytes::from_static(&[0x00]);
196        let af = AdaptationField::from_bytes(data).unwrap();
197        assert_eq!(af.adaptation_field_length, 1);
198        assert!(af.program_clock_reference.is_none());
199        assert!(af.original_program_clock_reference.is_none());
200        assert!(af.splice_countdown.is_none());
201        assert!(af.transport_private_data.is_empty());
202        assert!(af.adaptation_field_extension.is_empty());
203    }
204
205    #[test]
206    fn test_pcr_decode_zero() {
207        // PCR with base=0, extension=0 → value=0
208        let flags = make_flags(false, false, false, true, false, false, false, false);
209        let pcr = encode_pcr(0, 0);
210        let mut data = vec![flags];
211        data.extend_from_slice(&pcr);
212        let af = AdaptationField::from_bytes(Bytes::from(data)).unwrap();
213        assert_eq!(af.program_clock_reference, Some(0));
214    }
215
216    #[test]
217    fn test_pcr_decode_known_value() {
218        // base=1000, extension=150 → value = 1000*300 + 150 = 300150
219        let flags = make_flags(false, false, false, true, false, false, false, false);
220        let pcr = encode_pcr(1000, 150);
221        let mut data = vec![flags];
222        data.extend_from_slice(&pcr);
223        let af = AdaptationField::from_bytes(Bytes::from(data)).unwrap();
224        assert_eq!(af.program_clock_reference, Some(300_150));
225    }
226
227    #[test]
228    fn test_pcr_decode_max_base() {
229        // max 33-bit base = 2^33 - 1 = 8589934591, extension=299
230        let base: u64 = (1 << 33) - 1;
231        let ext: u64 = 299;
232        let flags = make_flags(false, false, false, true, false, false, false, false);
233        let pcr = encode_pcr(base, ext);
234        let mut data = vec![flags];
235        data.extend_from_slice(&pcr);
236        let af = AdaptationField::from_bytes(Bytes::from(data)).unwrap();
237        assert_eq!(af.program_clock_reference, Some(base * 300 + ext));
238    }
239
240    #[test]
241    fn test_pcr_decode_extension_bit8_set() {
242        // extension = 256 (bit 8 set) to verify low bit of byte 4
243        let base: u64 = 42;
244        let ext: u64 = 256;
245        let flags = make_flags(false, false, false, true, false, false, false, false);
246        let pcr = encode_pcr(base, ext);
247        let mut data = vec![flags];
248        data.extend_from_slice(&pcr);
249        let af = AdaptationField::from_bytes(Bytes::from(data)).unwrap();
250        assert_eq!(af.program_clock_reference, Some(base * 300 + ext));
251    }
252
253    #[test]
254    fn test_opcr_decode() {
255        let base: u64 = 5000;
256        let ext: u64 = 100;
257        let flags = make_flags(false, false, false, false, true, false, false, false);
258        let pcr = encode_pcr(base, ext);
259        let mut data = vec![flags];
260        data.extend_from_slice(&pcr);
261        let af = AdaptationField::from_bytes(Bytes::from(data)).unwrap();
262        assert_eq!(af.original_program_clock_reference, Some(base * 300 + ext));
263    }
264
265    #[test]
266    fn test_pcr_and_opcr_together() {
267        let flags = make_flags(false, false, false, true, true, false, false, false);
268        let pcr = encode_pcr(100, 50);
269        let opcr = encode_pcr(200, 99);
270        let mut data = vec![flags];
271        data.extend_from_slice(&pcr);
272        data.extend_from_slice(&opcr);
273        let af = AdaptationField::from_bytes(Bytes::from(data)).unwrap();
274        assert_eq!(af.program_clock_reference, Some(100 * 300 + 50));
275        assert_eq!(af.original_program_clock_reference, Some(200 * 300 + 99));
276    }
277
278    #[test]
279    fn test_splice_countdown() {
280        let flags = make_flags(false, false, false, false, false, true, false, false);
281        let data = Bytes::from(vec![flags, 42]);
282        let af = AdaptationField::from_bytes(data).unwrap();
283        assert_eq!(af.splice_countdown, Some(42));
284    }
285
286    #[test]
287    fn test_transport_private_data() {
288        let flags = make_flags(false, false, false, false, false, false, true, false);
289        let data = Bytes::from(vec![flags, 3, 0xAA, 0xBB, 0xCC]);
290        let af = AdaptationField::from_bytes(data).unwrap();
291        assert_eq!(
292            af.transport_private_data,
293            Bytes::from_static(&[0xAA, 0xBB, 0xCC])
294        );
295    }
296
297    #[test]
298    fn test_adaptation_field_extension() {
299        let flags = make_flags(false, false, false, false, false, false, false, true);
300        let data = Bytes::from(vec![flags, 2, 0x01, 0x02]);
301        let af = AdaptationField::from_bytes(data).unwrap();
302        assert_eq!(
303            af.adaptation_field_extension,
304            Bytes::from_static(&[0x01, 0x02])
305        );
306    }
307
308    #[test]
309    fn test_all_optional_fields() {
310        let flags = make_flags(true, true, true, true, true, true, true, true);
311        let pcr = encode_pcr(999, 123);
312        let opcr = encode_pcr(888, 77);
313        let splice: u8 = 10;
314        let private = [0xDE, 0xAD];
315        let ext = [0xBE, 0xEF];
316
317        let mut data = vec![flags];
318        data.extend_from_slice(&pcr);
319        data.extend_from_slice(&opcr);
320        data.push(splice);
321        data.push(private.len() as u8);
322        data.extend_from_slice(&private);
323        data.push(ext.len() as u8);
324        data.extend_from_slice(&ext);
325
326        let af = AdaptationField::from_bytes(Bytes::from(data)).unwrap();
327        assert_eq!(af.program_clock_reference, Some(999 * 300 + 123));
328        assert_eq!(af.original_program_clock_reference, Some(888 * 300 + 77));
329        assert_eq!(af.splice_countdown, Some(10));
330        assert_eq!(af.transport_private_data, Bytes::from_static(&[0xDE, 0xAD]));
331        assert_eq!(
332            af.adaptation_field_extension,
333            Bytes::from_static(&[0xBE, 0xEF])
334        );
335        assert!(af.flags.discontinuity_indicator());
336        assert!(af.flags.random_access_indicator());
337        assert!(af.flags.elementary_stream_priority_indicator());
338    }
339
340    #[test]
341    fn test_empty_data_returns_none() {
342        assert!(AdaptationField::from_bytes(Bytes::new()).is_none());
343    }
344
345    #[test]
346    fn test_truncated_pcr_returns_none() {
347        let flags = make_flags(false, false, false, true, false, false, false, false);
348        // Only 3 bytes of PCR instead of 6
349        let data = Bytes::from(vec![flags, 0x00, 0x00, 0x00]);
350        assert!(AdaptationField::from_bytes(data).is_none());
351    }
352
353    // ---------------------------------------------------------------
354    // to_bytes tests
355    // ---------------------------------------------------------------
356
357    #[test]
358    fn test_to_bytes_flags_only() {
359        let af = AdaptationField {
360            adaptation_field_length: 1,
361            flags: AdaptationFieldFlags::new().with_random_access_indicator(true),
362            program_clock_reference: None,
363            original_program_clock_reference: None,
364            splice_countdown: None,
365            transport_private_data: Default::default(),
366            adaptation_field_extension: Default::default(),
367        };
368        let bytes = af.to_bytes();
369        assert_eq!(bytes.len(), 1);
370        assert_eq!(bytes[0], 0b0100_0000); // random_access_indicator set
371    }
372
373    #[test]
374    fn test_to_bytes_pcr_reserved_bits() {
375        // Verify 6 reserved bits in PCR byte 4 are all 1
376        let af = AdaptationField {
377            adaptation_field_length: 7,
378            flags: AdaptationFieldFlags::new().with_pcr_flag(true),
379            program_clock_reference: Some(0), // base=0, ext=0
380            original_program_clock_reference: None,
381            splice_countdown: None,
382            transport_private_data: Default::default(),
383            adaptation_field_extension: Default::default(),
384        };
385        let bytes = af.to_bytes();
386        // byte 0 = flags, bytes 1-6 = PCR
387        // byte 5 (PCR byte 4): base[0]=0, reserved=0b111111, ext[8]=0 → 0x7E
388        assert_eq!(bytes[5] & 0x7E, 0x7E);
389    }
390
391    #[test]
392    fn test_to_bytes_stuffing() {
393        // adaptation_field_length=10 but only flags(1) → 9 stuffing bytes of 0xFF
394        let af = AdaptationField {
395            adaptation_field_length: 10,
396            flags: AdaptationFieldFlags::new(),
397            program_clock_reference: None,
398            original_program_clock_reference: None,
399            splice_countdown: None,
400            transport_private_data: Default::default(),
401            adaptation_field_extension: Default::default(),
402        };
403        let bytes = af.to_bytes();
404        assert_eq!(bytes.len(), 10);
405        assert!(bytes[1..].iter().all(|&b| b == 0xFF));
406    }
407
408    // ---------------------------------------------------------------
409    // roundtrip tests
410    // ---------------------------------------------------------------
411
412    #[test]
413    fn test_roundtrip_pcr() {
414        for &(base, ext) in &[
415            (0u64, 0u64),
416            (1, 0),
417            (0, 1),
418            (0, 299),
419            (1000, 150),
420            ((1u64 << 33) - 1, 299),
421            (123456789, 42),
422        ] {
423            let pcr_value = base * 300 + ext;
424            let flags = AdaptationFieldFlags::new().with_pcr_flag(true);
425            let af = AdaptationField {
426                adaptation_field_length: 7,
427                flags,
428                program_clock_reference: Some(pcr_value),
429                original_program_clock_reference: None,
430                splice_countdown: None,
431                transport_private_data: Default::default(),
432                adaptation_field_extension: Default::default(),
433            };
434            let bytes = af.to_bytes();
435            let af2 = AdaptationField::from_bytes(Bytes::from(bytes)).unwrap();
436            assert_eq!(
437                af2.program_clock_reference,
438                Some(pcr_value),
439                "roundtrip failed for base={base}, ext={ext}"
440            );
441        }
442    }
443
444    #[test]
445    fn test_roundtrip_all_fields() {
446        let flags = AdaptationFieldFlags::new()
447            .with_discontinuity_indicator(true)
448            .with_pcr_flag(true)
449            .with_opcr_flag(true)
450            .with_splicing_point_flag(true)
451            .with_transport_private_data_flag(true)
452            .with_adaptation_field_extension_flag(true);
453        let af = AdaptationField {
454            adaptation_field_length: 24,
455            flags,
456            program_clock_reference: Some(12345 * 300 + 67),
457            original_program_clock_reference: Some(99999 * 300 + 200),
458            splice_countdown: Some(5),
459            transport_private_data: Bytes::from_static(&[0x01, 0x02, 0x03]),
460            adaptation_field_extension: Bytes::from_static(&[0xAA]),
461        };
462        let bytes = af.to_bytes();
463        let af2 = AdaptationField::from_bytes(Bytes::from(bytes)).unwrap();
464        assert_eq!(af2.program_clock_reference, af.program_clock_reference);
465        assert_eq!(
466            af2.original_program_clock_reference,
467            af.original_program_clock_reference
468        );
469        assert_eq!(af2.splice_countdown, af.splice_countdown);
470        assert_eq!(af2.transport_private_data, af.transport_private_data);
471        assert_eq!(
472            af2.adaptation_field_extension,
473            af.adaptation_field_extension
474        );
475    }
476}