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;
11const MAX_SECTION_SIZE: usize = 4098;
16const SECTION_HEADER_LEN: usize = 3;
20pub(crate) const SECTION_LENGTH_HI_MASK: u8 = 0x0F;
24
25pub(crate) const STUFFING_BYTE: u8 = 0xFF;
27
28pub(crate) fn section_total_len(bytes: &[u8]) -> Option<usize> {
37 if bytes.len() < SECTION_HEADER_LEN {
38 return None;
39 }
40 let section_length = ((bytes[1] & SECTION_LENGTH_HI_MASK) as usize) << 8 | bytes[2] as usize;
41 Some(SECTION_HEADER_LEN + section_length)
42}
43
44#[non_exhaustive]
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54#[cfg_attr(feature = "serde", derive(serde::Serialize))]
55pub enum ScramblingControl {
56 NotScrambled,
58 Reserved,
60 EvenKey,
63 OddKey,
66}
67
68impl ScramblingControl {
69 pub fn from_bits(bits: u8) -> Self {
71 match bits & 0b11 {
72 0b00 => Self::NotScrambled,
73 0b01 => Self::Reserved,
74 0b10 => Self::EvenKey,
75 0b11 => Self::OddKey,
76 _ => unreachable!(),
77 }
78 }
79
80 pub fn to_bits(self) -> u8 {
85 match self {
86 Self::NotScrambled => 0b00,
87 Self::Reserved => 0b01,
88 Self::EvenKey => 0b10,
89 Self::OddKey => 0b11,
90 }
91 }
92
93 pub fn name(&self) -> &'static str {
95 match self {
96 Self::NotScrambled => "not_scrambled",
97 Self::Reserved => "reserved",
98 Self::EvenKey => "even_key",
99 Self::OddKey => "odd_key",
100 }
101 }
102}
103
104broadcast_common::impl_spec_display!(ScramblingControl);
105
106#[non_exhaustive]
112#[derive(Debug, Clone, Copy, PartialEq, Eq)]
113#[cfg_attr(feature = "serde", derive(serde::Serialize))]
114pub enum AdaptationFieldControl {
115 Reserved,
117 PayloadOnly,
119 AdaptationOnly,
121 AdaptationAndPayload,
123}
124
125impl AdaptationFieldControl {
126 pub fn from_flags(has_adaptation: bool, has_payload: bool) -> Self {
128 match (has_adaptation, has_payload) {
129 (false, false) => Self::Reserved,
130 (false, true) => Self::PayloadOnly,
131 (true, false) => Self::AdaptationOnly,
132 (true, true) => Self::AdaptationAndPayload,
133 }
134 }
135
136 pub fn to_flags(self) -> (bool, bool) {
139 match self {
140 Self::Reserved => (false, false),
141 Self::PayloadOnly => (false, true),
142 Self::AdaptationOnly => (true, false),
143 Self::AdaptationAndPayload => (true, true),
144 }
145 }
146
147 pub fn to_bits(self) -> u8 {
153 match self {
154 Self::Reserved => 0b00,
155 Self::PayloadOnly => 0b01,
156 Self::AdaptationOnly => 0b10,
157 Self::AdaptationAndPayload => 0b11,
158 }
159 }
160
161 pub fn name(&self) -> &'static str {
163 match self {
164 Self::Reserved => "reserved",
165 Self::PayloadOnly => "payload_only",
166 Self::AdaptationOnly => "adaptation_only",
167 Self::AdaptationAndPayload => "adaptation_and_payload",
168 }
169 }
170}
171
172broadcast_common::impl_spec_display!(AdaptationFieldControl);
173
174const TEI_MASK: u8 = 0x80;
176const PUSI_MASK: u8 = 0x40;
178pub const PID_MASK_HI: u8 = 0x1F;
180pub const SCRAMBLING_MASK: u8 = 0xC0;
182pub const ADAPTATION_FLAG: u8 = 0x20;
184pub const PAYLOAD_FLAG: u8 = 0x10;
186pub const CC_MASK: u8 = 0x0F;
188
189#[derive(Clone, Debug, PartialEq, Eq)]
191#[cfg_attr(feature = "serde", derive(serde::Serialize))]
192pub struct TsHeader {
193 pub tei: bool,
196 pub pusi: bool,
199 pub pid: Pid,
201 pub scrambling: u8,
203 pub has_adaptation: bool,
205 pub has_payload: bool,
207 pub continuity_counter: u8,
209}
210
211#[derive(Clone, Debug)]
217#[cfg_attr(feature = "serde", derive(serde::Serialize))]
218pub struct TsPacket<'a> {
219 pub header: TsHeader,
221 pub payload: Option<&'a [u8]>,
224 #[cfg_attr(feature = "serde", serde(skip))]
227 adaptation: Option<&'a [u8]>,
228 #[cfg_attr(feature = "serde", serde(skip))]
230 pub raw: &'a [u8; TS_PACKET_SIZE],
231}
232
233impl TsHeader {
234 pub fn parse(raw4: &[u8]) -> Result<Self> {
236 need_in(raw4, 4, "TsHeader")?;
237 let b1 = raw4[1];
238 let b2 = raw4[2];
239 let b3 = raw4[3];
240
241 let tei = (b1 & TEI_MASK) != 0;
242 let pusi = (b1 & PUSI_MASK) != 0;
243 let pid = Pid::new((((b1 & PID_MASK_HI) as u16) << 8) | (b2 as u16));
244 let scrambling = (b3 & SCRAMBLING_MASK) >> 6;
245 let has_adaptation = (b3 & ADAPTATION_FLAG) != 0;
246 let has_payload = (b3 & PAYLOAD_FLAG) != 0;
247 let continuity_counter = b3 & CC_MASK;
248
249 Ok(Self {
250 tei,
251 pusi,
252 pid,
253 scrambling,
254 has_adaptation,
255 has_payload,
256 continuity_counter,
257 })
258 }
259
260 pub const fn serialized_len() -> usize {
262 4
263 }
264
265 pub fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
267 need_out(buf, 4)?;
268 buf[0] = TS_SYNC_BYTE;
269 buf[1] = 0;
270 if self.tei {
271 buf[1] |= TEI_MASK;
272 }
273 if self.pusi {
274 buf[1] |= PUSI_MASK;
275 }
276 let pid = self.pid.value();
277 buf[1] |= ((pid >> 8) as u8) & PID_MASK_HI;
278 buf[2] = pid.to_be_bytes()[1];
279 buf[3] = (self.scrambling << 6) & SCRAMBLING_MASK;
280 if self.has_adaptation {
281 buf[3] |= ADAPTATION_FLAG;
282 }
283 if self.has_payload {
284 buf[3] |= PAYLOAD_FLAG;
285 }
286 buf[3] |= self.continuity_counter & CC_MASK;
287 Ok(4)
288 }
289
290 pub fn scrambling_control(&self) -> ScramblingControl {
295 ScramblingControl::from_bits(self.scrambling)
296 }
297
298 pub fn adaptation_field_control(&self) -> AdaptationFieldControl {
303 AdaptationFieldControl::from_flags(self.has_adaptation, self.has_payload)
304 }
305}
306
307impl<'a> broadcast_common::Parse<'a> for TsHeader {
308 type Error = Error;
309
310 fn parse(bytes: &'a [u8]) -> Result<Self> {
311 TsHeader::parse(bytes)
312 }
313}
314
315impl broadcast_common::Serialize for TsHeader {
316 type Error = Error;
317
318 fn serialized_len(&self) -> usize {
319 TsHeader::serialized_len()
320 }
321
322 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
323 TsHeader::serialize_into(self, buf)
324 }
325}
326
327fn adaptation_field_skip(pkt: &[u8], has_adaptation: bool) -> usize {
338 if !has_adaptation || pkt.len() <= 4 {
339 return 0;
340 }
341 let af_len = pkt[4] as usize;
342 1 + af_len
343}
344
345impl<'a> TsPacket<'a> {
346 pub fn parse(buf: &'a [u8]) -> Result<Self> {
352 need_in(buf, TS_PACKET_SIZE, "TsPacket")?;
353 if buf[0] != TS_SYNC_BYTE {
354 return Err(Error::InvalidSync(broadcast_common::error::InvalidSync {
355 what: "TS sync byte",
356 expected: u32::from(TS_SYNC_BYTE),
357 found: u32::from(buf[0]),
358 }));
359 }
360
361 let raw: &[u8; TS_PACKET_SIZE] = buf[..TS_PACKET_SIZE].try_into().map_err(|_| {
362 Error::BufferTooShort(broadcast_common::error::BufferTooShort {
363 need: TS_PACKET_SIZE,
364 have: buf.len(),
365 what: "TsPacket::parse (array conversion)",
366 })
367 })?;
368
369 let header = TsHeader::parse(&raw[..4])?;
370
371 let mut cursor = 4usize;
372 let mut payload = None;
373 let mut adaptation = None;
374
375 if header.has_adaptation && cursor < TS_PACKET_SIZE {
388 let af_len = raw[cursor] as usize;
389 let af_start = cursor + 1;
390 if af_len > 0 && af_start < TS_PACKET_SIZE && af_start + af_len <= TS_PACKET_SIZE {
391 adaptation = Some(&raw[af_start..af_start + af_len]);
392 }
393 }
394 cursor += adaptation_field_skip(raw, header.has_adaptation);
399
400 if header.has_payload && cursor < TS_PACKET_SIZE {
401 payload = Some(&raw[cursor..]);
402 }
403
404 Ok(TsPacket {
405 header,
406 payload,
407 adaptation,
408 raw,
409 })
410 }
411
412 pub fn adaptation_field(&self) -> Option<crate::Result<AdaptationField<'a>>> {
418 self.adaptation.map(AdaptationField::parse)
419 }
420}
421
422pub(crate) const AF_DISCONTINUITY: u8 = 0x80;
424pub(crate) const AF_RANDOM_ACCESS: u8 = 0x40;
425pub(crate) const AF_ES_PRIORITY: u8 = 0x20;
426pub const AF_PCR_FLAG: u8 = 0x10;
428pub(crate) const AF_OPCR_FLAG: u8 = 0x08;
429pub(crate) const AF_SPLICING_FLAG: u8 = 0x04;
430pub(crate) const AF_TRANSPORT_PRIVATE_DATA_FLAG: u8 = 0x02;
431pub(crate) const AF_EXTENSION_FLAG: u8 = 0x01;
432const PCR_RESERVED_BITS: u8 = 0x7E;
435const PCR_RESERVED_SHIFT: u32 = 1;
437const PCR_RESERVED_VALUE: u8 = 0x3F;
439pub(crate) const PCR_FIELD_LEN: usize = 6;
441
442#[derive(Clone, Copy, Debug, PartialEq, Eq)]
445#[cfg_attr(feature = "serde", derive(serde::Serialize))]
446pub struct Pcr {
447 pub base: u64,
449 pub extension: u16,
451}
452
453impl Pcr {
454 #[must_use]
458 pub fn as_27mhz(self) -> u64 {
459 broadcast_common::clock33::pcr_from_parts(self.base, self.extension)
460 }
461
462 #[must_use]
471 pub fn from_27mhz(ticks: u64) -> Self {
472 let (base, extension) = broadcast_common::clock33::pcr_split(ticks);
473 Self { base, extension }
474 }
475
476 #[must_use]
485 pub fn to_field_bytes(self) -> [u8; PCR_FIELD_LEN] {
486 let b = self.base;
487 let e = self.extension as u64;
488 [
489 ((b >> 25) & 0xFF) as u8,
490 ((b >> 17) & 0xFF) as u8,
491 ((b >> 9) & 0xFF) as u8,
492 ((b >> 1) & 0xFF) as u8,
493 (((b & 0x01) as u8) << 7) | PCR_RESERVED_BITS | ((e >> 8) as u8 & 0x01),
495 (e & 0xFF) as u8,
496 ]
497 }
498
499 pub(crate) fn parse(af: &[u8], at: usize) -> Result<Self> {
501 let b: &[u8; PCR_FIELD_LEN] = af
502 .get(at..at + PCR_FIELD_LEN)
503 .and_then(|s| s.try_into().ok())
504 .ok_or(Error::BufferTooShort(
505 broadcast_common::error::BufferTooShort {
506 need: at + PCR_FIELD_LEN,
507 have: af.len(),
508 what: "adaptation_field PCR",
509 },
510 ))?;
511 let base = ((b[0] as u64) << 25)
512 | ((b[1] as u64) << 17)
513 | ((b[2] as u64) << 9)
514 | ((b[3] as u64) << 1)
515 | ((b[4] as u64) >> 7);
516 let extension = (((b[4] & 0x01) as u16) << 8) | (b[5] as u16);
517 Ok(Self { base, extension })
518 }
519}
520
521#[derive(Clone, Copy, Debug, PartialEq, Eq)]
528#[cfg_attr(feature = "serde", derive(serde::Serialize))]
529pub struct Ltw {
530 pub ltw_valid_flag: bool,
532 pub ltw_offset: u16,
534}
535
536#[non_exhaustive]
545#[derive(Clone, Copy, Debug, PartialEq, Eq)]
546#[cfg_attr(feature = "serde", derive(serde::Serialize))]
547pub struct SeamlessSplice {
548 pub splice_type: u8,
550 pub dts_next_au: u64,
552 pub marker_bits: u8,
557}
558
559impl SeamlessSplice {
560 #[must_use]
562 pub const fn new(splice_type: u8, dts_next_au: u64) -> Self {
563 Self {
564 splice_type,
565 dts_next_au,
566 marker_bits: SPLICE_MARKERS_VALUE,
567 }
568 }
569}
570
571const SPLICE_MARKERS_VALUE: u8 = 0x07;
575const AFE_LTW_FLAG: u8 = 0x80;
576const AFE_PIECEWISE_RATE_FLAG: u8 = 0x40;
577const AFE_SEAMLESS_SPLICE_FLAG: u8 = 0x20;
578const LTW_OFFSET_HI_MASK: u8 = 0x7F;
580const PIECEWISE_RATE_HI_MASK: u8 = 0x3F;
582const AFE_AF_DESCRIPTOR_NOT_PRESENT_FLAG: u8 = 0x10;
584const AFE_RESERVED_FLAGS_MASK: u8 = 0x0F;
586const AFE_RESERVED_FLAGS_VALUE: u8 = 0x0F;
588const PIECEWISE_RATE_RESERVED_SHIFT: u32 = 6;
590const PIECEWISE_RATE_RESERVED_VALUE: u8 = 0x03;
592
593#[non_exhaustive]
613#[derive(Clone, Copy, Debug, PartialEq, Eq)]
614#[cfg_attr(feature = "serde", derive(serde::Serialize))]
615pub struct AdaptationFieldExtension<'a> {
616 pub ltw: Option<Ltw>,
618 pub piecewise_rate: Option<u32>,
620 pub piecewise_rate_reserved: u8,
623 pub seamless_splice: Option<SeamlessSplice>,
625 pub af_descriptor_not_present_flag: bool,
629 pub reserved_flags: u8,
631 pub trailing: &'a [u8],
635}
636
637impl Default for AdaptationFieldExtension<'_> {
638 fn default() -> Self {
639 Self::new()
640 }
641}
642
643impl<'a> AdaptationFieldExtension<'a> {
644 #[must_use]
647 pub const fn new() -> Self {
648 Self {
649 ltw: None,
650 piecewise_rate: None,
651 piecewise_rate_reserved: PIECEWISE_RATE_RESERVED_VALUE,
652 seamless_splice: None,
653 af_descriptor_not_present_flag: true,
654 reserved_flags: AFE_RESERVED_FLAGS_VALUE,
655 trailing: &[],
656 }
657 }
658
659 fn parse(data: &'a [u8]) -> Result<Self> {
662 need_in(data, 1, "adaptation_field_extension_length")?;
663 let ext_len = data[0] as usize;
664 if data.len() < 1 + ext_len || ext_len < 1 {
666 return Err(Error::BufferTooShort(
667 broadcast_common::error::BufferTooShort {
668 need: 2.max(1 + ext_len),
669 have: data.len(),
670 what: "adaptation_field_extension body",
671 },
672 ));
673 }
674 let ext = &data[1..1 + ext_len]; let flags = ext[0];
676 let mut cursor = 1usize;
677
678 let ltw = if flags & AFE_LTW_FLAG != 0 {
679 need_in(ext, cursor + 2, "ltw_offset")?;
680 let w0 = ext[cursor];
681 let w1 = ext[cursor + 1];
682 cursor += 2;
683 Some(Ltw {
684 ltw_valid_flag: (w0 & AFE_LTW_FLAG) != 0,
685 ltw_offset: (((w0 & LTW_OFFSET_HI_MASK) as u16) << 8) | (w1 as u16),
686 })
687 } else {
688 None
689 };
690
691 let mut piecewise_rate_reserved = PIECEWISE_RATE_RESERVED_VALUE;
692 let piecewise_rate = if flags & AFE_PIECEWISE_RATE_FLAG != 0 {
693 need_in(ext, cursor + 3, "piecewise_rate")?;
694 piecewise_rate_reserved = ext[cursor] >> PIECEWISE_RATE_RESERVED_SHIFT;
695 let r = (((ext[cursor] & PIECEWISE_RATE_HI_MASK) as u32) << 16)
696 | ((ext[cursor + 1] as u32) << 8)
697 | (ext[cursor + 2] as u32);
698 cursor += 3;
699 Some(r)
700 } else {
701 None
702 };
703
704 let seamless_splice = if flags & AFE_SEAMLESS_SPLICE_FLAG != 0 {
706 need_in(ext, cursor + 5, "seamless_splice DTS_next_AU")?;
707 let b = &ext[cursor..cursor + 5];
708 let field: &[u8; 5] = b.try_into().expect("slice is exactly 5 bytes");
711 let m = broadcast_common::clock33::unpack_marked(field);
712 let (splice_type, dts_next_au) = (m.prefix, m.timestamp);
713 cursor += 5;
714 Some(SeamlessSplice {
715 splice_type,
716 dts_next_au,
717 marker_bits: m.markers,
718 })
719 } else {
720 None
721 };
722
723 Ok(AdaptationFieldExtension {
724 ltw,
725 piecewise_rate,
726 piecewise_rate_reserved,
727 seamless_splice,
728 af_descriptor_not_present_flag: flags & AFE_AF_DESCRIPTOR_NOT_PRESENT_FLAG != 0,
729 reserved_flags: flags & AFE_RESERVED_FLAGS_MASK,
730 trailing: &ext[cursor..],
731 })
732 }
733
734 #[must_use]
737 pub fn serialized_len(&self) -> usize {
738 let body = 1 + self.ltw.map_or(0, |_| 2)
740 + self.piecewise_rate.map_or(0, |_| 3)
741 + self.seamless_splice.map_or(0, |_| 5)
742 + self.trailing.len();
743 1 + body }
745
746 pub fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
748 let need = self.serialized_len();
749 need_out(buf, need)?;
750 buf[0] = broadcast_common::len::fit_u8(need - 1, "adaptation_field_extension_length")?;
751
752 let mut flags = broadcast_common::len::fit_mask(
753 self.reserved_flags,
754 AFE_RESERVED_FLAGS_MASK,
755 "adaptation_field_extension.reserved",
756 )?;
757 if self.ltw.is_some() {
758 flags |= AFE_LTW_FLAG;
759 }
760 if self.piecewise_rate.is_some() {
761 flags |= AFE_PIECEWISE_RATE_FLAG;
762 }
763 if self.seamless_splice.is_some() {
764 flags |= AFE_SEAMLESS_SPLICE_FLAG;
765 }
766 if self.af_descriptor_not_present_flag {
767 flags |= AFE_AF_DESCRIPTOR_NOT_PRESENT_FLAG;
768 }
769 buf[1] = flags;
770 let mut cursor = 2usize;
771
772 if let Some(ltw) = self.ltw {
773 let ltw_valid = if ltw.ltw_valid_flag { AFE_LTW_FLAG } else { 0 };
774 buf[cursor] = ltw_valid | ((ltw.ltw_offset >> 8) as u8 & LTW_OFFSET_HI_MASK);
775 buf[cursor + 1] = (ltw.ltw_offset & 0xFF) as u8;
776 cursor += 2;
777 }
778 if let Some(rate) = self.piecewise_rate {
779 buf[cursor] = (broadcast_common::len::fit_mask(
781 self.piecewise_rate_reserved,
782 PIECEWISE_RATE_RESERVED_VALUE,
783 "piecewise_rate.reserved",
784 )? << PIECEWISE_RATE_RESERVED_SHIFT)
785 | ((rate >> 16) as u8 & PIECEWISE_RATE_HI_MASK);
786 buf[cursor + 1] = (rate >> 8) as u8;
787 buf[cursor + 2] = rate as u8;
788 cursor += 3;
789 }
790 if let Some(ss) = self.seamless_splice {
791 buf[cursor..cursor + 5].copy_from_slice(&broadcast_common::clock33::pack_marked_with(
793 ss.dts_next_au,
794 ss.splice_type,
795 ss.marker_bits,
796 ));
797 cursor += 5;
798 }
799 buf[cursor..cursor + self.trailing.len()].copy_from_slice(self.trailing);
800 cursor += self.trailing.len();
801 Ok(cursor)
802 }
803}
804
805#[non_exhaustive]
814#[derive(Clone, Debug, PartialEq, Eq)]
815#[cfg_attr(feature = "serde", derive(serde::Serialize))]
816pub struct AdaptationField<'a> {
817 pub discontinuity_indicator: bool,
819 pub random_access_indicator: bool,
821 pub elementary_stream_priority_indicator: bool,
823 pub pcr: Option<Pcr>,
825 pub opcr: Option<Pcr>,
827 pub splice_countdown: Option<i8>,
829 pub transport_private_data: Option<&'a [u8]>,
834 pub extension: Option<AdaptationFieldExtension<'a>>,
836 pub pcr_reserved: u8,
842 pub opcr_reserved: u8,
844 pub stuffing: &'a [u8],
854}
855
856impl Default for AdaptationField<'_> {
857 fn default() -> Self {
858 Self::new()
859 }
860}
861
862fn set_pcr_reserved(field: &mut [u8], reserved: u8) {
864 field[4] =
865 (field[4] & !PCR_RESERVED_BITS) | ((reserved << PCR_RESERVED_SHIFT) & PCR_RESERVED_BITS);
866}
867
868impl<'a> AdaptationField<'a> {
869 #[must_use]
873 pub const fn new() -> Self {
874 Self {
875 discontinuity_indicator: false,
876 random_access_indicator: false,
877 elementary_stream_priority_indicator: false,
878 pcr: None,
879 opcr: None,
880 splice_countdown: None,
881 transport_private_data: None,
882 extension: None,
883 pcr_reserved: PCR_RESERVED_VALUE,
884 opcr_reserved: PCR_RESERVED_VALUE,
885 stuffing: &[],
886 }
887 }
888
889 pub(crate) fn parse(af: &'a [u8]) -> Result<Self> {
896 let flags = *af.first().ok_or(Error::BufferTooShort(
897 broadcast_common::error::BufferTooShort {
898 need: 1,
899 have: 0,
900 what: "adaptation_field flags",
901 },
902 ))?;
903 let mut cursor = 1usize;
904
905 let mut pcr_reserved = PCR_RESERVED_VALUE;
906 let mut opcr_reserved = PCR_RESERVED_VALUE;
907 let pcr = if flags & AF_PCR_FLAG != 0 {
908 let p = Pcr::parse(af, cursor)?;
909 pcr_reserved = (af[cursor + 4] & PCR_RESERVED_BITS) >> PCR_RESERVED_SHIFT;
910 cursor += PCR_FIELD_LEN;
911 Some(p)
912 } else {
913 None
914 };
915 let opcr = if flags & AF_OPCR_FLAG != 0 {
916 let p = Pcr::parse(af, cursor)?;
917 opcr_reserved = (af[cursor + 4] & PCR_RESERVED_BITS) >> PCR_RESERVED_SHIFT;
918 cursor += PCR_FIELD_LEN;
919 Some(p)
920 } else {
921 None
922 };
923 let splice_countdown = if flags & AF_SPLICING_FLAG != 0 {
924 let b = *af.get(cursor).ok_or(Error::BufferTooShort(
925 broadcast_common::error::BufferTooShort {
926 need: cursor + 1,
927 have: af.len(),
928 what: "adaptation_field splice_countdown",
929 },
930 ))?;
931 cursor += 1;
932 Some(b as i8)
933 } else {
934 None
935 };
936
937 let transport_private_data = if flags & AF_TRANSPORT_PRIVATE_DATA_FLAG != 0 {
940 let tpd_len = *af.get(cursor).ok_or(Error::BufferTooShort(
941 broadcast_common::error::BufferTooShort {
942 need: cursor + 1,
943 have: af.len(),
944 what: "transport_private_data_length",
945 },
946 ))? as usize;
947 cursor += 1;
948 let end = cursor + tpd_len;
949 let slice = af.get(cursor..end).ok_or(Error::BufferTooShort(
950 broadcast_common::error::BufferTooShort {
951 need: end,
952 have: af.len(),
953 what: "transport_private_data",
954 },
955 ))?;
956 cursor = end;
957 Some(slice)
958 } else {
959 None
960 };
961
962 let extension = if flags & AF_EXTENSION_FLAG != 0 {
964 let ext_data = af.get(cursor..).ok_or(Error::BufferTooShort(
965 broadcast_common::error::BufferTooShort {
966 need: cursor + 1,
967 have: af.len(),
968 what: "adaptation_field_extension",
969 },
970 ))?;
971 let ext = AdaptationFieldExtension::parse(ext_data)?;
972 if !ext_data.is_empty() {
974 let _ext_len = ext_data[0] as usize;
975 cursor += 1 + _ext_len;
976 }
977 Some(ext)
978 } else {
979 None
980 };
981
982 let stuffing = af.get(cursor..).unwrap_or(&[]);
986
987 Ok(AdaptationField {
988 discontinuity_indicator: flags & AF_DISCONTINUITY != 0,
989 random_access_indicator: flags & AF_RANDOM_ACCESS != 0,
990 elementary_stream_priority_indicator: flags & AF_ES_PRIORITY != 0,
991 pcr,
992 opcr,
993 splice_countdown,
994 transport_private_data,
995 extension,
996 pcr_reserved,
997 opcr_reserved,
998 stuffing,
999 })
1000 }
1001
1002 #[must_use]
1008 pub fn serialized_len(&self) -> usize {
1009 let mut n = 1usize; if self.pcr.is_some() {
1011 n += PCR_FIELD_LEN;
1012 }
1013 if self.opcr.is_some() {
1014 n += PCR_FIELD_LEN;
1015 }
1016 if self.splice_countdown.is_some() {
1017 n += 1;
1018 }
1019 if let Some(tpd) = self.transport_private_data {
1020 n += 1 + tpd.len(); }
1022 if let Some(ref ext) = self.extension {
1023 n += ext.serialized_len();
1024 }
1025 n += self.stuffing.len();
1026 n
1027 }
1028
1029 pub fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
1040 let need = self.serialized_len();
1041 need_out(buf, need)?;
1042
1043 let mut flags = 0u8;
1045 if self.discontinuity_indicator {
1046 flags |= AF_DISCONTINUITY;
1047 }
1048 if self.random_access_indicator {
1049 flags |= AF_RANDOM_ACCESS;
1050 }
1051 if self.elementary_stream_priority_indicator {
1052 flags |= AF_ES_PRIORITY;
1053 }
1054 if self.pcr.is_some() {
1055 flags |= AF_PCR_FLAG;
1056 }
1057 if self.opcr.is_some() {
1058 flags |= AF_OPCR_FLAG;
1059 }
1060 if self.splice_countdown.is_some() {
1061 flags |= AF_SPLICING_FLAG;
1062 }
1063 if self.transport_private_data.is_some() {
1064 flags |= AF_TRANSPORT_PRIVATE_DATA_FLAG;
1065 }
1066 if self.extension.is_some() {
1067 flags |= AF_EXTENSION_FLAG;
1068 }
1069 buf[0] = flags;
1070
1071 let mut cursor = 1usize;
1072 if let Some(pcr) = self.pcr {
1073 buf[cursor..cursor + PCR_FIELD_LEN].copy_from_slice(&pcr.to_field_bytes());
1074 set_pcr_reserved(&mut buf[cursor..cursor + PCR_FIELD_LEN], self.pcr_reserved);
1075 cursor += PCR_FIELD_LEN;
1076 }
1077 if let Some(opcr) = self.opcr {
1078 buf[cursor..cursor + PCR_FIELD_LEN].copy_from_slice(&opcr.to_field_bytes());
1079 set_pcr_reserved(&mut buf[cursor..cursor + PCR_FIELD_LEN], self.opcr_reserved);
1080 cursor += PCR_FIELD_LEN;
1081 }
1082 if let Some(sc) = self.splice_countdown {
1083 buf[cursor] = sc as u8;
1084 cursor += 1;
1085 }
1086 if let Some(tpd) = self.transport_private_data {
1087 buf[cursor] = broadcast_common::len::fit_u8(
1088 tpd.len(),
1089 "adaptation_field.transport_private_data_length",
1090 )?;
1091 cursor += 1;
1092 buf[cursor..cursor + tpd.len()].copy_from_slice(tpd);
1093 cursor += tpd.len();
1094 }
1095 if let Some(ref ext) = self.extension {
1096 let written = ext.serialize_into(&mut buf[cursor..])?;
1097 cursor += written;
1098 }
1099
1100 buf[cursor..cursor + self.stuffing.len()].copy_from_slice(self.stuffing);
1103 cursor += self.stuffing.len();
1104
1105 Ok(cursor)
1106 }
1107}
1108
1109#[derive(Default)]
1114pub struct SectionReassembler {
1115 buf: bytes::BytesMut,
1116 ready: alloc::collections::VecDeque<bytes::Bytes>,
1117}
1118
1119impl SectionReassembler {
1120 pub fn feed(&mut self, payload: &[u8], pusi: bool) {
1128 if pusi {
1129 if payload.is_empty() {
1132 self.buf.clear();
1133 return;
1134 }
1135 let pointer = payload[0] as usize;
1136
1137 if !self.buf.is_empty() && pointer > 0 {
1145 let avail = payload.len() - 1;
1146 let tail_len = pointer.min(avail);
1147 if self.buf.len() + tail_len > MAX_SECTION_SIZE {
1148 self.buf.clear();
1149 } else {
1150 self.buf.extend_from_slice(&payload[1..1 + tail_len]);
1151 self.drain_complete_sections();
1152 }
1153 }
1154
1155 self.buf.clear();
1158
1159 let start = 1 + pointer;
1160 if start >= payload.len() {
1161 return;
1163 }
1164 let new_data = &payload[start..];
1165 if new_data.len() > MAX_SECTION_SIZE {
1166 return;
1167 }
1168 self.buf.extend_from_slice(new_data);
1169 } else {
1170 if self.buf.is_empty() {
1171 return;
1172 }
1173 let take = if let Some(exp) = section_total_len(&self.buf) {
1183 exp.saturating_sub(self.buf.len()).min(payload.len())
1184 } else {
1185 payload.len().min(MAX_SECTION_SIZE - self.buf.len())
1189 };
1190 self.buf.extend_from_slice(&payload[..take]);
1191 }
1192
1193 self.drain_complete_sections();
1194 }
1195
1196 fn drain_complete_sections(&mut self) {
1207 loop {
1208 if self.buf.len() < SECTION_HEADER_LEN {
1209 break;
1212 }
1213 if self.buf[0] == STUFFING_BYTE {
1214 self.buf.clear();
1216 break;
1217 }
1218 let exp =
1219 section_total_len(&self.buf).expect("checked len >= SECTION_HEADER_LEN above");
1220 if self.buf.len() >= exp {
1221 let section = self.buf.split_to(exp).freeze();
1224 self.ready.push_back(section);
1225 } else {
1226 break;
1228 }
1229 }
1230 }
1231
1232 pub fn pop_section(&mut self) -> Option<bytes::Bytes> {
1234 self.ready.pop_front()
1235 }
1236
1237 pub fn len(&self) -> usize {
1239 self.buf.len()
1240 }
1241
1242 pub fn is_empty(&self) -> bool {
1244 self.buf.is_empty()
1245 }
1246}
1247
1248pub fn iter_packets(buf: &[u8]) -> impl Iterator<Item = TsPacket<'_>> {
1266 buf.chunks_exact(TS_PACKET_SIZE)
1267 .filter_map(|chunk| TsPacket::parse(chunk).ok())
1268}
1269
1270pub fn extract_ts_payload(pkt: &[u8]) -> Option<&[u8]> {
1280 if pkt.len() < 4 {
1281 return None;
1282 }
1283 let header = TsHeader::parse(&pkt[..4]).ok()?;
1284 if !header.has_payload {
1285 return None;
1286 }
1287 let cursor = 4 + adaptation_field_skip(pkt, header.has_adaptation);
1288 if cursor < pkt.len() {
1289 Some(&pkt[cursor..])
1290 } else {
1291 None
1292 }
1293}
1294
1295#[cfg(test)]
1296mod tests {
1297 use super::*;
1298 use alloc::string::ToString;
1299 use alloc::vec;
1300 use alloc::vec::Vec;
1301
1302 fn make_packet(b1: u8, b2: u8, b3: u8, payload_data: &[u8]) -> [u8; TS_PACKET_SIZE] {
1304 let mut pkt = [0u8; TS_PACKET_SIZE];
1305 pkt[0] = TS_SYNC_BYTE;
1306 pkt[1] = b1;
1307 pkt[2] = b2;
1308 pkt[3] = b3;
1309 let payload_start = 4;
1310 let end = (payload_start + payload_data.len()).min(TS_PACKET_SIZE);
1311 let len = (end - payload_start).min(payload_data.len());
1312 pkt[payload_start..payload_start + len].copy_from_slice(&payload_data[..len]);
1313 pkt
1314 }
1315
1316 #[test]
1317 fn parse_rejects_non_0x47_sync_byte() {
1318 let mut pkt = [0u8; TS_PACKET_SIZE];
1319 pkt[0] = 0x46; let err = TsPacket::parse(&pkt).unwrap_err();
1321 match err {
1322 Error::InvalidSync(e) => assert_eq!(e.found, 0x46),
1323 other => panic!("expected InvalidSyncByte, got {other:?}"),
1324 }
1325 }
1326
1327 #[test]
1328 fn ts_header_round_trip() {
1329 let cases = [
1332 TsHeader {
1333 tei: false,
1334 pusi: true,
1335 pid: Pid::new(0x0000),
1336 scrambling: 0,
1337 has_adaptation: false,
1338 has_payload: true,
1339 continuity_counter: 0,
1340 },
1341 TsHeader {
1342 tei: true,
1343 pusi: false,
1344 pid: Pid::new(0x1FFF),
1345 scrambling: 0b11,
1346 has_adaptation: true,
1347 has_payload: true,
1348 continuity_counter: 0x0F,
1349 },
1350 TsHeader {
1351 tei: false,
1352 pusi: false,
1353 pid: Pid::new(0x0100),
1354 scrambling: 0b10,
1355 has_adaptation: true,
1356 has_payload: false,
1357 continuity_counter: 7,
1358 },
1359 ];
1360 for h in cases {
1361 let mut buf = [0u8; 4];
1362 assert_eq!(h.serialize_into(&mut buf).unwrap(), 4);
1363 assert_eq!(TsHeader::parse(&buf).unwrap(), h, "round-trip mismatch");
1364 }
1365 }
1366
1367 #[test]
1368 fn parse_extracts_pid_and_continuity_counter() {
1369 let pkt = make_packet(0x12, 0x34, 0x05, &[]);
1375 let pkt = TsPacket::parse(&pkt).unwrap();
1376 assert_eq!(pkt.header.pid, Pid::new(0x1234));
1377 assert_eq!(pkt.header.continuity_counter, 5);
1378 }
1379
1380 #[test]
1381 fn payload_unit_start_indicator_flag_extracted() {
1382 let pkt1 = make_packet(0x40, 0x00, 0x00, &[]);
1384 let pkt1 = TsPacket::parse(&pkt1).unwrap();
1385 assert!(pkt1.header.pusi);
1386
1387 let pkt2 = make_packet(0x00, 0x00, 0x00, &[]);
1389 let pkt2 = TsPacket::parse(&pkt2).unwrap();
1390 assert!(!pkt2.header.pusi);
1391 }
1392
1393 fn build_pusi_payload(pointer_field: u8, previous_tail: &[u8], section: &[u8]) -> Vec<u8> {
1398 assert_eq!(pointer_field as usize, previous_tail.len());
1399 let mut v = Vec::with_capacity(1 + previous_tail.len() + section.len());
1400 v.push(pointer_field);
1401 v.extend_from_slice(previous_tail);
1402 v.extend_from_slice(section);
1403 v
1404 }
1405
1406 #[test]
1412 fn reassembler_accumulates_multi_packet_section() {
1413 let body = vec![0xAAu8; 197];
1415 let section = test_fixtures::psi::short_section(0x02, &body);
1416 assert_eq!(section.len(), 200);
1417
1418 let first_chunk = 100;
1419 let payload1 = build_pusi_payload(0, &[], §ion[..first_chunk]);
1420 let payload2 = section[first_chunk..].to_vec();
1421
1422 let mut reasm = SectionReassembler::default();
1423 reasm.feed(&payload1, true);
1424 reasm.feed(&payload2, false);
1425
1426 let out = reasm.pop_section().expect("section should be ready");
1427 assert_eq!(out.len(), 200);
1428 assert_eq!(out.as_ref(), §ion[..]);
1429 }
1430
1431 #[test]
1432 fn reassembler_yields_complete_section_once_length_satisfied() {
1433 let section = test_fixtures::psi::short_section(0x42, &[0xAA]);
1435 assert_eq!(section.len(), 4);
1436 let payload = build_pusi_payload(0, &[], §ion);
1437
1438 let mut reasm = SectionReassembler::default();
1439 reasm.feed(&payload, true);
1440
1441 let out = reasm
1442 .pop_section()
1443 .expect("single-packet section should pop");
1444 assert_eq!(out.as_ref(), §ion[..]);
1445 }
1446
1447 #[test]
1448 fn reassembler_extracts_all_concatenated_sections_in_one_payload() {
1449 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();
1458 concat.extend_from_slice(&s1);
1459 concat.extend_from_slice(&s2);
1460 concat.extend_from_slice(&s3);
1461 let payload = build_pusi_payload(0, &[], &concat);
1462
1463 let mut reasm = SectionReassembler::default();
1464 reasm.feed(&payload, true);
1465
1466 let got: Vec<_> = core::iter::from_fn(|| reasm.pop_section()).collect();
1468 assert_eq!(got.len(), 3, "all three concatenated sections must pop");
1469 assert_eq!(got[0].as_ref(), &s1[..]);
1470 assert_eq!(got[1].as_ref(), &s2[..]);
1471 assert_eq!(got[2].as_ref(), &s3[..]);
1472 }
1473
1474 #[test]
1475 fn reassembler_stops_at_stuffing_after_concatenated_sections() {
1476 let s1 = test_fixtures::psi::short_section(0x42, &[0xAA]); let s2 = test_fixtures::psi::short_section(0x46, &[0xBB, 0xCC]); let mut concat = Vec::new();
1482 concat.extend_from_slice(&s1);
1483 concat.extend_from_slice(&s2);
1484 concat.extend_from_slice(&[0xFF, 0xFF, 0xFF, 0xFF]); let payload = build_pusi_payload(0, &[], &concat);
1486
1487 let mut reasm = SectionReassembler::default();
1488 reasm.feed(&payload, true);
1489
1490 let got: Vec<_> = core::iter::from_fn(|| reasm.pop_section()).collect();
1491 assert_eq!(got.len(), 2);
1492 assert_eq!(got[0].as_ref(), &s1[..]);
1493 assert_eq!(got[1].as_ref(), &s2[..]);
1494 assert!(
1495 reasm.is_empty(),
1496 "stuffing tail must be discarded, not buffered"
1497 );
1498 }
1499
1500 #[test]
1501 fn reassembler_concatenated_then_spanning_tail() {
1502 let s1 = test_fixtures::psi::short_section(0x42, &[0x01, 0x02]); let s2 = test_fixtures::psi::short_section(0x46, &[0x09u8; 60]); let split = 30;
1508
1509 let mut head = Vec::new();
1510 head.extend_from_slice(&s1);
1511 head.extend_from_slice(&s2[..split]);
1512 let payload1 = build_pusi_payload(0, &[], &head);
1513 let payload2 = s2[split..].to_vec();
1514
1515 let mut reasm = SectionReassembler::default();
1516 reasm.feed(&payload1, true);
1517 let first = reasm.pop_section().expect("first section pops at once");
1518 assert_eq!(first.as_ref(), &s1[..]);
1519 assert!(reasm.pop_section().is_none(), "second is still partial");
1520
1521 reasm.feed(&payload2, false);
1522 let second = reasm.pop_section().expect("second pops after continuation");
1523 assert_eq!(second.as_ref(), &s2[..]);
1524 }
1525
1526 #[test]
1527 fn reassembler_completes_section_spanning_into_pusi_packet() {
1528 let spanning = test_fixtures::psi::short_section(0x42, &[0x5Au8; 62]); let head = 41;
1536 let tail = &spanning[head..]; assert_eq!(tail.len(), 24);
1538
1539 let next = test_fixtures::psi::short_section(0x46, &[0x77, 0x88]); let payload_a = build_pusi_payload(0, &[], &spanning[..head]);
1544 let payload_b = build_pusi_payload(24, tail, &next);
1546
1547 let mut reasm = SectionReassembler::default();
1548 reasm.feed(&payload_a, true);
1549 assert!(reasm.pop_section().is_none(), "head alone is incomplete");
1550
1551 reasm.feed(&payload_b, true);
1552 let got: Vec<_> = core::iter::from_fn(|| reasm.pop_section()).collect();
1553 assert_eq!(got.len(), 2, "spanning section + new section must both pop");
1554 assert_eq!(
1555 got[0].as_ref(),
1556 &spanning[..],
1557 "spanning section completed from B's pointer tail"
1558 );
1559 assert_eq!(got[1].as_ref(), &next[..]);
1560 }
1561
1562 #[test]
1563 fn reassembler_pusi_pointer_spans_whole_payload() {
1564 let spanning = test_fixtures::psi::short_section(0x42, &[0x33u8; 40]); let head = 20;
1569 let payload_a = build_pusi_payload(0, &[], &spanning[..head]);
1570 let tail = &spanning[head..]; let mut reasm = SectionReassembler::default();
1573 reasm.feed(&payload_a, true);
1574 reasm.feed(&build_pusi_payload_pointer_spanning_all(tail), true);
1576
1577 let out = reasm.pop_section().expect("spanning section completes");
1578 assert_eq!(out.as_ref(), &spanning[..]);
1579 assert!(reasm.pop_section().is_none());
1580 }
1581
1582 fn build_pusi_payload_pointer_spanning_all(tail: &[u8]) -> Vec<u8> {
1585 let mut v = Vec::with_capacity(1 + tail.len());
1586 v.push(tail.len() as u8);
1587 v.extend_from_slice(tail);
1588 v
1589 }
1590
1591 #[test]
1592 fn reassembler_completes_max_length_section_and_stays_usable() {
1593 let mut section = Vec::with_capacity(MAX_SECTION_SIZE);
1599 section.push(0x00); section.push(0xB0 | ((4095u16 >> 8) as u8 & 0x0F));
1601 section.push(0xFF); section.resize(MAX_SECTION_SIZE, 0u8);
1603 assert_eq!(section.len(), MAX_SECTION_SIZE);
1604
1605 let mut reasm = SectionReassembler::default();
1606 let mut first = vec![0x00u8]; first.extend_from_slice(§ion[..183]);
1608 reasm.feed(&first, true);
1609 assert!(
1610 reasm.pop_section().is_none(),
1611 "incomplete until the declared length arrives"
1612 );
1613
1614 for chunk in section[183..].chunks(184) {
1615 reasm.feed(chunk, false);
1616 }
1617 let out = reasm
1618 .pop_section()
1619 .expect("max-length section completes at its declared length");
1620 assert_eq!(out.len(), MAX_SECTION_SIZE);
1621 assert_eq!(out.as_ref(), §ion[..]);
1622 assert!(reasm.is_empty());
1623
1624 reasm.feed(&[0u8; 184], false);
1628 assert!(reasm.pop_section().is_none());
1629
1630 let valid_section = test_fixtures::psi::short_section(0x00, &[0xAA]);
1632 let payload2 = build_pusi_payload(0, &[], &valid_section);
1633 reasm.feed(&payload2, true);
1634 let out = reasm
1635 .pop_section()
1636 .expect("fresh section should pop after reset");
1637 assert_eq!(out.as_ref(), &valid_section[..]);
1638 }
1639
1640 #[test]
1641 fn reassembler_handles_pusi_with_nonzero_pointer_field() {
1642 let prior_tail = vec![0x11, 0x22, 0x33];
1644 let new_section = test_fixtures::psi::short_section(0x02, &[0xBB]);
1645 assert_eq!(new_section.len(), 4);
1646 let payload = build_pusi_payload(3, &prior_tail, &new_section);
1647
1648 let mut reasm = SectionReassembler::default();
1649 reasm.feed(&payload, true);
1650
1651 let out = reasm
1652 .pop_section()
1653 .expect("section after pointer_field skip should pop");
1654 assert_eq!(out.as_ref(), &new_section[..]);
1655 }
1656
1657 #[test]
1658 fn reassembler_ignores_continuation_before_pusi() {
1659 let pkt = make_packet(0x00, 0x00, PAYLOAD_FLAG, &[0xAA, 0xBB, 0xCC]);
1662
1663 let mut reasm = SectionReassembler::default();
1664 reasm.feed(&pkt[4..], false); assert!(
1667 reasm.pop_section().is_none(),
1668 "no section should appear without prior PUSI"
1669 );
1670 assert!(
1671 reasm.pop_section().is_none(),
1672 "second pop should also be none"
1673 );
1674 }
1675
1676 #[test]
1679 fn reassembler_empty_pusi_payload_does_not_panic() {
1680 let mut reasm = SectionReassembler::default();
1681 reasm.feed(&[], true);
1682 assert!(reasm.pop_section().is_none());
1683 let payload = vec![0x00u8, 0x72, 0x70, 0x01, 0x00];
1685 reasm.feed(&payload, true);
1686 assert!(reasm.pop_section().is_some());
1687 }
1688
1689 #[test]
1693 fn reassembler_accepts_maximal_private_section() {
1694 let mut section = vec![0x80u8, 0x7F, 0xFF]; section.resize(3 + 0xFFF, 0xAB);
1696
1697 let mut reasm = SectionReassembler::default();
1698 let mut first = vec![0x00];
1700 first.extend_from_slice(§ion[..183]);
1701 reasm.feed(&first, true);
1702 for chunk in section[183..].chunks(184) {
1703 reasm.feed(chunk, false);
1704 }
1705 let out = reasm.pop_section().expect("4098-byte section should pop");
1706 assert_eq!(out.len(), 4098);
1707 assert_eq!(out.as_ref(), §ion[..]);
1708 }
1709
1710 #[test]
1715 fn reassembler_completes_large_section_with_trailing_stuffing() {
1716 let body = vec![0x5Au8; 4096 - 3];
1717 let section = test_fixtures::psi::short_section(0x50, &body); assert_eq!(section.len(), 4096);
1719
1720 let mut reasm = SectionReassembler::default();
1721 let mut first = vec![0x00u8];
1723 first.extend_from_slice(§ion[..183]);
1724 reasm.feed(&first, true);
1725
1726 let mut pos = 183usize;
1730 while pos < section.len() {
1731 let take = (section.len() - pos).min(184);
1732 let mut payload = section[pos..pos + take].to_vec();
1733 if take < 184 {
1734 payload.resize(184, 0xFF); }
1736 reasm.feed(&payload, false);
1737 pos += take;
1738 }
1739
1740 let out = reasm
1741 .pop_section()
1742 .expect("4096-byte section must complete despite trailing stuffing (#148)");
1743 assert_eq!(out.len(), 4096);
1744 assert_eq!(out.as_ref(), §ion[..]);
1745 assert!(reasm.is_empty(), "stuffing tail must be discarded");
1746 }
1747
1748 #[test]
1751 fn pcr_as_27mhz_known_value() {
1752 assert_eq!(
1753 Pcr {
1754 base: 10_000,
1755 extension: 0
1756 }
1757 .as_27mhz(),
1758 3_000_000
1759 );
1760 assert_eq!(
1762 Pcr {
1763 base: 1,
1764 extension: 100
1765 }
1766 .as_27mhz(),
1767 400
1768 );
1769 }
1770
1771 #[test]
1772 fn pcr_decode_from_bytes() {
1773 let af = [0x10u8, 0x00, 0x00, 0x13, 0x88, 0x7E, 0x00];
1775 let pcr = Pcr::parse(&af, 1).expect("6 bytes present");
1776 assert_eq!(
1777 pcr,
1778 Pcr {
1779 base: 10_000,
1780 extension: 0
1781 }
1782 );
1783 assert_eq!(pcr.as_27mhz(), 3_000_000);
1784 }
1785
1786 #[test]
1787 fn adaptation_field_flags_and_pcr() {
1788 let mut raw = [0xAAu8; TS_PACKET_SIZE];
1789 raw[0] = TS_SYNC_BYTE;
1790 raw[1] = 0x01; raw[2] = 0x00;
1792 raw[3] = ADAPTATION_FLAG | PAYLOAD_FLAG;
1793 raw[4] = 7; raw[5] = AF_DISCONTINUITY | AF_PCR_FLAG;
1795 raw[6..12].copy_from_slice(&[0x00, 0x00, 0x13, 0x88, 0x7E, 0x00]);
1796 let pkt = TsPacket::parse(&raw).expect("valid packet");
1799 let af = pkt
1800 .adaptation_field()
1801 .expect("has adaptation field")
1802 .expect("adaptation field parses");
1803 assert!(af.discontinuity_indicator);
1804 assert!(!af.random_access_indicator);
1805 assert_eq!(
1806 af.pcr,
1807 Some(Pcr {
1808 base: 10_000,
1809 extension: 0
1810 })
1811 );
1812 assert_eq!(af.pcr.unwrap().as_27mhz(), 3_000_000);
1813 assert!(af.opcr.is_none());
1814 assert!(af.splice_countdown.is_none());
1815 let payload = pkt.payload.expect("payload present");
1817 assert_eq!(payload.len(), TS_PACKET_SIZE - 12);
1818 assert_eq!(payload[0], 0xAA);
1819 }
1820
1821 #[test]
1822 fn oversized_adaptation_field_length_is_rejected_not_truncated() {
1823 let mut raw = [0xAAu8; TS_PACKET_SIZE];
1829 raw[0] = TS_SYNC_BYTE;
1830 raw[1] = 0x01;
1831 raw[2] = 0x00;
1832 raw[3] = ADAPTATION_FLAG; raw[4] = 200; let pkt = TsPacket::parse(&raw).expect("header + af_len byte still parse");
1836 assert!(
1837 pkt.adaptation_field().is_none(),
1838 "an over-long adaptation field must be rejected, not truncated"
1839 );
1840 assert!(pkt.payload.is_none());
1841
1842 let owned = crate::owned::OwnedTsPacket::parse(raw).unwrap();
1844 assert!(owned.adaptation_field().is_none());
1845 }
1846
1847 #[test]
1848 fn no_adaptation_returns_none() {
1849 let mut raw = [0x00u8; TS_PACKET_SIZE];
1850 raw[0] = TS_SYNC_BYTE;
1851 raw[1] = 0x01;
1852 raw[3] = PAYLOAD_FLAG; let pkt = TsPacket::parse(&raw).expect("valid");
1854 assert!(pkt.adaptation_field().is_none());
1855 assert!(pkt.adaptation.is_none());
1856 }
1857
1858 #[test]
1859 fn adaptation_field_splice_countdown_negative() {
1860 let mut raw = [0xAAu8; TS_PACKET_SIZE];
1861 raw[0] = TS_SYNC_BYTE;
1862 raw[1] = 0x01;
1863 raw[2] = 0x00;
1864 raw[3] = ADAPTATION_FLAG | PAYLOAD_FLAG;
1865 raw[4] = 2; raw[5] = AF_SPLICING_FLAG;
1867 raw[6] = 0xFB; let pkt = TsPacket::parse(&raw).expect("valid");
1869 let af = pkt.adaptation_field().unwrap().unwrap();
1870 assert_eq!(af.splice_countdown, Some(-5));
1871 assert!(af.pcr.is_none());
1872 }
1873
1874 #[test]
1877 fn scrambling_control_all_values() {
1878 assert_eq!(
1879 ScramblingControl::from_bits(0b00),
1880 ScramblingControl::NotScrambled
1881 );
1882 assert_eq!(
1883 ScramblingControl::from_bits(0b01),
1884 ScramblingControl::Reserved
1885 );
1886 assert_eq!(
1887 ScramblingControl::from_bits(0b10),
1888 ScramblingControl::EvenKey
1889 );
1890 assert_eq!(
1891 ScramblingControl::from_bits(0b11),
1892 ScramblingControl::OddKey
1893 );
1894 assert_eq!(ScramblingControl::NotScrambled.name(), "not_scrambled");
1896 assert_eq!(ScramblingControl::Reserved.name(), "reserved");
1897 assert_eq!(ScramblingControl::EvenKey.name(), "even_key");
1898 assert_eq!(ScramblingControl::OddKey.name(), "odd_key");
1899 assert_eq!(ScramblingControl::NotScrambled.to_string(), "not_scrambled");
1901 assert_eq!(ScramblingControl::OddKey.to_string(), "odd_key");
1902 assert_eq!(
1904 ScramblingControl::from_bits(0xFF),
1905 ScramblingControl::OddKey
1906 );
1907 }
1908
1909 #[test]
1910 fn adaptation_field_control_all_values() {
1911 assert_eq!(
1912 AdaptationFieldControl::from_flags(false, false),
1913 AdaptationFieldControl::Reserved
1914 );
1915 assert_eq!(
1916 AdaptationFieldControl::from_flags(false, true),
1917 AdaptationFieldControl::PayloadOnly
1918 );
1919 assert_eq!(
1920 AdaptationFieldControl::from_flags(true, false),
1921 AdaptationFieldControl::AdaptationOnly
1922 );
1923 assert_eq!(
1924 AdaptationFieldControl::from_flags(true, true),
1925 AdaptationFieldControl::AdaptationAndPayload
1926 );
1927 assert_eq!(AdaptationFieldControl::Reserved.name(), "reserved");
1929 assert_eq!(AdaptationFieldControl::PayloadOnly.name(), "payload_only");
1930 assert_eq!(
1931 AdaptationFieldControl::AdaptationOnly.name(),
1932 "adaptation_only"
1933 );
1934 assert_eq!(
1935 AdaptationFieldControl::AdaptationAndPayload.name(),
1936 "adaptation_and_payload"
1937 );
1938 assert_eq!(
1940 AdaptationFieldControl::PayloadOnly.to_string(),
1941 "payload_only"
1942 );
1943 }
1944
1945 #[test]
1946 fn ts_header_scrambling_control_accessor() {
1947 let hdr = TsHeader {
1948 tei: false,
1949 pusi: false,
1950 pid: Pid::new(0x0100),
1951 scrambling: 0b10,
1952 has_adaptation: false,
1953 has_payload: true,
1954 continuity_counter: 0,
1955 };
1956 assert_eq!(hdr.scrambling_control(), ScramblingControl::EvenKey);
1957 }
1958
1959 #[test]
1960 fn ts_header_adaptation_field_control_accessor() {
1961 let hdr_payload_only = TsHeader {
1962 tei: false,
1963 pusi: false,
1964 pid: Pid::new(0x0100),
1965 scrambling: 0,
1966 has_adaptation: false,
1967 has_payload: true,
1968 continuity_counter: 0,
1969 };
1970 assert_eq!(
1971 hdr_payload_only.adaptation_field_control(),
1972 AdaptationFieldControl::PayloadOnly
1973 );
1974
1975 let hdr_both = TsHeader {
1976 tei: false,
1977 pusi: false,
1978 pid: Pid::new(0x0100),
1979 scrambling: 0,
1980 has_adaptation: true,
1981 has_payload: true,
1982 continuity_counter: 0,
1983 };
1984 assert_eq!(
1985 hdr_both.adaptation_field_control(),
1986 AdaptationFieldControl::AdaptationAndPayload
1987 );
1988 }
1989
1990 #[test]
1993 fn iter_packets_yields_valid_and_skips_bad_sync() {
1994 let pkt1 = make_packet(0x00, 0x00, PAYLOAD_FLAG, &[0xAA; 10]);
1996 let pkt2 = make_packet(0x40, 0x64, PAYLOAD_FLAG, &[0xBB; 10]);
1997 let mut bad = [0u8; TS_PACKET_SIZE];
1998 bad[0] = 0x00; let mut buf = Vec::new();
2001 buf.extend_from_slice(&pkt1);
2002 buf.extend_from_slice(&pkt2);
2003 buf.extend_from_slice(&bad);
2004
2005 let pkts: Vec<_> = super::iter_packets(&buf).collect();
2006 assert_eq!(pkts.len(), 2, "bad sync packet must be skipped");
2007 assert_eq!(pkts[0].header.pid, Pid::new(0x0000));
2008 assert_eq!(pkts[1].header.pid, Pid::new(0x0064));
2009 }
2010
2011 #[test]
2012 fn extract_ts_payload_payload_only() {
2013 let pkt = make_packet(0x00, 0x00, PAYLOAD_FLAG, &[0xABu8; 10]);
2014 let p = super::extract_ts_payload(&pkt).expect("payload present");
2015 assert_eq!(p[0], 0xAB);
2016 assert_eq!(p.len(), TS_PACKET_SIZE - 4);
2017 }
2018
2019 #[test]
2020 fn extract_ts_payload_adaptation_only_returns_none() {
2021 let pkt = make_packet(0x00, 0x00, ADAPTATION_FLAG, &[]);
2022 assert!(super::extract_ts_payload(&pkt).is_none());
2023 }
2024
2025 #[test]
2030 fn pcr_from_27mhz_round_trips() {
2031 for &ticks in &[0u64, 1, 300, 27_000_000, u64::from(u32::MAX), 8_589_934_591] {
2032 let pcr = Pcr::from_27mhz(ticks);
2033 assert_eq!(pcr.as_27mhz(), ticks, "ticks={ticks}");
2034 }
2035 }
2036
2037 #[test]
2039 fn pcr_to_field_bytes_round_trips_parse() {
2040 let cases = [
2041 Pcr {
2042 base: 0,
2043 extension: 0,
2044 },
2045 Pcr {
2046 base: 10_000,
2047 extension: 0,
2048 },
2049 Pcr {
2050 base: 1,
2051 extension: 100,
2052 },
2053 Pcr {
2054 base: 0x1_FFFF_FFFF,
2055 extension: 0x1FF,
2056 },
2057 ];
2058 for pcr in cases {
2059 let bytes = pcr.to_field_bytes();
2060 let mut af = [0u8; 7];
2063 af[1..7].copy_from_slice(&bytes);
2064 let decoded = Pcr::parse(&af, 1).expect("parse round-trip");
2065 assert_eq!(decoded, pcr, "round-trip failed for {pcr:?}");
2066 }
2067 }
2068
2069 #[test]
2072 fn pcr_to_field_bytes_known_vector() {
2073 let pcr = Pcr {
2074 base: 10_000,
2075 extension: 0,
2076 };
2077 let bytes = pcr.to_field_bytes();
2078 assert_eq!(bytes, [0x00, 0x00, 0x13, 0x88, 0x7E, 0x00]);
2079 }
2080
2081 #[test]
2084 fn scrambling_control_to_bits_inverse_of_from_bits() {
2085 for bits in 0u8..=3 {
2086 let sc = ScramblingControl::from_bits(bits);
2087 assert_eq!(sc.to_bits(), bits, "to_bits() != from_bits() for {bits}");
2088 }
2089 }
2090
2091 #[test]
2094 fn adaptation_field_control_to_bits_inverse_of_from_flags() {
2095 let cases = [
2096 (false, false, 0b00u8),
2097 (false, true, 0b01),
2098 (true, false, 0b10),
2099 (true, true, 0b11),
2100 ];
2101 for (has_af, has_pl, expected_bits) in cases {
2102 let afc = AdaptationFieldControl::from_flags(has_af, has_pl);
2103 assert_eq!(afc.to_bits(), expected_bits);
2104 assert_eq!(afc.to_flags(), (has_af, has_pl));
2105 }
2106 }
2107
2108 #[test]
2112 fn adaptation_field_serialize_round_trip_with_pcr() {
2113 let original = AdaptationField {
2114 discontinuity_indicator: true,
2115 random_access_indicator: false,
2116 elementary_stream_priority_indicator: false,
2117 pcr: Some(Pcr {
2118 base: 10_000,
2119 extension: 0,
2120 }),
2121 opcr: None,
2122 splice_countdown: None,
2123 transport_private_data: None,
2124 extension: None,
2125 stuffing: &[],
2126 pcr_reserved: PCR_RESERVED_VALUE,
2127 opcr_reserved: PCR_RESERVED_VALUE,
2128 };
2129 let len = original.serialized_len();
2130 assert_eq!(len, 7); let mut buf = vec![0u8; len];
2132 let written = original.serialize_into(&mut buf).expect("serialize");
2133 assert_eq!(written, len);
2134 let decoded = AdaptationField::parse(&buf).expect("parse round-trip");
2135 assert_eq!(decoded, original);
2136 }
2137
2138 #[test]
2142 fn transport_private_data_over_255_bytes_rejected_not_wrapped() {
2143 let data = vec![0u8; 256];
2144 let af = AdaptationField {
2145 discontinuity_indicator: false,
2146 random_access_indicator: false,
2147 elementary_stream_priority_indicator: false,
2148 pcr: None,
2149 opcr: None,
2150 splice_countdown: None,
2151 transport_private_data: Some(&data),
2152 extension: None,
2153 stuffing: &[],
2154 pcr_reserved: PCR_RESERVED_VALUE,
2155 opcr_reserved: PCR_RESERVED_VALUE,
2156 };
2157 let mut buf = vec![0u8; af.serialized_len()];
2158 assert!(matches!(
2159 &(af.serialize_into(&mut buf)),
2160 Err(crate::error::Error::FieldOverflow(_))
2161 ));
2162 }
2163
2164 #[test]
2166 fn adaptation_field_serialize_produces_known_bytes() {
2167 let af = AdaptationField {
2171 discontinuity_indicator: true,
2172 random_access_indicator: false,
2173 elementary_stream_priority_indicator: false,
2174 pcr: Some(Pcr {
2175 base: 10_000,
2176 extension: 0,
2177 }),
2178 opcr: None,
2179 splice_countdown: None,
2180 transport_private_data: None,
2181 extension: None,
2182 stuffing: &[],
2183 pcr_reserved: PCR_RESERVED_VALUE,
2184 opcr_reserved: PCR_RESERVED_VALUE,
2185 };
2186 let mut buf = [0u8; 7];
2187 af.serialize_into(&mut buf).unwrap();
2188 assert_eq!(buf[0], AF_DISCONTINUITY | AF_PCR_FLAG);
2189 assert_eq!(&buf[1..7], &[0x00, 0x00, 0x13, 0x88, 0x7E, 0x00]);
2190 }
2191
2192 #[test]
2194 fn adaptation_field_serialize_round_trip_opcr_and_splice() {
2195 let original = AdaptationField {
2196 discontinuity_indicator: false,
2197 random_access_indicator: true,
2198 elementary_stream_priority_indicator: true,
2199 pcr: Some(Pcr {
2200 base: 1,
2201 extension: 100,
2202 }),
2203 opcr: Some(Pcr {
2204 base: 999,
2205 extension: 5,
2206 }),
2207 splice_countdown: Some(-3),
2208 transport_private_data: None,
2209 extension: None,
2210 stuffing: &[],
2211 pcr_reserved: PCR_RESERVED_VALUE,
2212 opcr_reserved: PCR_RESERVED_VALUE,
2213 };
2214 let len = original.serialized_len();
2215 assert_eq!(len, 1 + 6 + 6 + 1); let mut buf = vec![0u8; len];
2217 original.serialize_into(&mut buf).unwrap();
2218 let decoded = AdaptationField::parse(&buf).expect("parse");
2219 assert_eq!(decoded, original);
2220 }
2221
2222 #[test]
2224 fn adaptation_field_serialize_flags_only() {
2225 let af = AdaptationField {
2226 discontinuity_indicator: false,
2227 random_access_indicator: true,
2228 elementary_stream_priority_indicator: false,
2229 pcr: None,
2230 opcr: None,
2231 splice_countdown: None,
2232 transport_private_data: None,
2233 extension: None,
2234 stuffing: &[],
2235 pcr_reserved: PCR_RESERVED_VALUE,
2236 opcr_reserved: PCR_RESERVED_VALUE,
2237 };
2238 assert_eq!(af.serialized_len(), 1);
2239 let mut buf = [0u8; 1];
2240 af.serialize_into(&mut buf).unwrap();
2241 assert_eq!(buf[0], AF_RANDOM_ACCESS);
2242 let decoded = AdaptationField::parse(&buf).unwrap();
2243 assert_eq!(decoded, af);
2244 }
2245
2246 #[test]
2248 fn adaptation_field_serialize_rejects_small_buffer() {
2249 let af = AdaptationField {
2250 discontinuity_indicator: false,
2251 random_access_indicator: false,
2252 elementary_stream_priority_indicator: false,
2253 pcr: Some(Pcr {
2254 base: 0,
2255 extension: 0,
2256 }),
2257 opcr: None,
2258 splice_countdown: None,
2259 transport_private_data: None,
2260 extension: None,
2261 stuffing: &[],
2262 pcr_reserved: PCR_RESERVED_VALUE,
2263 opcr_reserved: PCR_RESERVED_VALUE,
2264 };
2265 let mut buf = [0u8; 3]; assert!(matches!(
2267 af.serialize_into(&mut buf),
2268 Err(Error::OutputBufferTooSmall(..))
2269 ));
2270 }
2271
2272 #[test]
2276 fn adaptation_field_extension_ltw_round_trip() {
2277 let ext = AdaptationFieldExtension {
2278 ltw: Some(Ltw {
2279 ltw_valid_flag: true,
2280 ltw_offset: 0x1234,
2281 }),
2282 piecewise_rate: None,
2283 seamless_splice: None,
2284 ..AdaptationFieldExtension::new()
2285 };
2286 let mut buf = vec![0u8; ext.serialized_len()];
2287 ext.serialize_into(&mut buf).unwrap();
2288 let af = AdaptationField {
2291 discontinuity_indicator: false,
2292 random_access_indicator: false,
2293 elementary_stream_priority_indicator: false,
2294 pcr: None,
2295 opcr: None,
2296 splice_countdown: None,
2297 transport_private_data: None,
2298 extension: Some(ext),
2299 stuffing: &[],
2300 pcr_reserved: PCR_RESERVED_VALUE,
2301 opcr_reserved: PCR_RESERVED_VALUE,
2302 };
2303 let len = af.serialized_len();
2304 let mut abuf = vec![0u8; len];
2305 af.serialize_into(&mut abuf).unwrap();
2306 let decoded = AdaptationField::parse(&abuf).unwrap();
2307 assert_eq!(decoded.extension, Some(ext));
2308 }
2309
2310 #[test]
2312 fn adaptation_field_extension_piecewise_rate_round_trip() {
2313 let af = AdaptationField {
2314 discontinuity_indicator: false,
2315 random_access_indicator: false,
2316 elementary_stream_priority_indicator: false,
2317 pcr: None,
2318 opcr: None,
2319 splice_countdown: None,
2320 transport_private_data: None,
2321 extension: Some(AdaptationFieldExtension {
2322 ltw: None,
2323 piecewise_rate: Some(0x3FFFFF), seamless_splice: None,
2325 ..AdaptationFieldExtension::new()
2326 }),
2327 stuffing: &[],
2328 pcr_reserved: PCR_RESERVED_VALUE,
2329 opcr_reserved: PCR_RESERVED_VALUE,
2330 };
2331 let mut buf = vec![0u8; af.serialized_len()];
2332 af.serialize_into(&mut buf).unwrap();
2333 let decoded = AdaptationField::parse(&buf).unwrap();
2334 assert_eq!(decoded.extension.unwrap().piecewise_rate, Some(0x3FFFFF));
2335 }
2336
2337 #[test]
2339 fn adaptation_field_extension_seamless_splice_round_trip() {
2340 let af = AdaptationField {
2341 discontinuity_indicator: false,
2342 random_access_indicator: false,
2343 elementary_stream_priority_indicator: false,
2344 pcr: None,
2345 opcr: None,
2346 splice_countdown: None,
2347 transport_private_data: None,
2348 extension: Some(AdaptationFieldExtension {
2349 ltw: None,
2350 piecewise_rate: None,
2351 seamless_splice: Some(SeamlessSplice::new(0xA, 0x1_2345_6789)),
2352 ..AdaptationFieldExtension::new()
2353 }),
2354 stuffing: &[],
2355 pcr_reserved: PCR_RESERVED_VALUE,
2356 opcr_reserved: PCR_RESERVED_VALUE,
2357 };
2358 let mut buf = vec![0u8; af.serialized_len()];
2359 af.serialize_into(&mut buf).unwrap();
2360 let decoded = AdaptationField::parse(&buf).unwrap();
2361 let ss = decoded.extension.unwrap().seamless_splice.unwrap();
2362 assert_eq!(ss.splice_type, 0xA);
2363 assert_eq!(ss.dts_next_au, 0x1_2345_6789);
2364 }
2365
2366 #[test]
2368 fn adaptation_field_transport_private_data_round_trip() {
2369 let tpd = [0xDE, 0xAD, 0xBE, 0xEF];
2370 let af = AdaptationField {
2371 discontinuity_indicator: false,
2372 random_access_indicator: false,
2373 elementary_stream_priority_indicator: false,
2374 pcr: None,
2375 opcr: None,
2376 splice_countdown: None,
2377 transport_private_data: Some(&tpd),
2378 extension: None,
2379 stuffing: &[],
2380 pcr_reserved: PCR_RESERVED_VALUE,
2381 opcr_reserved: PCR_RESERVED_VALUE,
2382 };
2383 let mut buf = vec![0u8; af.serialized_len()];
2384 af.serialize_into(&mut buf).unwrap();
2385 let decoded = AdaptationField::parse(&buf).unwrap();
2386 assert_eq!(decoded.transport_private_data, Some(tpd.as_slice()));
2387 }
2388
2389 #[test]
2392 fn adaptation_field_stuffing_round_trip() {
2393 let af = AdaptationField {
2394 discontinuity_indicator: false,
2395 random_access_indicator: false,
2396 elementary_stream_priority_indicator: false,
2397 pcr: Some(Pcr {
2398 base: 12_345,
2399 extension: 7,
2400 }),
2401 opcr: None,
2402 splice_countdown: None,
2403 transport_private_data: None,
2404 extension: None,
2405 stuffing: &[0xFF; 20],
2406 pcr_reserved: PCR_RESERVED_VALUE,
2407 opcr_reserved: PCR_RESERVED_VALUE,
2408 };
2409 assert_eq!(af.serialized_len(), 27);
2411 let mut buf = vec![0u8; af.serialized_len()];
2412 af.serialize_into(&mut buf).unwrap();
2413 assert!(buf[7..27].iter().all(|&b| b == 0xFF));
2415 let decoded = AdaptationField::parse(&buf).unwrap();
2416 assert_eq!(decoded.stuffing.len(), 20);
2417 assert_eq!(decoded, af);
2418 let pure = AdaptationField {
2420 discontinuity_indicator: false,
2421 random_access_indicator: false,
2422 elementary_stream_priority_indicator: false,
2423 pcr: None,
2424 opcr: None,
2425 splice_countdown: None,
2426 transport_private_data: None,
2427 extension: None,
2428 stuffing: &[0xFF; 5],
2429 pcr_reserved: PCR_RESERVED_VALUE,
2430 opcr_reserved: PCR_RESERVED_VALUE,
2431 };
2432 let mut pbuf = vec![0u8; pure.serialized_len()];
2433 pure.serialize_into(&mut pbuf).unwrap();
2434 assert_eq!(pbuf, vec![0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]);
2435 assert_eq!(AdaptationField::parse(&pbuf).unwrap(), pure);
2436 }
2437
2438 #[test]
2440 fn adaptation_field_all_fields_round_trip() {
2441 let tpd = [0x01u8, 0x02, 0x03];
2442 let af = AdaptationField {
2443 discontinuity_indicator: true,
2444 random_access_indicator: false,
2445 elementary_stream_priority_indicator: false,
2446 pcr: Some(Pcr {
2447 base: 90_000,
2448 extension: 50,
2449 }),
2450 opcr: None,
2451 splice_countdown: Some(10),
2452 transport_private_data: Some(&tpd),
2453 extension: Some(AdaptationFieldExtension {
2454 ltw: Some(Ltw {
2455 ltw_valid_flag: false,
2456 ltw_offset: 500,
2457 }),
2458 piecewise_rate: Some(12345),
2459 seamless_splice: None,
2460 ..AdaptationFieldExtension::new()
2461 }),
2462 stuffing: &[],
2463 pcr_reserved: PCR_RESERVED_VALUE,
2464 opcr_reserved: PCR_RESERVED_VALUE,
2465 };
2466 let len = af.serialized_len();
2467 let mut buf = vec![0u8; len];
2468 af.serialize_into(&mut buf).unwrap();
2469 let decoded = AdaptationField::parse(&buf).unwrap();
2470 assert_eq!(decoded.pcr, af.pcr);
2471 assert_eq!(decoded.splice_countdown, af.splice_countdown);
2472 assert_eq!(decoded.transport_private_data, af.transport_private_data);
2473 assert_eq!(decoded.extension, af.extension);
2474 assert!(decoded.discontinuity_indicator);
2475 }
2476
2477 #[test]
2480 fn adaptation_field_serialize_from_real_packet_bytes() {
2481 let mut raw = [0xAAu8; TS_PACKET_SIZE];
2483 raw[0] = TS_SYNC_BYTE;
2484 raw[1] = 0x01;
2485 raw[2] = 0x00;
2486 raw[3] = ADAPTATION_FLAG | PAYLOAD_FLAG;
2487 raw[4] = 7;
2488 raw[5] = AF_DISCONTINUITY | AF_PCR_FLAG;
2489 raw[6..12].copy_from_slice(&[0x00, 0x00, 0x13, 0x88, 0x7E, 0x00]);
2490
2491 let pkt = TsPacket::parse(&raw).unwrap();
2492 let af = pkt.adaptation_field().unwrap().unwrap();
2493
2494 let mut ser = vec![0u8; af.serialized_len()];
2496 af.serialize_into(&mut ser).unwrap();
2497 let decoded = AdaptationField::parse(&ser).unwrap();
2498 assert_eq!(
2499 decoded.pcr,
2500 Some(Pcr {
2501 base: 10_000,
2502 extension: 0
2503 })
2504 );
2505 assert!(decoded.discontinuity_indicator);
2506 }
2507}