1use crate::error::{Error, Result};
4use crate::pid::Pid;
5use broadcast_common::len::{need_in, need_out};
6
7pub const TS_PACKET_SIZE: usize = 188;
9pub const TS_SYNC_BYTE: u8 = 0x47;
11pub const MAX_DATAGRAM_PAYLOAD: usize = 1472;
17pub const TS_PACKETS_PER_DATAGRAM: usize = 7;
24pub const TS_BYTES_PER_DATAGRAM: usize = TS_PACKETS_PER_DATAGRAM * TS_PACKET_SIZE;
27const MAX_SECTION_SIZE: usize = 4098;
32const SECTION_HEADER_LEN: usize = 3;
36pub(crate) const SECTION_LENGTH_HI_MASK: u8 = 0x0F;
40
41pub(crate) const STUFFING_BYTE: u8 = 0xFF;
43
44pub(crate) fn section_total_len(bytes: &[u8]) -> Option<usize> {
53 if bytes.len() < SECTION_HEADER_LEN {
54 return None;
55 }
56 let section_length = ((bytes[1] & SECTION_LENGTH_HI_MASK) as usize) << 8 | bytes[2] as usize;
57 Some(SECTION_HEADER_LEN + section_length)
58}
59
60#[non_exhaustive]
69#[derive(Debug, Clone, Copy, PartialEq, Eq)]
70#[cfg_attr(feature = "serde", derive(serde::Serialize))]
71pub enum ScramblingControl {
72 NotScrambled,
74 Reserved,
76 EvenKey,
79 OddKey,
82}
83
84impl ScramblingControl {
85 pub fn from_bits(bits: u8) -> Self {
87 match bits & 0b11 {
88 0b00 => Self::NotScrambled,
89 0b01 => Self::Reserved,
90 0b10 => Self::EvenKey,
91 0b11 => Self::OddKey,
92 _ => unreachable!(),
93 }
94 }
95
96 pub fn to_bits(self) -> u8 {
101 match self {
102 Self::NotScrambled => 0b00,
103 Self::Reserved => 0b01,
104 Self::EvenKey => 0b10,
105 Self::OddKey => 0b11,
106 }
107 }
108
109 pub fn name(&self) -> &'static str {
111 match self {
112 Self::NotScrambled => "not_scrambled",
113 Self::Reserved => "reserved",
114 Self::EvenKey => "even_key",
115 Self::OddKey => "odd_key",
116 }
117 }
118}
119
120broadcast_common::impl_spec_display!(ScramblingControl);
121
122#[non_exhaustive]
128#[derive(Debug, Clone, Copy, PartialEq, Eq)]
129#[cfg_attr(feature = "serde", derive(serde::Serialize))]
130pub enum AdaptationFieldControl {
131 Reserved,
133 PayloadOnly,
135 AdaptationOnly,
137 AdaptationAndPayload,
139}
140
141impl AdaptationFieldControl {
142 pub fn from_flags(has_adaptation: bool, has_payload: bool) -> Self {
144 match (has_adaptation, has_payload) {
145 (false, false) => Self::Reserved,
146 (false, true) => Self::PayloadOnly,
147 (true, false) => Self::AdaptationOnly,
148 (true, true) => Self::AdaptationAndPayload,
149 }
150 }
151
152 pub fn to_flags(self) -> (bool, bool) {
155 match self {
156 Self::Reserved => (false, false),
157 Self::PayloadOnly => (false, true),
158 Self::AdaptationOnly => (true, false),
159 Self::AdaptationAndPayload => (true, true),
160 }
161 }
162
163 pub fn to_bits(self) -> u8 {
169 match self {
170 Self::Reserved => 0b00,
171 Self::PayloadOnly => 0b01,
172 Self::AdaptationOnly => 0b10,
173 Self::AdaptationAndPayload => 0b11,
174 }
175 }
176
177 pub fn name(&self) -> &'static str {
179 match self {
180 Self::Reserved => "reserved",
181 Self::PayloadOnly => "payload_only",
182 Self::AdaptationOnly => "adaptation_only",
183 Self::AdaptationAndPayload => "adaptation_and_payload",
184 }
185 }
186}
187
188broadcast_common::impl_spec_display!(AdaptationFieldControl);
189
190const TEI_MASK: u8 = 0x80;
192const PUSI_MASK: u8 = 0x40;
194pub const PID_MASK_HI: u8 = 0x1F;
196pub const SCRAMBLING_MASK: u8 = 0xC0;
198pub const ADAPTATION_FLAG: u8 = 0x20;
200pub const PAYLOAD_FLAG: u8 = 0x10;
202pub const CC_MASK: u8 = 0x0F;
204
205#[derive(Clone, Debug, PartialEq, Eq)]
207#[cfg_attr(feature = "serde", derive(serde::Serialize))]
208pub struct TsHeader {
209 pub tei: bool,
212 pub pusi: bool,
215 pub pid: Pid,
217 pub scrambling: u8,
219 pub has_adaptation: bool,
221 pub has_payload: bool,
223 pub continuity_counter: u8,
225}
226
227#[derive(Clone, Debug)]
233#[cfg_attr(feature = "serde", derive(serde::Serialize))]
234pub struct TsPacket<'a> {
235 pub header: TsHeader,
237 pub payload: Option<&'a [u8]>,
240 #[cfg_attr(feature = "serde", serde(skip))]
243 adaptation: Option<&'a [u8]>,
244 #[cfg_attr(feature = "serde", serde(skip))]
246 pub raw: &'a [u8; TS_PACKET_SIZE],
247}
248
249impl TsHeader {
250 pub fn parse(raw4: &[u8]) -> Result<Self> {
252 need_in(raw4, 4, "TsHeader")?;
253 let b1 = raw4[1];
254 let b2 = raw4[2];
255 let b3 = raw4[3];
256
257 let tei = (b1 & TEI_MASK) != 0;
258 let pusi = (b1 & PUSI_MASK) != 0;
259 let pid = Pid::new((((b1 & PID_MASK_HI) as u16) << 8) | (b2 as u16));
260 let scrambling = (b3 & SCRAMBLING_MASK) >> 6;
261 let has_adaptation = (b3 & ADAPTATION_FLAG) != 0;
262 let has_payload = (b3 & PAYLOAD_FLAG) != 0;
263 let continuity_counter = b3 & CC_MASK;
264
265 Ok(Self {
266 tei,
267 pusi,
268 pid,
269 scrambling,
270 has_adaptation,
271 has_payload,
272 continuity_counter,
273 })
274 }
275
276 pub const fn serialized_len() -> usize {
278 4
279 }
280
281 pub fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
283 need_out(buf, 4)?;
284 buf[0] = TS_SYNC_BYTE;
285 buf[1] = 0;
286 if self.tei {
287 buf[1] |= TEI_MASK;
288 }
289 if self.pusi {
290 buf[1] |= PUSI_MASK;
291 }
292 let pid = self.pid.value();
293 buf[1] |= ((pid >> 8) as u8) & PID_MASK_HI;
294 buf[2] = pid.to_be_bytes()[1];
295 buf[3] = (self.scrambling << 6) & SCRAMBLING_MASK;
296 if self.has_adaptation {
297 buf[3] |= ADAPTATION_FLAG;
298 }
299 if self.has_payload {
300 buf[3] |= PAYLOAD_FLAG;
301 }
302 buf[3] |= self.continuity_counter & CC_MASK;
303 Ok(4)
304 }
305
306 pub fn scrambling_control(&self) -> ScramblingControl {
311 ScramblingControl::from_bits(self.scrambling)
312 }
313
314 pub fn adaptation_field_control(&self) -> AdaptationFieldControl {
319 AdaptationFieldControl::from_flags(self.has_adaptation, self.has_payload)
320 }
321}
322
323impl<'a> broadcast_common::Parse<'a> for TsHeader {
324 type Error = Error;
325
326 fn parse(bytes: &'a [u8]) -> Result<Self> {
327 TsHeader::parse(bytes)
328 }
329}
330
331impl broadcast_common::Serialize for TsHeader {
332 type Error = Error;
333
334 fn serialized_len(&self) -> usize {
335 TsHeader::serialized_len()
336 }
337
338 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
339 TsHeader::serialize_into(self, buf)
340 }
341}
342
343fn adaptation_field_skip(pkt: &[u8], has_adaptation: bool) -> usize {
354 if !has_adaptation || pkt.len() <= 4 {
355 return 0;
356 }
357 let af_len = pkt[4] as usize;
358 1 + af_len
359}
360
361impl<'a> TsPacket<'a> {
362 pub fn parse(buf: &'a [u8]) -> Result<Self> {
368 need_in(buf, TS_PACKET_SIZE, "TsPacket")?;
369 if buf[0] != TS_SYNC_BYTE {
370 return Err(Error::InvalidSync(broadcast_common::error::InvalidSync {
371 what: "TS sync byte",
372 expected: u32::from(TS_SYNC_BYTE),
373 found: u32::from(buf[0]),
374 }));
375 }
376
377 let raw: &[u8; TS_PACKET_SIZE] = buf[..TS_PACKET_SIZE].try_into().map_err(|_| {
378 Error::BufferTooShort(broadcast_common::error::BufferTooShort {
379 need: TS_PACKET_SIZE,
380 have: buf.len(),
381 what: "TsPacket::parse (array conversion)",
382 })
383 })?;
384
385 let header = TsHeader::parse(&raw[..4])?;
386
387 let mut cursor = 4usize;
388 let mut payload = None;
389 let mut adaptation = None;
390
391 if header.has_adaptation && cursor < TS_PACKET_SIZE {
404 let af_len = raw[cursor] as usize;
405 let af_start = cursor + 1;
406 if af_len > 0 && af_start < TS_PACKET_SIZE && af_start + af_len <= TS_PACKET_SIZE {
407 adaptation = Some(&raw[af_start..af_start + af_len]);
408 }
409 }
410 cursor += adaptation_field_skip(raw, header.has_adaptation);
415
416 if header.has_payload && cursor < TS_PACKET_SIZE {
417 payload = Some(&raw[cursor..]);
418 }
419
420 Ok(TsPacket {
421 header,
422 payload,
423 adaptation,
424 raw,
425 })
426 }
427
428 pub fn adaptation_field(&self) -> Option<crate::Result<AdaptationField<'a>>> {
434 self.adaptation.map(AdaptationField::parse)
435 }
436}
437
438pub(crate) const AF_DISCONTINUITY: u8 = 0x80;
440pub(crate) const AF_RANDOM_ACCESS: u8 = 0x40;
441pub(crate) const AF_ES_PRIORITY: u8 = 0x20;
442pub const AF_PCR_FLAG: u8 = 0x10;
444pub(crate) const AF_OPCR_FLAG: u8 = 0x08;
445pub(crate) const AF_SPLICING_FLAG: u8 = 0x04;
446pub(crate) const AF_TRANSPORT_PRIVATE_DATA_FLAG: u8 = 0x02;
447pub(crate) const AF_EXTENSION_FLAG: u8 = 0x01;
448const PCR_RESERVED_BITS: u8 = 0x7E;
451const PCR_RESERVED_SHIFT: u32 = 1;
453const PCR_RESERVED_VALUE: u8 = 0x3F;
455pub(crate) const PCR_FIELD_LEN: usize = 6;
457
458#[derive(Clone, Copy, Debug, PartialEq, Eq)]
461#[cfg_attr(feature = "serde", derive(serde::Serialize))]
462pub struct Pcr {
463 pub base: u64,
465 pub extension: u16,
467}
468
469impl Pcr {
470 #[must_use]
474 pub fn as_27mhz(self) -> u64 {
475 broadcast_common::clock33::pcr_from_parts(self.base, self.extension)
476 }
477
478 #[must_use]
487 pub fn from_27mhz(ticks: u64) -> Self {
488 let (base, extension) = broadcast_common::clock33::pcr_split(ticks);
489 Self { base, extension }
490 }
491
492 #[must_use]
501 pub fn to_field_bytes(self) -> [u8; PCR_FIELD_LEN] {
502 let b = self.base;
503 let e = self.extension as u64;
504 [
505 ((b >> 25) & 0xFF) as u8,
506 ((b >> 17) & 0xFF) as u8,
507 ((b >> 9) & 0xFF) as u8,
508 ((b >> 1) & 0xFF) as u8,
509 (((b & 0x01) as u8) << 7) | PCR_RESERVED_BITS | ((e >> 8) as u8 & 0x01),
511 (e & 0xFF) as u8,
512 ]
513 }
514
515 pub(crate) fn parse(af: &[u8], at: usize) -> Result<Self> {
517 let b: &[u8; PCR_FIELD_LEN] = af
518 .get(at..at + PCR_FIELD_LEN)
519 .and_then(|s| s.try_into().ok())
520 .ok_or(Error::BufferTooShort(
521 broadcast_common::error::BufferTooShort {
522 need: at + PCR_FIELD_LEN,
523 have: af.len(),
524 what: "adaptation_field PCR",
525 },
526 ))?;
527 let base = ((b[0] as u64) << 25)
528 | ((b[1] as u64) << 17)
529 | ((b[2] as u64) << 9)
530 | ((b[3] as u64) << 1)
531 | ((b[4] as u64) >> 7);
532 let extension = (((b[4] & 0x01) as u16) << 8) | (b[5] as u16);
533 Ok(Self { base, extension })
534 }
535}
536
537#[derive(Clone, Copy, Debug, PartialEq, Eq)]
544#[cfg_attr(feature = "serde", derive(serde::Serialize))]
545pub struct Ltw {
546 pub ltw_valid_flag: bool,
548 pub ltw_offset: u16,
550}
551
552#[non_exhaustive]
561#[derive(Clone, Copy, Debug, PartialEq, Eq)]
562#[cfg_attr(feature = "serde", derive(serde::Serialize))]
563pub struct SeamlessSplice {
564 pub splice_type: u8,
566 pub dts_next_au: u64,
568 pub marker_bits: u8,
573}
574
575impl SeamlessSplice {
576 #[must_use]
578 pub const fn new(splice_type: u8, dts_next_au: u64) -> Self {
579 Self {
580 splice_type,
581 dts_next_au,
582 marker_bits: SPLICE_MARKERS_VALUE,
583 }
584 }
585}
586
587const SPLICE_MARKERS_VALUE: u8 = 0x07;
591const AFE_LTW_FLAG: u8 = 0x80;
592const AFE_PIECEWISE_RATE_FLAG: u8 = 0x40;
593const AFE_SEAMLESS_SPLICE_FLAG: u8 = 0x20;
594const LTW_OFFSET_HI_MASK: u8 = 0x7F;
596const PIECEWISE_RATE_HI_MASK: u8 = 0x3F;
598const AFE_AF_DESCRIPTOR_NOT_PRESENT_FLAG: u8 = 0x10;
600const AFE_RESERVED_FLAGS_MASK: u8 = 0x0F;
602const AFE_RESERVED_FLAGS_VALUE: u8 = 0x0F;
604const PIECEWISE_RATE_RESERVED_SHIFT: u32 = 6;
606const PIECEWISE_RATE_RESERVED_VALUE: u8 = 0x03;
608
609#[non_exhaustive]
629#[derive(Clone, Copy, Debug, PartialEq, Eq)]
630#[cfg_attr(feature = "serde", derive(serde::Serialize))]
631pub struct AdaptationFieldExtension<'a> {
632 pub ltw: Option<Ltw>,
634 pub piecewise_rate: Option<u32>,
636 pub piecewise_rate_reserved: u8,
639 pub seamless_splice: Option<SeamlessSplice>,
641 pub af_descriptor_not_present_flag: bool,
645 pub reserved_flags: u8,
647 pub trailing: &'a [u8],
651}
652
653impl Default for AdaptationFieldExtension<'_> {
654 fn default() -> Self {
655 Self::new()
656 }
657}
658
659impl<'a> AdaptationFieldExtension<'a> {
660 #[must_use]
663 pub const fn new() -> Self {
664 Self {
665 ltw: None,
666 piecewise_rate: None,
667 piecewise_rate_reserved: PIECEWISE_RATE_RESERVED_VALUE,
668 seamless_splice: None,
669 af_descriptor_not_present_flag: true,
670 reserved_flags: AFE_RESERVED_FLAGS_VALUE,
671 trailing: &[],
672 }
673 }
674
675 fn parse(data: &'a [u8]) -> Result<Self> {
678 need_in(data, 1, "adaptation_field_extension_length")?;
679 let ext_len = data[0] as usize;
680 if data.len() < 1 + ext_len || ext_len < 1 {
682 return Err(Error::BufferTooShort(
683 broadcast_common::error::BufferTooShort {
684 need: 2.max(1 + ext_len),
685 have: data.len(),
686 what: "adaptation_field_extension body",
687 },
688 ));
689 }
690 let ext = &data[1..1 + ext_len]; let flags = ext[0];
692 let mut cursor = 1usize;
693
694 let ltw = if flags & AFE_LTW_FLAG != 0 {
695 need_in(ext, cursor + 2, "ltw_offset")?;
696 let w0 = ext[cursor];
697 let w1 = ext[cursor + 1];
698 cursor += 2;
699 Some(Ltw {
700 ltw_valid_flag: (w0 & AFE_LTW_FLAG) != 0,
701 ltw_offset: (((w0 & LTW_OFFSET_HI_MASK) as u16) << 8) | (w1 as u16),
702 })
703 } else {
704 None
705 };
706
707 let mut piecewise_rate_reserved = PIECEWISE_RATE_RESERVED_VALUE;
708 let piecewise_rate = if flags & AFE_PIECEWISE_RATE_FLAG != 0 {
709 need_in(ext, cursor + 3, "piecewise_rate")?;
710 piecewise_rate_reserved = ext[cursor] >> PIECEWISE_RATE_RESERVED_SHIFT;
711 let r = (((ext[cursor] & PIECEWISE_RATE_HI_MASK) as u32) << 16)
712 | ((ext[cursor + 1] as u32) << 8)
713 | (ext[cursor + 2] as u32);
714 cursor += 3;
715 Some(r)
716 } else {
717 None
718 };
719
720 let seamless_splice = if flags & AFE_SEAMLESS_SPLICE_FLAG != 0 {
722 need_in(ext, cursor + 5, "seamless_splice DTS_next_AU")?;
723 let b = &ext[cursor..cursor + 5];
724 let field: &[u8; 5] = b.try_into().expect("slice is exactly 5 bytes");
727 let m = broadcast_common::clock33::unpack_marked(field);
728 let (splice_type, dts_next_au) = (m.prefix, m.timestamp);
729 cursor += 5;
730 Some(SeamlessSplice {
731 splice_type,
732 dts_next_au,
733 marker_bits: m.markers,
734 })
735 } else {
736 None
737 };
738
739 Ok(AdaptationFieldExtension {
740 ltw,
741 piecewise_rate,
742 piecewise_rate_reserved,
743 seamless_splice,
744 af_descriptor_not_present_flag: flags & AFE_AF_DESCRIPTOR_NOT_PRESENT_FLAG != 0,
745 reserved_flags: flags & AFE_RESERVED_FLAGS_MASK,
746 trailing: &ext[cursor..],
747 })
748 }
749
750 #[must_use]
753 pub fn serialized_len(&self) -> usize {
754 let body = 1 + self.ltw.map_or(0, |_| 2)
756 + self.piecewise_rate.map_or(0, |_| 3)
757 + self.seamless_splice.map_or(0, |_| 5)
758 + self.trailing.len();
759 1 + body }
761
762 pub fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
764 let need = self.serialized_len();
765 need_out(buf, need)?;
766 buf[0] = broadcast_common::len::fit_u8(need - 1, "adaptation_field_extension_length")?;
767
768 let mut flags = broadcast_common::len::fit_mask(
769 self.reserved_flags,
770 AFE_RESERVED_FLAGS_MASK,
771 "adaptation_field_extension.reserved",
772 )?;
773 if self.ltw.is_some() {
774 flags |= AFE_LTW_FLAG;
775 }
776 if self.piecewise_rate.is_some() {
777 flags |= AFE_PIECEWISE_RATE_FLAG;
778 }
779 if self.seamless_splice.is_some() {
780 flags |= AFE_SEAMLESS_SPLICE_FLAG;
781 }
782 if self.af_descriptor_not_present_flag {
783 flags |= AFE_AF_DESCRIPTOR_NOT_PRESENT_FLAG;
784 }
785 buf[1] = flags;
786 let mut cursor = 2usize;
787
788 if let Some(ltw) = self.ltw {
789 let ltw_valid = if ltw.ltw_valid_flag { AFE_LTW_FLAG } else { 0 };
790 buf[cursor] = ltw_valid | ((ltw.ltw_offset >> 8) as u8 & LTW_OFFSET_HI_MASK);
791 buf[cursor + 1] = (ltw.ltw_offset & 0xFF) as u8;
792 cursor += 2;
793 }
794 if let Some(rate) = self.piecewise_rate {
795 buf[cursor] = (broadcast_common::len::fit_mask(
797 self.piecewise_rate_reserved,
798 PIECEWISE_RATE_RESERVED_VALUE,
799 "piecewise_rate.reserved",
800 )? << PIECEWISE_RATE_RESERVED_SHIFT)
801 | ((rate >> 16) as u8 & PIECEWISE_RATE_HI_MASK);
802 buf[cursor + 1] = (rate >> 8) as u8;
803 buf[cursor + 2] = rate as u8;
804 cursor += 3;
805 }
806 if let Some(ss) = self.seamless_splice {
807 buf[cursor..cursor + 5].copy_from_slice(&broadcast_common::clock33::pack_marked_with(
809 ss.dts_next_au,
810 ss.splice_type,
811 ss.marker_bits,
812 ));
813 cursor += 5;
814 }
815 buf[cursor..cursor + self.trailing.len()].copy_from_slice(self.trailing);
816 cursor += self.trailing.len();
817 Ok(cursor)
818 }
819}
820
821#[non_exhaustive]
830#[derive(Clone, Debug, PartialEq, Eq)]
831#[cfg_attr(feature = "serde", derive(serde::Serialize))]
832pub struct AdaptationField<'a> {
833 pub discontinuity_indicator: bool,
835 pub random_access_indicator: bool,
837 pub elementary_stream_priority_indicator: bool,
839 pub pcr: Option<Pcr>,
841 pub opcr: Option<Pcr>,
843 pub splice_countdown: Option<i8>,
845 pub transport_private_data: Option<&'a [u8]>,
850 pub extension: Option<AdaptationFieldExtension<'a>>,
852 pub pcr_reserved: u8,
858 pub opcr_reserved: u8,
860 pub stuffing: &'a [u8],
870}
871
872impl Default for AdaptationField<'_> {
873 fn default() -> Self {
874 Self::new()
875 }
876}
877
878fn set_pcr_reserved(field: &mut [u8], reserved: u8) {
880 field[4] =
881 (field[4] & !PCR_RESERVED_BITS) | ((reserved << PCR_RESERVED_SHIFT) & PCR_RESERVED_BITS);
882}
883
884impl<'a> AdaptationField<'a> {
885 #[must_use]
889 pub const fn new() -> Self {
890 Self {
891 discontinuity_indicator: false,
892 random_access_indicator: false,
893 elementary_stream_priority_indicator: false,
894 pcr: None,
895 opcr: None,
896 splice_countdown: None,
897 transport_private_data: None,
898 extension: None,
899 pcr_reserved: PCR_RESERVED_VALUE,
900 opcr_reserved: PCR_RESERVED_VALUE,
901 stuffing: &[],
902 }
903 }
904
905 pub(crate) fn parse(af: &'a [u8]) -> Result<Self> {
912 let flags = *af.first().ok_or(Error::BufferTooShort(
913 broadcast_common::error::BufferTooShort {
914 need: 1,
915 have: 0,
916 what: "adaptation_field flags",
917 },
918 ))?;
919 let mut cursor = 1usize;
920
921 let mut pcr_reserved = PCR_RESERVED_VALUE;
922 let mut opcr_reserved = PCR_RESERVED_VALUE;
923 let pcr = if flags & AF_PCR_FLAG != 0 {
924 let p = Pcr::parse(af, cursor)?;
925 pcr_reserved = (af[cursor + 4] & PCR_RESERVED_BITS) >> PCR_RESERVED_SHIFT;
926 cursor += PCR_FIELD_LEN;
927 Some(p)
928 } else {
929 None
930 };
931 let opcr = if flags & AF_OPCR_FLAG != 0 {
932 let p = Pcr::parse(af, cursor)?;
933 opcr_reserved = (af[cursor + 4] & PCR_RESERVED_BITS) >> PCR_RESERVED_SHIFT;
934 cursor += PCR_FIELD_LEN;
935 Some(p)
936 } else {
937 None
938 };
939 let splice_countdown = if flags & AF_SPLICING_FLAG != 0 {
940 let b = *af.get(cursor).ok_or(Error::BufferTooShort(
941 broadcast_common::error::BufferTooShort {
942 need: cursor + 1,
943 have: af.len(),
944 what: "adaptation_field splice_countdown",
945 },
946 ))?;
947 cursor += 1;
948 Some(b as i8)
949 } else {
950 None
951 };
952
953 let transport_private_data = if flags & AF_TRANSPORT_PRIVATE_DATA_FLAG != 0 {
956 let tpd_len = *af.get(cursor).ok_or(Error::BufferTooShort(
957 broadcast_common::error::BufferTooShort {
958 need: cursor + 1,
959 have: af.len(),
960 what: "transport_private_data_length",
961 },
962 ))? as usize;
963 cursor += 1;
964 let end = cursor + tpd_len;
965 let slice = af.get(cursor..end).ok_or(Error::BufferTooShort(
966 broadcast_common::error::BufferTooShort {
967 need: end,
968 have: af.len(),
969 what: "transport_private_data",
970 },
971 ))?;
972 cursor = end;
973 Some(slice)
974 } else {
975 None
976 };
977
978 let extension = if flags & AF_EXTENSION_FLAG != 0 {
980 let ext_data = af.get(cursor..).ok_or(Error::BufferTooShort(
981 broadcast_common::error::BufferTooShort {
982 need: cursor + 1,
983 have: af.len(),
984 what: "adaptation_field_extension",
985 },
986 ))?;
987 let ext = AdaptationFieldExtension::parse(ext_data)?;
988 if !ext_data.is_empty() {
990 let _ext_len = ext_data[0] as usize;
991 cursor += 1 + _ext_len;
992 }
993 Some(ext)
994 } else {
995 None
996 };
997
998 let stuffing = af.get(cursor..).unwrap_or(&[]);
1002
1003 Ok(AdaptationField {
1004 discontinuity_indicator: flags & AF_DISCONTINUITY != 0,
1005 random_access_indicator: flags & AF_RANDOM_ACCESS != 0,
1006 elementary_stream_priority_indicator: flags & AF_ES_PRIORITY != 0,
1007 pcr,
1008 opcr,
1009 splice_countdown,
1010 transport_private_data,
1011 extension,
1012 pcr_reserved,
1013 opcr_reserved,
1014 stuffing,
1015 })
1016 }
1017
1018 #[must_use]
1024 pub fn serialized_len(&self) -> usize {
1025 let mut n = 1usize; if self.pcr.is_some() {
1027 n += PCR_FIELD_LEN;
1028 }
1029 if self.opcr.is_some() {
1030 n += PCR_FIELD_LEN;
1031 }
1032 if self.splice_countdown.is_some() {
1033 n += 1;
1034 }
1035 if let Some(tpd) = self.transport_private_data {
1036 n += 1 + tpd.len(); }
1038 if let Some(ref ext) = self.extension {
1039 n += ext.serialized_len();
1040 }
1041 n += self.stuffing.len();
1042 n
1043 }
1044
1045 pub fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
1056 let need = self.serialized_len();
1057 need_out(buf, need)?;
1058
1059 let mut flags = 0u8;
1061 if self.discontinuity_indicator {
1062 flags |= AF_DISCONTINUITY;
1063 }
1064 if self.random_access_indicator {
1065 flags |= AF_RANDOM_ACCESS;
1066 }
1067 if self.elementary_stream_priority_indicator {
1068 flags |= AF_ES_PRIORITY;
1069 }
1070 if self.pcr.is_some() {
1071 flags |= AF_PCR_FLAG;
1072 }
1073 if self.opcr.is_some() {
1074 flags |= AF_OPCR_FLAG;
1075 }
1076 if self.splice_countdown.is_some() {
1077 flags |= AF_SPLICING_FLAG;
1078 }
1079 if self.transport_private_data.is_some() {
1080 flags |= AF_TRANSPORT_PRIVATE_DATA_FLAG;
1081 }
1082 if self.extension.is_some() {
1083 flags |= AF_EXTENSION_FLAG;
1084 }
1085 buf[0] = flags;
1086
1087 let mut cursor = 1usize;
1088 if let Some(pcr) = self.pcr {
1089 buf[cursor..cursor + PCR_FIELD_LEN].copy_from_slice(&pcr.to_field_bytes());
1090 set_pcr_reserved(&mut buf[cursor..cursor + PCR_FIELD_LEN], self.pcr_reserved);
1091 cursor += PCR_FIELD_LEN;
1092 }
1093 if let Some(opcr) = self.opcr {
1094 buf[cursor..cursor + PCR_FIELD_LEN].copy_from_slice(&opcr.to_field_bytes());
1095 set_pcr_reserved(&mut buf[cursor..cursor + PCR_FIELD_LEN], self.opcr_reserved);
1096 cursor += PCR_FIELD_LEN;
1097 }
1098 if let Some(sc) = self.splice_countdown {
1099 buf[cursor] = sc as u8;
1100 cursor += 1;
1101 }
1102 if let Some(tpd) = self.transport_private_data {
1103 buf[cursor] = broadcast_common::len::fit_u8(
1104 tpd.len(),
1105 "adaptation_field.transport_private_data_length",
1106 )?;
1107 cursor += 1;
1108 buf[cursor..cursor + tpd.len()].copy_from_slice(tpd);
1109 cursor += tpd.len();
1110 }
1111 if let Some(ref ext) = self.extension {
1112 let written = ext.serialize_into(&mut buf[cursor..])?;
1113 cursor += written;
1114 }
1115
1116 buf[cursor..cursor + self.stuffing.len()].copy_from_slice(self.stuffing);
1119 cursor += self.stuffing.len();
1120
1121 Ok(cursor)
1122 }
1123}
1124
1125#[derive(Default)]
1130pub struct SectionReassembler {
1131 buf: bytes::BytesMut,
1132 ready: alloc::collections::VecDeque<bytes::Bytes>,
1133 last_continuity_counter: Option<u8>,
1134}
1135
1136impl SectionReassembler {
1137 pub fn feed(&mut self, payload: &[u8], pusi: bool) {
1145 self.last_continuity_counter = None;
1146 self.feed_payload(payload, pusi);
1147 }
1148
1149 pub fn feed_with_continuity(
1163 &mut self,
1164 payload: &[u8],
1165 pusi: bool,
1166 continuity_counter: u8,
1167 discontinuity: bool,
1168 ) {
1169 let duplicate = !discontinuity && self.last_continuity_counter == Some(continuity_counter);
1170 self.last_continuity_counter = Some(continuity_counter);
1171 if duplicate && !pusi {
1172 return;
1173 }
1174 self.feed_payload(payload, pusi);
1175 }
1176
1177 fn feed_payload(&mut self, payload: &[u8], pusi: bool) {
1178 if pusi {
1179 if payload.is_empty() {
1182 self.buf.clear();
1183 return;
1184 }
1185 let pointer = payload[0] as usize;
1186
1187 if !self.buf.is_empty() && pointer > 0 {
1195 let avail = payload.len() - 1;
1196 let tail_len = pointer.min(avail);
1197 if self.buf.len() + tail_len > MAX_SECTION_SIZE {
1198 self.buf.clear();
1199 } else {
1200 self.buf.extend_from_slice(&payload[1..1 + tail_len]);
1201 self.drain_complete_sections();
1202 }
1203 }
1204
1205 self.buf.clear();
1208
1209 let start = 1 + pointer;
1210 if start >= payload.len() {
1211 return;
1213 }
1214 let new_data = &payload[start..];
1215 if new_data.len() > MAX_SECTION_SIZE {
1216 return;
1217 }
1218 self.buf.extend_from_slice(new_data);
1219 } else {
1220 if self.buf.is_empty() {
1221 return;
1222 }
1223 let take = if let Some(exp) = section_total_len(&self.buf) {
1233 exp.saturating_sub(self.buf.len()).min(payload.len())
1234 } else {
1235 payload.len().min(MAX_SECTION_SIZE - self.buf.len())
1239 };
1240 self.buf.extend_from_slice(&payload[..take]);
1241 }
1242
1243 self.drain_complete_sections();
1244 }
1245
1246 fn drain_complete_sections(&mut self) {
1257 loop {
1258 if self.buf.len() < SECTION_HEADER_LEN {
1259 break;
1262 }
1263 if self.buf[0] == STUFFING_BYTE {
1264 self.buf.clear();
1266 break;
1267 }
1268 let exp =
1269 section_total_len(&self.buf).expect("checked len >= SECTION_HEADER_LEN above");
1270 if self.buf.len() >= exp {
1271 let section = self.buf.split_to(exp).freeze();
1272 self.ready.push_back(section);
1273 } else {
1274 break;
1276 }
1277 }
1278 }
1279
1280 pub fn pop_section(&mut self) -> Option<bytes::Bytes> {
1282 self.ready.pop_front()
1283 }
1284
1285 pub fn len(&self) -> usize {
1287 self.buf.len()
1288 }
1289
1290 pub fn is_empty(&self) -> bool {
1292 self.buf.is_empty()
1293 }
1294}
1295
1296pub fn iter_packets(buf: &[u8]) -> impl Iterator<Item = TsPacket<'_>> {
1314 buf.chunks_exact(TS_PACKET_SIZE)
1315 .filter_map(|chunk| TsPacket::parse(chunk).ok())
1316}
1317
1318pub fn extract_ts_payload(pkt: &[u8]) -> Option<&[u8]> {
1328 if pkt.len() < 4 {
1329 return None;
1330 }
1331 let header = TsHeader::parse(&pkt[..4]).ok()?;
1332 if !header.has_payload {
1333 return None;
1334 }
1335 let cursor = 4 + adaptation_field_skip(pkt, header.has_adaptation);
1336 if cursor < pkt.len() {
1337 Some(&pkt[cursor..])
1338 } else {
1339 None
1340 }
1341}
1342
1343#[cfg(test)]
1344mod tests {
1345 use super::*;
1346 use alloc::string::ToString;
1347 use alloc::vec;
1348 use alloc::vec::Vec;
1349
1350 fn make_packet(b1: u8, b2: u8, b3: u8, payload_data: &[u8]) -> [u8; TS_PACKET_SIZE] {
1352 let mut pkt = [0u8; TS_PACKET_SIZE];
1353 pkt[0] = TS_SYNC_BYTE;
1354 pkt[1] = b1;
1355 pkt[2] = b2;
1356 pkt[3] = b3;
1357 let payload_start = 4;
1358 let end = (payload_start + payload_data.len()).min(TS_PACKET_SIZE);
1359 let len = (end - payload_start).min(payload_data.len());
1360 pkt[payload_start..payload_start + len].copy_from_slice(&payload_data[..len]);
1361 pkt
1362 }
1363
1364 #[test]
1365 fn parse_rejects_non_0x47_sync_byte() {
1366 let mut pkt = [0u8; TS_PACKET_SIZE];
1367 pkt[0] = 0x46; let err = TsPacket::parse(&pkt).unwrap_err();
1369 match err {
1370 Error::InvalidSync(e) => assert_eq!(e.found, 0x46),
1371 other => panic!("expected InvalidSyncByte, got {other:?}"),
1372 }
1373 }
1374
1375 #[test]
1376 fn ts_header_round_trip() {
1377 let cases = [
1380 TsHeader {
1381 tei: false,
1382 pusi: true,
1383 pid: Pid::new(0x0000),
1384 scrambling: 0,
1385 has_adaptation: false,
1386 has_payload: true,
1387 continuity_counter: 0,
1388 },
1389 TsHeader {
1390 tei: true,
1391 pusi: false,
1392 pid: Pid::new(0x1FFF),
1393 scrambling: 0b11,
1394 has_adaptation: true,
1395 has_payload: true,
1396 continuity_counter: 0x0F,
1397 },
1398 TsHeader {
1399 tei: false,
1400 pusi: false,
1401 pid: Pid::new(0x0100),
1402 scrambling: 0b10,
1403 has_adaptation: true,
1404 has_payload: false,
1405 continuity_counter: 7,
1406 },
1407 ];
1408 for h in cases {
1409 let mut buf = [0u8; 4];
1410 assert_eq!(h.serialize_into(&mut buf).unwrap(), 4);
1411 assert_eq!(TsHeader::parse(&buf).unwrap(), h, "round-trip mismatch");
1412 }
1413 }
1414
1415 #[test]
1416 fn parse_extracts_pid_and_continuity_counter() {
1417 let pkt = make_packet(0x12, 0x34, 0x05, &[]);
1423 let pkt = TsPacket::parse(&pkt).unwrap();
1424 assert_eq!(pkt.header.pid, Pid::new(0x1234));
1425 assert_eq!(pkt.header.continuity_counter, 5);
1426 }
1427
1428 #[test]
1429 fn payload_unit_start_indicator_flag_extracted() {
1430 let pkt1 = make_packet(0x40, 0x00, 0x00, &[]);
1432 let pkt1 = TsPacket::parse(&pkt1).unwrap();
1433 assert!(pkt1.header.pusi);
1434
1435 let pkt2 = make_packet(0x00, 0x00, 0x00, &[]);
1437 let pkt2 = TsPacket::parse(&pkt2).unwrap();
1438 assert!(!pkt2.header.pusi);
1439 }
1440
1441 fn build_pusi_payload(pointer_field: u8, previous_tail: &[u8], section: &[u8]) -> Vec<u8> {
1446 assert_eq!(pointer_field as usize, previous_tail.len());
1447 let mut v = Vec::with_capacity(1 + previous_tail.len() + section.len());
1448 v.push(pointer_field);
1449 v.extend_from_slice(previous_tail);
1450 v.extend_from_slice(section);
1451 v
1452 }
1453
1454 #[test]
1460 fn reassembler_accumulates_multi_packet_section() {
1461 let body = vec![0xAAu8; 197];
1463 let section = test_fixtures::psi::short_section(0x02, &body);
1464 assert_eq!(section.len(), 200);
1465
1466 let first_chunk = 100;
1467 let payload1 = build_pusi_payload(0, &[], §ion[..first_chunk]);
1468 let payload2 = section[first_chunk..].to_vec();
1469
1470 let mut reasm = SectionReassembler::default();
1471 reasm.feed(&payload1, true);
1472 reasm.feed(&payload2, false);
1473
1474 let out = reasm.pop_section().expect("section should be ready");
1475 assert_eq!(out.len(), 200);
1476 assert_eq!(out.as_ref(), §ion[..]);
1477 }
1478
1479 #[test]
1480 fn reassembler_yields_complete_section_once_length_satisfied() {
1481 let section = test_fixtures::psi::short_section(0x42, &[0xAA]);
1483 assert_eq!(section.len(), 4);
1484 let payload = build_pusi_payload(0, &[], §ion);
1485
1486 let mut reasm = SectionReassembler::default();
1487 reasm.feed(&payload, true);
1488
1489 let out = reasm
1490 .pop_section()
1491 .expect("single-packet section should pop");
1492 assert_eq!(out.as_ref(), §ion[..]);
1493 }
1494
1495 #[test]
1496 fn reassembler_extracts_all_concatenated_sections_in_one_payload() {
1497 let s1 = test_fixtures::psi::short_section(0x42, &[0x11, 0x22]); let s2 = test_fixtures::psi::short_section(0x46, &[0x33]); let s3 = test_fixtures::psi::short_section(0x4A, &[0x44, 0x55, 0x66]); let mut concat = Vec::new();
1506 concat.extend_from_slice(&s1);
1507 concat.extend_from_slice(&s2);
1508 concat.extend_from_slice(&s3);
1509 let payload = build_pusi_payload(0, &[], &concat);
1510
1511 let mut reasm = SectionReassembler::default();
1512 reasm.feed(&payload, true);
1513
1514 let got: Vec<_> = core::iter::from_fn(|| reasm.pop_section()).collect();
1516 assert_eq!(got.len(), 3, "all three concatenated sections must pop");
1517 assert_eq!(got[0].as_ref(), &s1[..]);
1518 assert_eq!(got[1].as_ref(), &s2[..]);
1519 assert_eq!(got[2].as_ref(), &s3[..]);
1520 }
1521
1522 #[test]
1523 fn reassembler_stops_at_stuffing_after_concatenated_sections() {
1524 let s1 = test_fixtures::psi::short_section(0x42, &[0xAA]); let s2 = test_fixtures::psi::short_section(0x46, &[0xBB, 0xCC]); let mut concat = Vec::new();
1530 concat.extend_from_slice(&s1);
1531 concat.extend_from_slice(&s2);
1532 concat.extend_from_slice(&[0xFF, 0xFF, 0xFF, 0xFF]); let payload = build_pusi_payload(0, &[], &concat);
1534
1535 let mut reasm = SectionReassembler::default();
1536 reasm.feed(&payload, true);
1537
1538 let got: Vec<_> = core::iter::from_fn(|| reasm.pop_section()).collect();
1539 assert_eq!(got.len(), 2);
1540 assert_eq!(got[0].as_ref(), &s1[..]);
1541 assert_eq!(got[1].as_ref(), &s2[..]);
1542 assert!(
1543 reasm.is_empty(),
1544 "stuffing tail must be discarded, not buffered"
1545 );
1546 }
1547
1548 #[test]
1549 fn reassembler_concatenated_then_spanning_tail() {
1550 let s1 = test_fixtures::psi::short_section(0x42, &[0x01, 0x02]); let s2 = test_fixtures::psi::short_section(0x46, &[0x09u8; 60]); let split = 30;
1556
1557 let mut head = Vec::new();
1558 head.extend_from_slice(&s1);
1559 head.extend_from_slice(&s2[..split]);
1560 let payload1 = build_pusi_payload(0, &[], &head);
1561 let payload2 = s2[split..].to_vec();
1562
1563 let mut reasm = SectionReassembler::default();
1564 reasm.feed(&payload1, true);
1565 let first = reasm.pop_section().expect("first section pops at once");
1566 assert_eq!(first.as_ref(), &s1[..]);
1567 assert!(reasm.pop_section().is_none(), "second is still partial");
1568
1569 reasm.feed(&payload2, false);
1570 let second = reasm.pop_section().expect("second pops after continuation");
1571 assert_eq!(second.as_ref(), &s2[..]);
1572 }
1573
1574 #[test]
1575 fn reassembler_completes_section_spanning_into_pusi_packet() {
1576 let spanning = test_fixtures::psi::short_section(0x42, &[0x5Au8; 62]); let head = 41;
1584 let tail = &spanning[head..]; assert_eq!(tail.len(), 24);
1586
1587 let next = test_fixtures::psi::short_section(0x46, &[0x77, 0x88]); let payload_a = build_pusi_payload(0, &[], &spanning[..head]);
1592 let payload_b = build_pusi_payload(24, tail, &next);
1594
1595 let mut reasm = SectionReassembler::default();
1596 reasm.feed(&payload_a, true);
1597 assert!(reasm.pop_section().is_none(), "head alone is incomplete");
1598
1599 reasm.feed(&payload_b, true);
1600 let got: Vec<_> = core::iter::from_fn(|| reasm.pop_section()).collect();
1601 assert_eq!(got.len(), 2, "spanning section + new section must both pop");
1602 assert_eq!(
1603 got[0].as_ref(),
1604 &spanning[..],
1605 "spanning section completed from B's pointer tail"
1606 );
1607 assert_eq!(got[1].as_ref(), &next[..]);
1608 }
1609
1610 #[test]
1611 fn reassembler_pusi_pointer_spans_whole_payload() {
1612 let spanning = test_fixtures::psi::short_section(0x42, &[0x33u8; 40]); let head = 20;
1617 let payload_a = build_pusi_payload(0, &[], &spanning[..head]);
1618 let tail = &spanning[head..]; let mut reasm = SectionReassembler::default();
1621 reasm.feed(&payload_a, true);
1622 reasm.feed(&build_pusi_payload_pointer_spanning_all(tail), true);
1624
1625 let out = reasm.pop_section().expect("spanning section completes");
1626 assert_eq!(out.as_ref(), &spanning[..]);
1627 assert!(reasm.pop_section().is_none());
1628 }
1629
1630 fn build_pusi_payload_pointer_spanning_all(tail: &[u8]) -> Vec<u8> {
1633 let mut v = Vec::with_capacity(1 + tail.len());
1634 v.push(tail.len() as u8);
1635 v.extend_from_slice(tail);
1636 v
1637 }
1638
1639 #[test]
1640 fn reassembler_discards_a_retransmitted_continuation_packet() {
1641 let mut section = vec![0x4Eu8, 0xB0, 0x00];
1642 section.resize(300, 0x5A);
1643 section[1] = 0xB0 | (((300 - 3) >> 8) as u8);
1644 section[2] = ((300 - 3) & 0xFF) as u8;
1645 let mut first = vec![0x00u8];
1646 first.extend_from_slice(§ion[..183]);
1647
1648 let mut reasm = SectionReassembler::default();
1649 reasm.feed_with_continuity(&first, true, 0, false);
1650 reasm.feed_with_continuity(§ion[183..250], false, 1, false);
1651 reasm.feed_with_continuity(§ion[183..250], false, 1, false);
1652 reasm.feed_with_continuity(§ion[250..], false, 2, false);
1653
1654 let out = reasm.pop_section().expect("section survives the duplicate");
1655 assert_eq!(out.as_ref(), §ion[..]);
1656 assert!(reasm.pop_section().is_none());
1657 }
1658
1659 #[test]
1660 fn a_packet_after_a_discontinuity_with_an_unchanged_counter_is_not_a_duplicate() {
1661 let mut section = vec![0x4Eu8, 0xB0, 0x00];
1662 section.resize(300, 0x5A);
1663 section[1] = 0xB0 | (((300 - 3) >> 8) as u8);
1664 section[2] = ((300 - 3) & 0xFF) as u8;
1665 let mut first = vec![0x00u8];
1666 first.extend_from_slice(§ion[..183]);
1667
1668 let mut reasm = SectionReassembler::default();
1669 reasm.feed_with_continuity(&first, true, 0, false);
1670 reasm.feed_with_continuity(§ion[183..250], false, 0, true);
1671 reasm.feed_with_continuity(§ion[250..], false, 1, false);
1672
1673 let out = reasm
1674 .pop_section()
1675 .expect("section survives the discontinuity");
1676 assert_eq!(out.as_ref(), §ion[..]);
1677 assert!(reasm.pop_section().is_none());
1678 }
1679
1680 #[test]
1681 fn reassembler_completes_max_length_section_and_stays_usable() {
1682 let mut section = Vec::with_capacity(MAX_SECTION_SIZE);
1688 section.push(0x00); section.push(0xB0 | ((4095u16 >> 8) as u8 & 0x0F));
1690 section.push(0xFF); section.resize(MAX_SECTION_SIZE, 0u8);
1692 assert_eq!(section.len(), MAX_SECTION_SIZE);
1693
1694 let mut reasm = SectionReassembler::default();
1695 let mut first = vec![0x00u8]; first.extend_from_slice(§ion[..183]);
1697 reasm.feed(&first, true);
1698 assert!(
1699 reasm.pop_section().is_none(),
1700 "incomplete until the declared length arrives"
1701 );
1702
1703 for chunk in section[183..].chunks(184) {
1704 reasm.feed(chunk, false);
1705 }
1706 let out = reasm
1707 .pop_section()
1708 .expect("max-length section completes at its declared length");
1709 assert_eq!(out.len(), MAX_SECTION_SIZE);
1710 assert_eq!(out.as_ref(), §ion[..]);
1711 assert!(reasm.is_empty());
1712
1713 reasm.feed(&[0u8; 184], false);
1717 assert!(reasm.pop_section().is_none());
1718
1719 let valid_section = test_fixtures::psi::short_section(0x00, &[0xAA]);
1721 let payload2 = build_pusi_payload(0, &[], &valid_section);
1722 reasm.feed(&payload2, true);
1723 let out = reasm
1724 .pop_section()
1725 .expect("fresh section should pop after reset");
1726 assert_eq!(out.as_ref(), &valid_section[..]);
1727 }
1728
1729 #[test]
1730 fn reassembler_handles_pusi_with_nonzero_pointer_field() {
1731 let prior_tail = vec![0x11, 0x22, 0x33];
1733 let new_section = test_fixtures::psi::short_section(0x02, &[0xBB]);
1734 assert_eq!(new_section.len(), 4);
1735 let payload = build_pusi_payload(3, &prior_tail, &new_section);
1736
1737 let mut reasm = SectionReassembler::default();
1738 reasm.feed(&payload, true);
1739
1740 let out = reasm
1741 .pop_section()
1742 .expect("section after pointer_field skip should pop");
1743 assert_eq!(out.as_ref(), &new_section[..]);
1744 }
1745
1746 #[test]
1747 fn reassembler_ignores_continuation_before_pusi() {
1748 let pkt = make_packet(0x00, 0x00, PAYLOAD_FLAG, &[0xAA, 0xBB, 0xCC]);
1751
1752 let mut reasm = SectionReassembler::default();
1753 reasm.feed(&pkt[4..], false); assert!(
1756 reasm.pop_section().is_none(),
1757 "no section should appear without prior PUSI"
1758 );
1759 assert!(
1760 reasm.pop_section().is_none(),
1761 "second pop should also be none"
1762 );
1763 }
1764
1765 #[test]
1768 fn reassembler_empty_pusi_payload_does_not_panic() {
1769 let mut reasm = SectionReassembler::default();
1770 reasm.feed(&[], true);
1771 assert!(reasm.pop_section().is_none());
1772 let payload = vec![0x00u8, 0x72, 0x70, 0x01, 0x00];
1774 reasm.feed(&payload, true);
1775 assert!(reasm.pop_section().is_some());
1776 }
1777
1778 #[test]
1782 fn reassembler_accepts_maximal_private_section() {
1783 let mut section = vec![0x80u8, 0x7F, 0xFF]; section.resize(3 + 0xFFF, 0xAB);
1785
1786 let mut reasm = SectionReassembler::default();
1787 let mut first = vec![0x00];
1789 first.extend_from_slice(§ion[..183]);
1790 reasm.feed(&first, true);
1791 for chunk in section[183..].chunks(184) {
1792 reasm.feed(chunk, false);
1793 }
1794 let out = reasm.pop_section().expect("4098-byte section should pop");
1795 assert_eq!(out.len(), 4098);
1796 assert_eq!(out.as_ref(), §ion[..]);
1797 }
1798
1799 #[test]
1804 fn reassembler_completes_large_section_with_trailing_stuffing() {
1805 let body = vec![0x5Au8; 4096 - 3];
1806 let section = test_fixtures::psi::short_section(0x50, &body); assert_eq!(section.len(), 4096);
1808
1809 let mut reasm = SectionReassembler::default();
1810 let mut first = vec![0x00u8];
1812 first.extend_from_slice(§ion[..183]);
1813 reasm.feed(&first, true);
1814
1815 let mut pos = 183usize;
1819 while pos < section.len() {
1820 let take = (section.len() - pos).min(184);
1821 let mut payload = section[pos..pos + take].to_vec();
1822 if take < 184 {
1823 payload.resize(184, 0xFF); }
1825 reasm.feed(&payload, false);
1826 pos += take;
1827 }
1828
1829 let out = reasm
1830 .pop_section()
1831 .expect("4096-byte section must complete despite trailing stuffing (#148)");
1832 assert_eq!(out.len(), 4096);
1833 assert_eq!(out.as_ref(), §ion[..]);
1834 assert!(reasm.is_empty(), "stuffing tail must be discarded");
1835 }
1836
1837 #[test]
1840 fn pcr_as_27mhz_known_value() {
1841 assert_eq!(
1842 Pcr {
1843 base: 10_000,
1844 extension: 0
1845 }
1846 .as_27mhz(),
1847 3_000_000
1848 );
1849 assert_eq!(
1851 Pcr {
1852 base: 1,
1853 extension: 100
1854 }
1855 .as_27mhz(),
1856 400
1857 );
1858 }
1859
1860 #[test]
1861 fn pcr_decode_from_bytes() {
1862 let af = [0x10u8, 0x00, 0x00, 0x13, 0x88, 0x7E, 0x00];
1864 let pcr = Pcr::parse(&af, 1).expect("6 bytes present");
1865 assert_eq!(
1866 pcr,
1867 Pcr {
1868 base: 10_000,
1869 extension: 0
1870 }
1871 );
1872 assert_eq!(pcr.as_27mhz(), 3_000_000);
1873 }
1874
1875 #[test]
1876 fn adaptation_field_flags_and_pcr() {
1877 let mut raw = [0xAAu8; TS_PACKET_SIZE];
1878 raw[0] = TS_SYNC_BYTE;
1879 raw[1] = 0x01; raw[2] = 0x00;
1881 raw[3] = ADAPTATION_FLAG | PAYLOAD_FLAG;
1882 raw[4] = 7; raw[5] = AF_DISCONTINUITY | AF_PCR_FLAG;
1884 raw[6..12].copy_from_slice(&[0x00, 0x00, 0x13, 0x88, 0x7E, 0x00]);
1885 let pkt = TsPacket::parse(&raw).expect("valid packet");
1888 let af = pkt
1889 .adaptation_field()
1890 .expect("has adaptation field")
1891 .expect("adaptation field parses");
1892 assert!(af.discontinuity_indicator);
1893 assert!(!af.random_access_indicator);
1894 assert_eq!(
1895 af.pcr,
1896 Some(Pcr {
1897 base: 10_000,
1898 extension: 0
1899 })
1900 );
1901 assert_eq!(af.pcr.unwrap().as_27mhz(), 3_000_000);
1902 assert!(af.opcr.is_none());
1903 assert!(af.splice_countdown.is_none());
1904 let payload = pkt.payload.expect("payload present");
1906 assert_eq!(payload.len(), TS_PACKET_SIZE - 12);
1907 assert_eq!(payload[0], 0xAA);
1908 }
1909
1910 #[test]
1911 fn oversized_adaptation_field_length_is_rejected_not_truncated() {
1912 let mut raw = [0xAAu8; TS_PACKET_SIZE];
1918 raw[0] = TS_SYNC_BYTE;
1919 raw[1] = 0x01;
1920 raw[2] = 0x00;
1921 raw[3] = ADAPTATION_FLAG; raw[4] = 200; let pkt = TsPacket::parse(&raw).expect("header + af_len byte still parse");
1925 assert!(
1926 pkt.adaptation_field().is_none(),
1927 "an over-long adaptation field must be rejected, not truncated"
1928 );
1929 assert!(pkt.payload.is_none());
1930
1931 let owned = crate::owned::OwnedTsPacket::parse(raw).unwrap();
1933 assert!(owned.adaptation_field().is_none());
1934 }
1935
1936 #[test]
1937 fn no_adaptation_returns_none() {
1938 let mut raw = [0x00u8; TS_PACKET_SIZE];
1939 raw[0] = TS_SYNC_BYTE;
1940 raw[1] = 0x01;
1941 raw[3] = PAYLOAD_FLAG; let pkt = TsPacket::parse(&raw).expect("valid");
1943 assert!(pkt.adaptation_field().is_none());
1944 assert!(pkt.adaptation.is_none());
1945 }
1946
1947 #[test]
1948 fn adaptation_field_splice_countdown_negative() {
1949 let mut raw = [0xAAu8; TS_PACKET_SIZE];
1950 raw[0] = TS_SYNC_BYTE;
1951 raw[1] = 0x01;
1952 raw[2] = 0x00;
1953 raw[3] = ADAPTATION_FLAG | PAYLOAD_FLAG;
1954 raw[4] = 2; raw[5] = AF_SPLICING_FLAG;
1956 raw[6] = 0xFB; let pkt = TsPacket::parse(&raw).expect("valid");
1958 let af = pkt.adaptation_field().unwrap().unwrap();
1959 assert_eq!(af.splice_countdown, Some(-5));
1960 assert!(af.pcr.is_none());
1961 }
1962
1963 #[test]
1966 fn scrambling_control_all_values() {
1967 assert_eq!(
1968 ScramblingControl::from_bits(0b00),
1969 ScramblingControl::NotScrambled
1970 );
1971 assert_eq!(
1972 ScramblingControl::from_bits(0b01),
1973 ScramblingControl::Reserved
1974 );
1975 assert_eq!(
1976 ScramblingControl::from_bits(0b10),
1977 ScramblingControl::EvenKey
1978 );
1979 assert_eq!(
1980 ScramblingControl::from_bits(0b11),
1981 ScramblingControl::OddKey
1982 );
1983 assert_eq!(ScramblingControl::NotScrambled.name(), "not_scrambled");
1985 assert_eq!(ScramblingControl::Reserved.name(), "reserved");
1986 assert_eq!(ScramblingControl::EvenKey.name(), "even_key");
1987 assert_eq!(ScramblingControl::OddKey.name(), "odd_key");
1988 assert_eq!(ScramblingControl::NotScrambled.to_string(), "not_scrambled");
1990 assert_eq!(ScramblingControl::OddKey.to_string(), "odd_key");
1991 assert_eq!(
1993 ScramblingControl::from_bits(0xFF),
1994 ScramblingControl::OddKey
1995 );
1996 }
1997
1998 #[test]
1999 fn adaptation_field_control_all_values() {
2000 assert_eq!(
2001 AdaptationFieldControl::from_flags(false, false),
2002 AdaptationFieldControl::Reserved
2003 );
2004 assert_eq!(
2005 AdaptationFieldControl::from_flags(false, true),
2006 AdaptationFieldControl::PayloadOnly
2007 );
2008 assert_eq!(
2009 AdaptationFieldControl::from_flags(true, false),
2010 AdaptationFieldControl::AdaptationOnly
2011 );
2012 assert_eq!(
2013 AdaptationFieldControl::from_flags(true, true),
2014 AdaptationFieldControl::AdaptationAndPayload
2015 );
2016 assert_eq!(AdaptationFieldControl::Reserved.name(), "reserved");
2018 assert_eq!(AdaptationFieldControl::PayloadOnly.name(), "payload_only");
2019 assert_eq!(
2020 AdaptationFieldControl::AdaptationOnly.name(),
2021 "adaptation_only"
2022 );
2023 assert_eq!(
2024 AdaptationFieldControl::AdaptationAndPayload.name(),
2025 "adaptation_and_payload"
2026 );
2027 assert_eq!(
2029 AdaptationFieldControl::PayloadOnly.to_string(),
2030 "payload_only"
2031 );
2032 }
2033
2034 #[test]
2035 fn ts_header_scrambling_control_accessor() {
2036 let hdr = TsHeader {
2037 tei: false,
2038 pusi: false,
2039 pid: Pid::new(0x0100),
2040 scrambling: 0b10,
2041 has_adaptation: false,
2042 has_payload: true,
2043 continuity_counter: 0,
2044 };
2045 assert_eq!(hdr.scrambling_control(), ScramblingControl::EvenKey);
2046 }
2047
2048 #[test]
2049 fn ts_header_adaptation_field_control_accessor() {
2050 let hdr_payload_only = TsHeader {
2051 tei: false,
2052 pusi: false,
2053 pid: Pid::new(0x0100),
2054 scrambling: 0,
2055 has_adaptation: false,
2056 has_payload: true,
2057 continuity_counter: 0,
2058 };
2059 assert_eq!(
2060 hdr_payload_only.adaptation_field_control(),
2061 AdaptationFieldControl::PayloadOnly
2062 );
2063
2064 let hdr_both = TsHeader {
2065 tei: false,
2066 pusi: false,
2067 pid: Pid::new(0x0100),
2068 scrambling: 0,
2069 has_adaptation: true,
2070 has_payload: true,
2071 continuity_counter: 0,
2072 };
2073 assert_eq!(
2074 hdr_both.adaptation_field_control(),
2075 AdaptationFieldControl::AdaptationAndPayload
2076 );
2077 }
2078
2079 #[test]
2082 fn iter_packets_yields_valid_and_skips_bad_sync() {
2083 let pkt1 = make_packet(0x00, 0x00, PAYLOAD_FLAG, &[0xAA; 10]);
2085 let pkt2 = make_packet(0x40, 0x64, PAYLOAD_FLAG, &[0xBB; 10]);
2086 let mut bad = [0u8; TS_PACKET_SIZE];
2087 bad[0] = 0x00; let mut buf = Vec::new();
2090 buf.extend_from_slice(&pkt1);
2091 buf.extend_from_slice(&pkt2);
2092 buf.extend_from_slice(&bad);
2093
2094 let pkts: Vec<_> = super::iter_packets(&buf).collect();
2095 assert_eq!(pkts.len(), 2, "bad sync packet must be skipped");
2096 assert_eq!(pkts[0].header.pid, Pid::new(0x0000));
2097 assert_eq!(pkts[1].header.pid, Pid::new(0x0064));
2098 }
2099
2100 #[test]
2101 fn extract_ts_payload_payload_only() {
2102 let pkt = make_packet(0x00, 0x00, PAYLOAD_FLAG, &[0xABu8; 10]);
2103 let p = super::extract_ts_payload(&pkt).expect("payload present");
2104 assert_eq!(p[0], 0xAB);
2105 assert_eq!(p.len(), TS_PACKET_SIZE - 4);
2106 }
2107
2108 #[test]
2109 fn extract_ts_payload_adaptation_only_returns_none() {
2110 let pkt = make_packet(0x00, 0x00, ADAPTATION_FLAG, &[]);
2111 assert!(super::extract_ts_payload(&pkt).is_none());
2112 }
2113
2114 #[test]
2119 fn pcr_from_27mhz_round_trips() {
2120 for &ticks in &[0u64, 1, 300, 27_000_000, u64::from(u32::MAX), 8_589_934_591] {
2121 let pcr = Pcr::from_27mhz(ticks);
2122 assert_eq!(pcr.as_27mhz(), ticks, "ticks={ticks}");
2123 }
2124 }
2125
2126 #[test]
2128 fn pcr_to_field_bytes_round_trips_parse() {
2129 let cases = [
2130 Pcr {
2131 base: 0,
2132 extension: 0,
2133 },
2134 Pcr {
2135 base: 10_000,
2136 extension: 0,
2137 },
2138 Pcr {
2139 base: 1,
2140 extension: 100,
2141 },
2142 Pcr {
2143 base: 0x1_FFFF_FFFF,
2144 extension: 0x1FF,
2145 },
2146 ];
2147 for pcr in cases {
2148 let bytes = pcr.to_field_bytes();
2149 let mut af = [0u8; 7];
2152 af[1..7].copy_from_slice(&bytes);
2153 let decoded = Pcr::parse(&af, 1).expect("parse round-trip");
2154 assert_eq!(decoded, pcr, "round-trip failed for {pcr:?}");
2155 }
2156 }
2157
2158 #[test]
2161 fn pcr_to_field_bytes_known_vector() {
2162 let pcr = Pcr {
2163 base: 10_000,
2164 extension: 0,
2165 };
2166 let bytes = pcr.to_field_bytes();
2167 assert_eq!(bytes, [0x00, 0x00, 0x13, 0x88, 0x7E, 0x00]);
2168 }
2169
2170 #[test]
2173 fn scrambling_control_to_bits_inverse_of_from_bits() {
2174 for bits in 0u8..=3 {
2175 let sc = ScramblingControl::from_bits(bits);
2176 assert_eq!(sc.to_bits(), bits, "to_bits() != from_bits() for {bits}");
2177 }
2178 }
2179
2180 #[test]
2183 fn adaptation_field_control_to_bits_inverse_of_from_flags() {
2184 let cases = [
2185 (false, false, 0b00u8),
2186 (false, true, 0b01),
2187 (true, false, 0b10),
2188 (true, true, 0b11),
2189 ];
2190 for (has_af, has_pl, expected_bits) in cases {
2191 let afc = AdaptationFieldControl::from_flags(has_af, has_pl);
2192 assert_eq!(afc.to_bits(), expected_bits);
2193 assert_eq!(afc.to_flags(), (has_af, has_pl));
2194 }
2195 }
2196
2197 #[test]
2201 fn adaptation_field_serialize_round_trip_with_pcr() {
2202 let original = AdaptationField {
2203 discontinuity_indicator: true,
2204 random_access_indicator: false,
2205 elementary_stream_priority_indicator: false,
2206 pcr: Some(Pcr {
2207 base: 10_000,
2208 extension: 0,
2209 }),
2210 opcr: None,
2211 splice_countdown: None,
2212 transport_private_data: None,
2213 extension: None,
2214 stuffing: &[],
2215 pcr_reserved: PCR_RESERVED_VALUE,
2216 opcr_reserved: PCR_RESERVED_VALUE,
2217 };
2218 let len = original.serialized_len();
2219 assert_eq!(len, 7); let mut buf = vec![0u8; len];
2221 let written = original.serialize_into(&mut buf).expect("serialize");
2222 assert_eq!(written, len);
2223 let decoded = AdaptationField::parse(&buf).expect("parse round-trip");
2224 assert_eq!(decoded, original);
2225 }
2226
2227 #[test]
2231 fn transport_private_data_over_255_bytes_rejected_not_wrapped() {
2232 let data = vec![0u8; 256];
2233 let af = AdaptationField {
2234 discontinuity_indicator: false,
2235 random_access_indicator: false,
2236 elementary_stream_priority_indicator: false,
2237 pcr: None,
2238 opcr: None,
2239 splice_countdown: None,
2240 transport_private_data: Some(&data),
2241 extension: None,
2242 stuffing: &[],
2243 pcr_reserved: PCR_RESERVED_VALUE,
2244 opcr_reserved: PCR_RESERVED_VALUE,
2245 };
2246 let mut buf = vec![0u8; af.serialized_len()];
2247 assert!(matches!(
2248 &(af.serialize_into(&mut buf)),
2249 Err(crate::error::Error::FieldOverflow(_))
2250 ));
2251 }
2252
2253 #[test]
2255 fn adaptation_field_serialize_produces_known_bytes() {
2256 let af = AdaptationField {
2260 discontinuity_indicator: true,
2261 random_access_indicator: false,
2262 elementary_stream_priority_indicator: false,
2263 pcr: Some(Pcr {
2264 base: 10_000,
2265 extension: 0,
2266 }),
2267 opcr: None,
2268 splice_countdown: None,
2269 transport_private_data: None,
2270 extension: None,
2271 stuffing: &[],
2272 pcr_reserved: PCR_RESERVED_VALUE,
2273 opcr_reserved: PCR_RESERVED_VALUE,
2274 };
2275 let mut buf = [0u8; 7];
2276 af.serialize_into(&mut buf).unwrap();
2277 assert_eq!(buf[0], AF_DISCONTINUITY | AF_PCR_FLAG);
2278 assert_eq!(&buf[1..7], &[0x00, 0x00, 0x13, 0x88, 0x7E, 0x00]);
2279 }
2280
2281 #[test]
2283 fn adaptation_field_serialize_round_trip_opcr_and_splice() {
2284 let original = AdaptationField {
2285 discontinuity_indicator: false,
2286 random_access_indicator: true,
2287 elementary_stream_priority_indicator: true,
2288 pcr: Some(Pcr {
2289 base: 1,
2290 extension: 100,
2291 }),
2292 opcr: Some(Pcr {
2293 base: 999,
2294 extension: 5,
2295 }),
2296 splice_countdown: Some(-3),
2297 transport_private_data: None,
2298 extension: None,
2299 stuffing: &[],
2300 pcr_reserved: PCR_RESERVED_VALUE,
2301 opcr_reserved: PCR_RESERVED_VALUE,
2302 };
2303 let len = original.serialized_len();
2304 assert_eq!(len, 1 + 6 + 6 + 1); let mut buf = vec![0u8; len];
2306 original.serialize_into(&mut buf).unwrap();
2307 let decoded = AdaptationField::parse(&buf).expect("parse");
2308 assert_eq!(decoded, original);
2309 }
2310
2311 #[test]
2313 fn adaptation_field_serialize_flags_only() {
2314 let af = AdaptationField {
2315 discontinuity_indicator: false,
2316 random_access_indicator: true,
2317 elementary_stream_priority_indicator: false,
2318 pcr: None,
2319 opcr: None,
2320 splice_countdown: None,
2321 transport_private_data: None,
2322 extension: None,
2323 stuffing: &[],
2324 pcr_reserved: PCR_RESERVED_VALUE,
2325 opcr_reserved: PCR_RESERVED_VALUE,
2326 };
2327 assert_eq!(af.serialized_len(), 1);
2328 let mut buf = [0u8; 1];
2329 af.serialize_into(&mut buf).unwrap();
2330 assert_eq!(buf[0], AF_RANDOM_ACCESS);
2331 let decoded = AdaptationField::parse(&buf).unwrap();
2332 assert_eq!(decoded, af);
2333 }
2334
2335 #[test]
2337 fn adaptation_field_serialize_rejects_small_buffer() {
2338 let af = AdaptationField {
2339 discontinuity_indicator: false,
2340 random_access_indicator: false,
2341 elementary_stream_priority_indicator: false,
2342 pcr: Some(Pcr {
2343 base: 0,
2344 extension: 0,
2345 }),
2346 opcr: None,
2347 splice_countdown: None,
2348 transport_private_data: None,
2349 extension: None,
2350 stuffing: &[],
2351 pcr_reserved: PCR_RESERVED_VALUE,
2352 opcr_reserved: PCR_RESERVED_VALUE,
2353 };
2354 let mut buf = [0u8; 3]; assert!(matches!(
2356 af.serialize_into(&mut buf),
2357 Err(Error::OutputBufferTooSmall(..))
2358 ));
2359 }
2360
2361 #[test]
2365 fn adaptation_field_extension_ltw_round_trip() {
2366 let ext = AdaptationFieldExtension {
2367 ltw: Some(Ltw {
2368 ltw_valid_flag: true,
2369 ltw_offset: 0x1234,
2370 }),
2371 piecewise_rate: None,
2372 seamless_splice: None,
2373 ..AdaptationFieldExtension::new()
2374 };
2375 let mut buf = vec![0u8; ext.serialized_len()];
2376 ext.serialize_into(&mut buf).unwrap();
2377 let af = AdaptationField {
2380 discontinuity_indicator: false,
2381 random_access_indicator: false,
2382 elementary_stream_priority_indicator: false,
2383 pcr: None,
2384 opcr: None,
2385 splice_countdown: None,
2386 transport_private_data: None,
2387 extension: Some(ext),
2388 stuffing: &[],
2389 pcr_reserved: PCR_RESERVED_VALUE,
2390 opcr_reserved: PCR_RESERVED_VALUE,
2391 };
2392 let len = af.serialized_len();
2393 let mut abuf = vec![0u8; len];
2394 af.serialize_into(&mut abuf).unwrap();
2395 let decoded = AdaptationField::parse(&abuf).unwrap();
2396 assert_eq!(decoded.extension, Some(ext));
2397 }
2398
2399 #[test]
2401 fn adaptation_field_extension_piecewise_rate_round_trip() {
2402 let af = AdaptationField {
2403 discontinuity_indicator: false,
2404 random_access_indicator: false,
2405 elementary_stream_priority_indicator: false,
2406 pcr: None,
2407 opcr: None,
2408 splice_countdown: None,
2409 transport_private_data: None,
2410 extension: Some(AdaptationFieldExtension {
2411 ltw: None,
2412 piecewise_rate: Some(0x3FFFFF), seamless_splice: None,
2414 ..AdaptationFieldExtension::new()
2415 }),
2416 stuffing: &[],
2417 pcr_reserved: PCR_RESERVED_VALUE,
2418 opcr_reserved: PCR_RESERVED_VALUE,
2419 };
2420 let mut buf = vec![0u8; af.serialized_len()];
2421 af.serialize_into(&mut buf).unwrap();
2422 let decoded = AdaptationField::parse(&buf).unwrap();
2423 assert_eq!(decoded.extension.unwrap().piecewise_rate, Some(0x3FFFFF));
2424 }
2425
2426 #[test]
2428 fn adaptation_field_extension_seamless_splice_round_trip() {
2429 let af = AdaptationField {
2430 discontinuity_indicator: false,
2431 random_access_indicator: false,
2432 elementary_stream_priority_indicator: false,
2433 pcr: None,
2434 opcr: None,
2435 splice_countdown: None,
2436 transport_private_data: None,
2437 extension: Some(AdaptationFieldExtension {
2438 ltw: None,
2439 piecewise_rate: None,
2440 seamless_splice: Some(SeamlessSplice::new(0xA, 0x1_2345_6789)),
2441 ..AdaptationFieldExtension::new()
2442 }),
2443 stuffing: &[],
2444 pcr_reserved: PCR_RESERVED_VALUE,
2445 opcr_reserved: PCR_RESERVED_VALUE,
2446 };
2447 let mut buf = vec![0u8; af.serialized_len()];
2448 af.serialize_into(&mut buf).unwrap();
2449 let decoded = AdaptationField::parse(&buf).unwrap();
2450 let ss = decoded.extension.unwrap().seamless_splice.unwrap();
2451 assert_eq!(ss.splice_type, 0xA);
2452 assert_eq!(ss.dts_next_au, 0x1_2345_6789);
2453 }
2454
2455 #[test]
2457 fn adaptation_field_transport_private_data_round_trip() {
2458 let tpd = [0xDE, 0xAD, 0xBE, 0xEF];
2459 let af = AdaptationField {
2460 discontinuity_indicator: false,
2461 random_access_indicator: false,
2462 elementary_stream_priority_indicator: false,
2463 pcr: None,
2464 opcr: None,
2465 splice_countdown: None,
2466 transport_private_data: Some(&tpd),
2467 extension: None,
2468 stuffing: &[],
2469 pcr_reserved: PCR_RESERVED_VALUE,
2470 opcr_reserved: PCR_RESERVED_VALUE,
2471 };
2472 let mut buf = vec![0u8; af.serialized_len()];
2473 af.serialize_into(&mut buf).unwrap();
2474 let decoded = AdaptationField::parse(&buf).unwrap();
2475 assert_eq!(decoded.transport_private_data, Some(tpd.as_slice()));
2476 }
2477
2478 #[test]
2481 fn adaptation_field_stuffing_round_trip() {
2482 let af = AdaptationField {
2483 discontinuity_indicator: false,
2484 random_access_indicator: false,
2485 elementary_stream_priority_indicator: false,
2486 pcr: Some(Pcr {
2487 base: 12_345,
2488 extension: 7,
2489 }),
2490 opcr: None,
2491 splice_countdown: None,
2492 transport_private_data: None,
2493 extension: None,
2494 stuffing: &[0xFF; 20],
2495 pcr_reserved: PCR_RESERVED_VALUE,
2496 opcr_reserved: PCR_RESERVED_VALUE,
2497 };
2498 assert_eq!(af.serialized_len(), 27);
2500 let mut buf = vec![0u8; af.serialized_len()];
2501 af.serialize_into(&mut buf).unwrap();
2502 assert!(buf[7..27].iter().all(|&b| b == 0xFF));
2504 let decoded = AdaptationField::parse(&buf).unwrap();
2505 assert_eq!(decoded.stuffing.len(), 20);
2506 assert_eq!(decoded, af);
2507 let pure = AdaptationField {
2509 discontinuity_indicator: false,
2510 random_access_indicator: false,
2511 elementary_stream_priority_indicator: false,
2512 pcr: None,
2513 opcr: None,
2514 splice_countdown: None,
2515 transport_private_data: None,
2516 extension: None,
2517 stuffing: &[0xFF; 5],
2518 pcr_reserved: PCR_RESERVED_VALUE,
2519 opcr_reserved: PCR_RESERVED_VALUE,
2520 };
2521 let mut pbuf = vec![0u8; pure.serialized_len()];
2522 pure.serialize_into(&mut pbuf).unwrap();
2523 assert_eq!(pbuf, vec![0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]);
2524 assert_eq!(AdaptationField::parse(&pbuf).unwrap(), pure);
2525 }
2526
2527 #[test]
2529 fn adaptation_field_all_fields_round_trip() {
2530 let tpd = [0x01u8, 0x02, 0x03];
2531 let af = AdaptationField {
2532 discontinuity_indicator: true,
2533 random_access_indicator: false,
2534 elementary_stream_priority_indicator: false,
2535 pcr: Some(Pcr {
2536 base: 90_000,
2537 extension: 50,
2538 }),
2539 opcr: None,
2540 splice_countdown: Some(10),
2541 transport_private_data: Some(&tpd),
2542 extension: Some(AdaptationFieldExtension {
2543 ltw: Some(Ltw {
2544 ltw_valid_flag: false,
2545 ltw_offset: 500,
2546 }),
2547 piecewise_rate: Some(12345),
2548 seamless_splice: None,
2549 ..AdaptationFieldExtension::new()
2550 }),
2551 stuffing: &[],
2552 pcr_reserved: PCR_RESERVED_VALUE,
2553 opcr_reserved: PCR_RESERVED_VALUE,
2554 };
2555 let len = af.serialized_len();
2556 let mut buf = vec![0u8; len];
2557 af.serialize_into(&mut buf).unwrap();
2558 let decoded = AdaptationField::parse(&buf).unwrap();
2559 assert_eq!(decoded.pcr, af.pcr);
2560 assert_eq!(decoded.splice_countdown, af.splice_countdown);
2561 assert_eq!(decoded.transport_private_data, af.transport_private_data);
2562 assert_eq!(decoded.extension, af.extension);
2563 assert!(decoded.discontinuity_indicator);
2564 }
2565
2566 #[test]
2569 fn adaptation_field_serialize_from_real_packet_bytes() {
2570 let mut raw = [0xAAu8; TS_PACKET_SIZE];
2572 raw[0] = TS_SYNC_BYTE;
2573 raw[1] = 0x01;
2574 raw[2] = 0x00;
2575 raw[3] = ADAPTATION_FLAG | PAYLOAD_FLAG;
2576 raw[4] = 7;
2577 raw[5] = AF_DISCONTINUITY | AF_PCR_FLAG;
2578 raw[6..12].copy_from_slice(&[0x00, 0x00, 0x13, 0x88, 0x7E, 0x00]);
2579
2580 let pkt = TsPacket::parse(&raw).unwrap();
2581 let af = pkt.adaptation_field().unwrap().unwrap();
2582
2583 let mut ser = vec![0u8; af.serialized_len()];
2585 af.serialize_into(&mut ser).unwrap();
2586 let decoded = AdaptationField::parse(&ser).unwrap();
2587 assert_eq!(
2588 decoded.pcr,
2589 Some(Pcr {
2590 base: 10_000,
2591 extension: 0
2592 })
2593 );
2594 assert!(decoded.discontinuity_indicator);
2595 }
2596}