1use crate::error::{Error, Result};
4use crate::pid::Pid;
5
6pub const TS_PACKET_SIZE: usize = 188;
8pub const TS_SYNC_BYTE: u8 = 0x47;
10const MAX_SECTION_SIZE: usize = 4098;
15const SECTION_HEADER_LEN: usize = 3;
19pub(crate) const SECTION_LENGTH_HI_MASK: u8 = 0x0F;
23
24pub(crate) const STUFFING_BYTE: u8 = 0xFF;
26
27pub(crate) fn section_total_len(bytes: &[u8]) -> Option<usize> {
36 if bytes.len() < SECTION_HEADER_LEN {
37 return None;
38 }
39 let section_length = ((bytes[1] & SECTION_LENGTH_HI_MASK) as usize) << 8 | bytes[2] as usize;
40 Some(SECTION_HEADER_LEN + section_length)
41}
42
43#[non_exhaustive]
52#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53#[cfg_attr(feature = "serde", derive(serde::Serialize))]
54pub enum ScramblingControl {
55 NotScrambled,
57 Reserved,
59 EvenKey,
62 OddKey,
65}
66
67impl ScramblingControl {
68 pub fn from_bits(bits: u8) -> Self {
70 match bits & 0b11 {
71 0b00 => Self::NotScrambled,
72 0b01 => Self::Reserved,
73 0b10 => Self::EvenKey,
74 0b11 => Self::OddKey,
75 _ => unreachable!(),
76 }
77 }
78
79 pub fn to_bits(self) -> u8 {
84 match self {
85 Self::NotScrambled => 0b00,
86 Self::Reserved => 0b01,
87 Self::EvenKey => 0b10,
88 Self::OddKey => 0b11,
89 }
90 }
91
92 pub fn name(&self) -> &'static str {
94 match self {
95 Self::NotScrambled => "not_scrambled",
96 Self::Reserved => "reserved",
97 Self::EvenKey => "even_key",
98 Self::OddKey => "odd_key",
99 }
100 }
101}
102
103broadcast_common::impl_spec_display!(ScramblingControl);
104
105#[non_exhaustive]
111#[derive(Debug, Clone, Copy, PartialEq, Eq)]
112#[cfg_attr(feature = "serde", derive(serde::Serialize))]
113pub enum AdaptationFieldControl {
114 Reserved,
116 PayloadOnly,
118 AdaptationOnly,
120 AdaptationAndPayload,
122}
123
124impl AdaptationFieldControl {
125 pub fn from_flags(has_adaptation: bool, has_payload: bool) -> Self {
127 match (has_adaptation, has_payload) {
128 (false, false) => Self::Reserved,
129 (false, true) => Self::PayloadOnly,
130 (true, false) => Self::AdaptationOnly,
131 (true, true) => Self::AdaptationAndPayload,
132 }
133 }
134
135 pub fn to_bits(self) -> u8 {
141 match self {
142 Self::Reserved => 0b00,
143 Self::PayloadOnly => 0b01,
144 Self::AdaptationOnly => 0b10,
145 Self::AdaptationAndPayload => 0b11,
146 }
147 }
148
149 pub fn to_flags(self) -> (bool, bool) {
152 match self {
153 Self::Reserved => (false, false),
154 Self::PayloadOnly => (false, true),
155 Self::AdaptationOnly => (true, false),
156 Self::AdaptationAndPayload => (true, true),
157 }
158 }
159
160 pub fn name(&self) -> &'static str {
162 match self {
163 Self::Reserved => "reserved",
164 Self::PayloadOnly => "payload_only",
165 Self::AdaptationOnly => "adaptation_only",
166 Self::AdaptationAndPayload => "adaptation_and_payload",
167 }
168 }
169}
170
171broadcast_common::impl_spec_display!(AdaptationFieldControl);
172
173const TEI_MASK: u8 = 0x80;
175const PUSI_MASK: u8 = 0x40;
177pub const PID_MASK_HI: u8 = 0x1F;
179pub const SCRAMBLING_MASK: u8 = 0xC0;
181pub const ADAPTATION_FLAG: u8 = 0x20;
183pub const PAYLOAD_FLAG: u8 = 0x10;
185pub const CC_MASK: u8 = 0x0F;
187
188#[derive(Clone, Debug, PartialEq, Eq)]
190#[cfg_attr(feature = "serde", derive(serde::Serialize))]
191pub struct TsHeader {
192 pub tei: bool,
195 pub pusi: bool,
198 pub pid: Pid,
200 pub scrambling: u8,
202 pub has_adaptation: bool,
204 pub has_payload: bool,
206 pub continuity_counter: u8,
208}
209
210#[derive(Clone, Debug)]
216#[cfg_attr(feature = "serde", derive(serde::Serialize))]
217pub struct TsPacket<'a> {
218 pub header: TsHeader,
220 pub payload: Option<&'a [u8]>,
223 #[cfg_attr(feature = "serde", serde(skip))]
226 adaptation: Option<&'a [u8]>,
227 #[cfg_attr(feature = "serde", serde(skip))]
229 pub raw: &'a [u8; TS_PACKET_SIZE],
230}
231
232impl TsHeader {
233 pub fn parse(raw4: &[u8]) -> Result<Self> {
235 if raw4.len() < 4 {
236 return Err(Error::BufferTooShort {
237 need: 4,
238 have: raw4.len(),
239 what: "TsHeader",
240 });
241 }
242 let b1 = raw4[1];
243 let b2 = raw4[2];
244 let b3 = raw4[3];
245
246 let tei = (b1 & TEI_MASK) != 0;
247 let pusi = (b1 & PUSI_MASK) != 0;
248 let pid = Pid::new((((b1 & PID_MASK_HI) as u16) << 8) | (b2 as u16));
249 let scrambling = (b3 & SCRAMBLING_MASK) >> 6;
250 let has_adaptation = (b3 & ADAPTATION_FLAG) != 0;
251 let has_payload = (b3 & PAYLOAD_FLAG) != 0;
252 let continuity_counter = b3 & CC_MASK;
253
254 Ok(Self {
255 tei,
256 pusi,
257 pid,
258 scrambling,
259 has_adaptation,
260 has_payload,
261 continuity_counter,
262 })
263 }
264
265 pub const fn serialized_len() -> usize {
267 4
268 }
269
270 pub fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
272 if buf.len() < 4 {
273 return Err(Error::OutputBufferTooSmall {
274 need: 4,
275 have: buf.len(),
276 });
277 }
278 buf[0] = TS_SYNC_BYTE;
279 buf[1] = 0;
280 if self.tei {
281 buf[1] |= TEI_MASK;
282 }
283 if self.pusi {
284 buf[1] |= PUSI_MASK;
285 }
286 let pid = self.pid.value();
287 buf[1] |= ((pid >> 8) as u8) & PID_MASK_HI;
288 buf[2] = pid.to_be_bytes()[1];
289 buf[3] = (self.scrambling << 6) & SCRAMBLING_MASK;
290 if self.has_adaptation {
291 buf[3] |= ADAPTATION_FLAG;
292 }
293 if self.has_payload {
294 buf[3] |= PAYLOAD_FLAG;
295 }
296 buf[3] |= self.continuity_counter & CC_MASK;
297 Ok(4)
298 }
299
300 pub fn scrambling_control(&self) -> ScramblingControl {
305 ScramblingControl::from_bits(self.scrambling)
306 }
307
308 pub fn adaptation_field_control(&self) -> AdaptationFieldControl {
313 AdaptationFieldControl::from_flags(self.has_adaptation, self.has_payload)
314 }
315}
316
317impl<'a> broadcast_common::Parse<'a> for TsHeader {
318 type Error = Error;
319
320 fn parse(bytes: &'a [u8]) -> Result<Self> {
321 TsHeader::parse(bytes)
322 }
323}
324
325impl broadcast_common::Serialize for TsHeader {
326 type Error = Error;
327
328 fn serialized_len(&self) -> usize {
329 TsHeader::serialized_len()
330 }
331
332 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
333 TsHeader::serialize_into(self, buf)
334 }
335}
336
337fn adaptation_field_skip(pkt: &[u8], has_adaptation: bool) -> usize {
348 if !has_adaptation || pkt.len() <= 4 {
349 return 0;
350 }
351 let af_len = pkt[4] as usize;
352 1 + af_len
353}
354
355impl<'a> TsPacket<'a> {
356 pub fn parse(buf: &'a [u8]) -> Result<Self> {
362 if buf.len() < TS_PACKET_SIZE {
363 return Err(Error::BufferTooShort {
364 need: TS_PACKET_SIZE,
365 have: buf.len(),
366 what: "TsPacket",
367 });
368 }
369 if buf[0] != TS_SYNC_BYTE {
370 return Err(Error::InvalidSyncByte { found: buf[0] });
371 }
372
373 let raw: &[u8; TS_PACKET_SIZE] =
374 buf[..TS_PACKET_SIZE]
375 .try_into()
376 .map_err(|_| Error::BufferTooShort {
377 need: TS_PACKET_SIZE,
378 have: buf.len(),
379 what: "TsPacket::parse (array conversion)",
380 })?;
381
382 let header = TsHeader::parse(&raw[..4])?;
383
384 let mut cursor = 4usize;
385 let mut payload = None;
386 let mut adaptation = None;
387
388 if header.has_adaptation && cursor < TS_PACKET_SIZE {
401 let af_len = raw[cursor] as usize;
402 let af_start = cursor + 1;
403 if af_len > 0 && af_start < TS_PACKET_SIZE && af_start + af_len <= TS_PACKET_SIZE {
404 adaptation = Some(&raw[af_start..af_start + af_len]);
405 }
406 }
407 cursor += adaptation_field_skip(raw, header.has_adaptation);
412
413 if header.has_payload && cursor < TS_PACKET_SIZE {
414 payload = Some(&raw[cursor..]);
415 }
416
417 Ok(TsPacket {
418 header,
419 payload,
420 adaptation,
421 raw,
422 })
423 }
424
425 pub fn adaptation_field(&self) -> Option<crate::Result<AdaptationField<'a>>> {
431 self.adaptation.map(AdaptationField::parse)
432 }
433}
434
435pub(crate) const AF_DISCONTINUITY: u8 = 0x80;
437pub(crate) const AF_RANDOM_ACCESS: u8 = 0x40;
438pub(crate) const AF_ES_PRIORITY: u8 = 0x20;
439pub const AF_PCR_FLAG: u8 = 0x10;
441pub(crate) const AF_OPCR_FLAG: u8 = 0x08;
442pub(crate) const AF_SPLICING_FLAG: u8 = 0x04;
443pub(crate) const AF_TRANSPORT_PRIVATE_DATA_FLAG: u8 = 0x02;
444pub(crate) const AF_EXTENSION_FLAG: u8 = 0x01;
445const PCR_RESERVED_BITS: u8 = 0x7E;
448const PCR_RESERVED_SHIFT: u32 = 1;
450const PCR_RESERVED_VALUE: u8 = 0x3F;
452pub(crate) const PCR_FIELD_LEN: usize = 6;
454
455#[derive(Clone, Copy, Debug, PartialEq, Eq)]
458#[cfg_attr(feature = "serde", derive(serde::Serialize))]
459pub struct Pcr {
460 pub base: u64,
462 pub extension: u16,
464}
465
466impl Pcr {
467 #[must_use]
471 pub fn as_27mhz(self) -> u64 {
472 broadcast_common::clock33::pcr_from_parts(self.base, self.extension)
473 }
474
475 #[must_use]
484 pub fn from_27mhz(ticks: u64) -> Self {
485 let (base, extension) = broadcast_common::clock33::pcr_split(ticks);
486 Self { base, extension }
487 }
488
489 #[must_use]
498 pub fn to_field_bytes(self) -> [u8; PCR_FIELD_LEN] {
499 let b = self.base;
500 let e = self.extension as u64;
501 [
502 ((b >> 25) & 0xFF) as u8,
503 ((b >> 17) & 0xFF) as u8,
504 ((b >> 9) & 0xFF) as u8,
505 ((b >> 1) & 0xFF) as u8,
506 (((b & 0x01) as u8) << 7) | PCR_RESERVED_BITS | ((e >> 8) as u8 & 0x01),
508 (e & 0xFF) as u8,
509 ]
510 }
511
512 pub(crate) fn parse(af: &[u8], at: usize) -> Result<Self> {
514 let b: &[u8; PCR_FIELD_LEN] = af
515 .get(at..at + PCR_FIELD_LEN)
516 .and_then(|s| s.try_into().ok())
517 .ok_or(Error::BufferTooShort {
518 need: at + PCR_FIELD_LEN,
519 have: af.len(),
520 what: "adaptation_field PCR",
521 })?;
522 let base = ((b[0] as u64) << 25)
523 | ((b[1] as u64) << 17)
524 | ((b[2] as u64) << 9)
525 | ((b[3] as u64) << 1)
526 | ((b[4] as u64) >> 7);
527 let extension = (((b[4] & 0x01) as u16) << 8) | (b[5] as u16);
528 Ok(Self { base, extension })
529 }
530}
531
532#[derive(Clone, Copy, Debug, PartialEq, Eq)]
539#[cfg_attr(feature = "serde", derive(serde::Serialize))]
540pub struct Ltw {
541 pub ltw_valid_flag: bool,
543 pub ltw_offset: u16,
545}
546
547#[non_exhaustive]
556#[derive(Clone, Copy, Debug, PartialEq, Eq)]
557#[cfg_attr(feature = "serde", derive(serde::Serialize))]
558pub struct SeamlessSplice {
559 pub splice_type: u8,
561 pub dts_next_au: u64,
563 pub marker_bits: u8,
568}
569
570impl SeamlessSplice {
571 #[must_use]
573 pub const fn new(splice_type: u8, dts_next_au: u64) -> Self {
574 Self {
575 splice_type,
576 dts_next_au,
577 marker_bits: SPLICE_MARKERS_VALUE,
578 }
579 }
580}
581
582const SPLICE_MARKERS_VALUE: u8 = 0x07;
586const AFE_LTW_FLAG: u8 = 0x80;
587const AFE_PIECEWISE_RATE_FLAG: u8 = 0x40;
588const AFE_SEAMLESS_SPLICE_FLAG: u8 = 0x20;
589const LTW_OFFSET_HI_MASK: u8 = 0x7F;
591const PIECEWISE_RATE_HI_MASK: u8 = 0x3F;
593const AFE_AF_DESCRIPTOR_NOT_PRESENT_FLAG: u8 = 0x10;
595const AFE_RESERVED_FLAGS_MASK: u8 = 0x0F;
597const AFE_RESERVED_FLAGS_VALUE: u8 = 0x0F;
599const PIECEWISE_RATE_RESERVED_SHIFT: u32 = 6;
601const PIECEWISE_RATE_RESERVED_VALUE: u8 = 0x03;
603
604#[non_exhaustive]
624#[derive(Clone, Copy, Debug, PartialEq, Eq)]
625#[cfg_attr(feature = "serde", derive(serde::Serialize))]
626pub struct AdaptationFieldExtension<'a> {
627 pub ltw: Option<Ltw>,
629 pub piecewise_rate: Option<u32>,
631 pub piecewise_rate_reserved: u8,
634 pub seamless_splice: Option<SeamlessSplice>,
636 pub af_descriptor_not_present_flag: bool,
640 pub reserved_flags: u8,
642 pub trailing: &'a [u8],
646}
647
648impl Default for AdaptationFieldExtension<'_> {
649 fn default() -> Self {
650 Self::new()
651 }
652}
653
654impl<'a> AdaptationFieldExtension<'a> {
655 #[must_use]
658 pub const fn new() -> Self {
659 Self {
660 ltw: None,
661 piecewise_rate: None,
662 piecewise_rate_reserved: PIECEWISE_RATE_RESERVED_VALUE,
663 seamless_splice: None,
664 af_descriptor_not_present_flag: true,
665 reserved_flags: AFE_RESERVED_FLAGS_VALUE,
666 trailing: &[],
667 }
668 }
669
670 fn parse(data: &'a [u8]) -> Result<Self> {
673 if data.is_empty() {
674 return Err(Error::BufferTooShort {
675 need: 1,
676 have: 0,
677 what: "adaptation_field_extension_length",
678 });
679 }
680 let ext_len = data[0] as usize;
681 if data.len() < 1 + ext_len || ext_len < 1 {
683 return Err(Error::BufferTooShort {
684 need: 2.max(1 + ext_len),
685 have: data.len(),
686 what: "adaptation_field_extension body",
687 });
688 }
689 let ext = &data[1..1 + ext_len]; let flags = ext[0];
691 let mut cursor = 1usize;
692
693 let ltw = if flags & AFE_LTW_FLAG != 0 {
694 if ext.len() < cursor + 2 {
695 return Err(Error::BufferTooShort {
696 need: cursor + 2,
697 have: ext.len(),
698 what: "ltw_offset",
699 });
700 }
701 let w0 = ext[cursor];
702 let w1 = ext[cursor + 1];
703 cursor += 2;
704 Some(Ltw {
705 ltw_valid_flag: (w0 & AFE_LTW_FLAG) != 0,
706 ltw_offset: (((w0 & LTW_OFFSET_HI_MASK) as u16) << 8) | (w1 as u16),
707 })
708 } else {
709 None
710 };
711
712 let mut piecewise_rate_reserved = PIECEWISE_RATE_RESERVED_VALUE;
713 let piecewise_rate = if flags & AFE_PIECEWISE_RATE_FLAG != 0 {
714 if ext.len() < cursor + 3 {
715 return Err(Error::BufferTooShort {
716 need: cursor + 3,
717 have: ext.len(),
718 what: "piecewise_rate",
719 });
720 }
721 piecewise_rate_reserved = ext[cursor] >> PIECEWISE_RATE_RESERVED_SHIFT;
722 let r = (((ext[cursor] & PIECEWISE_RATE_HI_MASK) as u32) << 16)
723 | ((ext[cursor + 1] as u32) << 8)
724 | (ext[cursor + 2] as u32);
725 cursor += 3;
726 Some(r)
727 } else {
728 None
729 };
730
731 let seamless_splice = if flags & AFE_SEAMLESS_SPLICE_FLAG != 0 {
733 if ext.len() < cursor + 5 {
734 return Err(Error::BufferTooShort {
735 need: cursor + 5,
736 have: ext.len(),
737 what: "seamless_splice DTS_next_AU",
738 });
739 }
740 let b = &ext[cursor..cursor + 5];
741 let field: &[u8; 5] = b.try_into().expect("slice is exactly 5 bytes");
744 let m = broadcast_common::clock33::unpack_marked(field);
745 let (splice_type, dts_next_au) = (m.prefix, m.timestamp);
746 cursor += 5;
747 Some(SeamlessSplice {
748 splice_type,
749 dts_next_au,
750 marker_bits: m.markers,
751 })
752 } else {
753 None
754 };
755
756 Ok(AdaptationFieldExtension {
757 ltw,
758 piecewise_rate,
759 piecewise_rate_reserved,
760 seamless_splice,
761 af_descriptor_not_present_flag: flags & AFE_AF_DESCRIPTOR_NOT_PRESENT_FLAG != 0,
762 reserved_flags: flags & AFE_RESERVED_FLAGS_MASK,
763 trailing: &ext[cursor..],
764 })
765 }
766
767 #[must_use]
770 pub fn serialized_len(&self) -> usize {
771 let body = 1 + self.ltw.map_or(0, |_| 2)
773 + self.piecewise_rate.map_or(0, |_| 3)
774 + self.seamless_splice.map_or(0, |_| 5)
775 + self.trailing.len();
776 1 + body }
778
779 pub fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
781 let need = self.serialized_len();
782 if buf.len() < need {
783 return Err(Error::OutputBufferTooSmall {
784 need,
785 have: buf.len(),
786 });
787 }
788 buf[0] = broadcast_common::len::fit_u8(need - 1, "adaptation_field_extension_length")?;
789
790 let mut flags = broadcast_common::len::fit_mask(
791 self.reserved_flags,
792 AFE_RESERVED_FLAGS_MASK,
793 "adaptation_field_extension.reserved",
794 )?;
795 if self.ltw.is_some() {
796 flags |= AFE_LTW_FLAG;
797 }
798 if self.piecewise_rate.is_some() {
799 flags |= AFE_PIECEWISE_RATE_FLAG;
800 }
801 if self.seamless_splice.is_some() {
802 flags |= AFE_SEAMLESS_SPLICE_FLAG;
803 }
804 if self.af_descriptor_not_present_flag {
805 flags |= AFE_AF_DESCRIPTOR_NOT_PRESENT_FLAG;
806 }
807 buf[1] = flags;
808 let mut cursor = 2usize;
809
810 if let Some(ltw) = self.ltw {
811 let ltw_valid = if ltw.ltw_valid_flag { AFE_LTW_FLAG } else { 0 };
812 buf[cursor] = ltw_valid | ((ltw.ltw_offset >> 8) as u8 & LTW_OFFSET_HI_MASK);
813 buf[cursor + 1] = (ltw.ltw_offset & 0xFF) as u8;
814 cursor += 2;
815 }
816 if let Some(rate) = self.piecewise_rate {
817 buf[cursor] = (broadcast_common::len::fit_mask(
819 self.piecewise_rate_reserved,
820 PIECEWISE_RATE_RESERVED_VALUE,
821 "piecewise_rate.reserved",
822 )? << PIECEWISE_RATE_RESERVED_SHIFT)
823 | ((rate >> 16) as u8 & PIECEWISE_RATE_HI_MASK);
824 buf[cursor + 1] = (rate >> 8) as u8;
825 buf[cursor + 2] = rate as u8;
826 cursor += 3;
827 }
828 if let Some(ss) = self.seamless_splice {
829 buf[cursor..cursor + 5].copy_from_slice(&broadcast_common::clock33::pack_marked_with(
831 ss.dts_next_au,
832 ss.splice_type,
833 ss.marker_bits,
834 ));
835 cursor += 5;
836 }
837 buf[cursor..cursor + self.trailing.len()].copy_from_slice(self.trailing);
838 cursor += self.trailing.len();
839 Ok(cursor)
840 }
841}
842
843#[non_exhaustive]
852#[derive(Clone, Debug, PartialEq, Eq)]
853#[cfg_attr(feature = "serde", derive(serde::Serialize))]
854pub struct AdaptationField<'a> {
855 pub discontinuity_indicator: bool,
857 pub random_access_indicator: bool,
859 pub elementary_stream_priority_indicator: bool,
861 pub pcr: Option<Pcr>,
863 pub opcr: Option<Pcr>,
865 pub splice_countdown: Option<i8>,
867 pub transport_private_data: Option<&'a [u8]>,
872 pub extension: Option<AdaptationFieldExtension<'a>>,
874 pub pcr_reserved: u8,
880 pub opcr_reserved: u8,
882 pub stuffing: &'a [u8],
892}
893
894impl Default for AdaptationField<'_> {
895 fn default() -> Self {
896 Self::new()
897 }
898}
899
900fn set_pcr_reserved(field: &mut [u8], reserved: u8) {
902 field[4] =
903 (field[4] & !PCR_RESERVED_BITS) | ((reserved << PCR_RESERVED_SHIFT) & PCR_RESERVED_BITS);
904}
905
906impl<'a> AdaptationField<'a> {
907 #[must_use]
911 pub const fn new() -> Self {
912 Self {
913 discontinuity_indicator: false,
914 random_access_indicator: false,
915 elementary_stream_priority_indicator: false,
916 pcr: None,
917 opcr: None,
918 splice_countdown: None,
919 transport_private_data: None,
920 extension: None,
921 pcr_reserved: PCR_RESERVED_VALUE,
922 opcr_reserved: PCR_RESERVED_VALUE,
923 stuffing: &[],
924 }
925 }
926
927 pub(crate) fn parse(af: &'a [u8]) -> Result<Self> {
934 let flags = *af.first().ok_or(Error::BufferTooShort {
935 need: 1,
936 have: 0,
937 what: "adaptation_field flags",
938 })?;
939 let mut cursor = 1usize;
940
941 let mut pcr_reserved = PCR_RESERVED_VALUE;
942 let mut opcr_reserved = PCR_RESERVED_VALUE;
943 let pcr = if flags & AF_PCR_FLAG != 0 {
944 let p = Pcr::parse(af, cursor)?;
945 pcr_reserved = (af[cursor + 4] & PCR_RESERVED_BITS) >> PCR_RESERVED_SHIFT;
946 cursor += PCR_FIELD_LEN;
947 Some(p)
948 } else {
949 None
950 };
951 let opcr = if flags & AF_OPCR_FLAG != 0 {
952 let p = Pcr::parse(af, cursor)?;
953 opcr_reserved = (af[cursor + 4] & PCR_RESERVED_BITS) >> PCR_RESERVED_SHIFT;
954 cursor += PCR_FIELD_LEN;
955 Some(p)
956 } else {
957 None
958 };
959 let splice_countdown = if flags & AF_SPLICING_FLAG != 0 {
960 let b = *af.get(cursor).ok_or(Error::BufferTooShort {
961 need: cursor + 1,
962 have: af.len(),
963 what: "adaptation_field splice_countdown",
964 })?;
965 cursor += 1;
966 Some(b as i8)
967 } else {
968 None
969 };
970
971 let transport_private_data = if flags & AF_TRANSPORT_PRIVATE_DATA_FLAG != 0 {
974 let tpd_len = *af.get(cursor).ok_or(Error::BufferTooShort {
975 need: cursor + 1,
976 have: af.len(),
977 what: "transport_private_data_length",
978 })? as usize;
979 cursor += 1;
980 let end = cursor + tpd_len;
981 let slice = af.get(cursor..end).ok_or(Error::BufferTooShort {
982 need: end,
983 have: af.len(),
984 what: "transport_private_data",
985 })?;
986 cursor = end;
987 Some(slice)
988 } else {
989 None
990 };
991
992 let extension = if flags & AF_EXTENSION_FLAG != 0 {
994 let ext_data = af.get(cursor..).ok_or(Error::BufferTooShort {
995 need: cursor + 1,
996 have: af.len(),
997 what: "adaptation_field_extension",
998 })?;
999 let ext = AdaptationFieldExtension::parse(ext_data)?;
1000 if !ext_data.is_empty() {
1002 let _ext_len = ext_data[0] as usize;
1003 cursor += 1 + _ext_len;
1004 }
1005 Some(ext)
1006 } else {
1007 None
1008 };
1009
1010 let stuffing = af.get(cursor..).unwrap_or(&[]);
1014
1015 Ok(AdaptationField {
1016 discontinuity_indicator: flags & AF_DISCONTINUITY != 0,
1017 random_access_indicator: flags & AF_RANDOM_ACCESS != 0,
1018 elementary_stream_priority_indicator: flags & AF_ES_PRIORITY != 0,
1019 pcr,
1020 opcr,
1021 splice_countdown,
1022 transport_private_data,
1023 extension,
1024 pcr_reserved,
1025 opcr_reserved,
1026 stuffing,
1027 })
1028 }
1029
1030 #[must_use]
1036 pub fn serialized_len(&self) -> usize {
1037 let mut n = 1usize; if self.pcr.is_some() {
1039 n += PCR_FIELD_LEN;
1040 }
1041 if self.opcr.is_some() {
1042 n += PCR_FIELD_LEN;
1043 }
1044 if self.splice_countdown.is_some() {
1045 n += 1;
1046 }
1047 if let Some(tpd) = self.transport_private_data {
1048 n += 1 + tpd.len(); }
1050 if let Some(ref ext) = self.extension {
1051 n += ext.serialized_len();
1052 }
1053 n += self.stuffing.len();
1054 n
1055 }
1056
1057 pub fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
1068 let need = self.serialized_len();
1069 if buf.len() < need {
1070 return Err(Error::OutputBufferTooSmall {
1071 need,
1072 have: buf.len(),
1073 });
1074 }
1075
1076 let mut flags = 0u8;
1078 if self.discontinuity_indicator {
1079 flags |= AF_DISCONTINUITY;
1080 }
1081 if self.random_access_indicator {
1082 flags |= AF_RANDOM_ACCESS;
1083 }
1084 if self.elementary_stream_priority_indicator {
1085 flags |= AF_ES_PRIORITY;
1086 }
1087 if self.pcr.is_some() {
1088 flags |= AF_PCR_FLAG;
1089 }
1090 if self.opcr.is_some() {
1091 flags |= AF_OPCR_FLAG;
1092 }
1093 if self.splice_countdown.is_some() {
1094 flags |= AF_SPLICING_FLAG;
1095 }
1096 if self.transport_private_data.is_some() {
1097 flags |= AF_TRANSPORT_PRIVATE_DATA_FLAG;
1098 }
1099 if self.extension.is_some() {
1100 flags |= AF_EXTENSION_FLAG;
1101 }
1102 buf[0] = flags;
1103
1104 let mut cursor = 1usize;
1105 if let Some(pcr) = self.pcr {
1106 buf[cursor..cursor + PCR_FIELD_LEN].copy_from_slice(&pcr.to_field_bytes());
1107 set_pcr_reserved(&mut buf[cursor..cursor + PCR_FIELD_LEN], self.pcr_reserved);
1108 cursor += PCR_FIELD_LEN;
1109 }
1110 if let Some(opcr) = self.opcr {
1111 buf[cursor..cursor + PCR_FIELD_LEN].copy_from_slice(&opcr.to_field_bytes());
1112 set_pcr_reserved(&mut buf[cursor..cursor + PCR_FIELD_LEN], self.opcr_reserved);
1113 cursor += PCR_FIELD_LEN;
1114 }
1115 if let Some(sc) = self.splice_countdown {
1116 buf[cursor] = sc as u8;
1117 cursor += 1;
1118 }
1119 if let Some(tpd) = self.transport_private_data {
1120 buf[cursor] = broadcast_common::len::fit_u8(
1121 tpd.len(),
1122 "adaptation_field.transport_private_data_length",
1123 )?;
1124 cursor += 1;
1125 buf[cursor..cursor + tpd.len()].copy_from_slice(tpd);
1126 cursor += tpd.len();
1127 }
1128 if let Some(ref ext) = self.extension {
1129 let written = ext.serialize_into(&mut buf[cursor..])?;
1130 cursor += written;
1131 }
1132
1133 buf[cursor..cursor + self.stuffing.len()].copy_from_slice(self.stuffing);
1136 cursor += self.stuffing.len();
1137
1138 Ok(cursor)
1139 }
1140}
1141
1142#[derive(Default)]
1147pub struct SectionReassembler {
1148 buf: bytes::BytesMut,
1149 ready: alloc::collections::VecDeque<bytes::Bytes>,
1150}
1151
1152impl SectionReassembler {
1153 pub fn feed(&mut self, payload: &[u8], pusi: bool) {
1161 if pusi {
1162 if payload.is_empty() {
1165 self.buf.clear();
1166 return;
1167 }
1168 let pointer = payload[0] as usize;
1169
1170 if !self.buf.is_empty() && pointer > 0 {
1178 let avail = payload.len() - 1;
1179 let tail_len = pointer.min(avail);
1180 if self.buf.len() + tail_len > MAX_SECTION_SIZE {
1181 self.buf.clear();
1182 } else {
1183 self.buf.extend_from_slice(&payload[1..1 + tail_len]);
1184 self.drain_complete_sections();
1185 }
1186 }
1187
1188 self.buf.clear();
1191
1192 let start = 1 + pointer;
1193 if start >= payload.len() {
1194 return;
1196 }
1197 let new_data = &payload[start..];
1198 if new_data.len() > MAX_SECTION_SIZE {
1199 return;
1200 }
1201 self.buf.extend_from_slice(new_data);
1202 } else {
1203 if self.buf.is_empty() {
1204 return;
1205 }
1206 let take = if let Some(exp) = section_total_len(&self.buf) {
1216 exp.saturating_sub(self.buf.len()).min(payload.len())
1217 } else {
1218 payload.len().min(MAX_SECTION_SIZE - self.buf.len())
1222 };
1223 self.buf.extend_from_slice(&payload[..take]);
1224 }
1225
1226 self.drain_complete_sections();
1227 }
1228
1229 fn drain_complete_sections(&mut self) {
1240 loop {
1241 if self.buf.len() < SECTION_HEADER_LEN {
1242 break;
1245 }
1246 if self.buf[0] == STUFFING_BYTE {
1247 self.buf.clear();
1249 break;
1250 }
1251 let exp =
1252 section_total_len(&self.buf).expect("checked len >= SECTION_HEADER_LEN above");
1253 if self.buf.len() >= exp {
1254 let section = self.buf.split_to(exp).freeze();
1257 self.ready.push_back(section);
1258 } else {
1259 break;
1261 }
1262 }
1263 }
1264
1265 pub fn pop_section(&mut self) -> Option<bytes::Bytes> {
1267 self.ready.pop_front()
1268 }
1269
1270 pub fn len(&self) -> usize {
1272 self.buf.len()
1273 }
1274
1275 pub fn is_empty(&self) -> bool {
1277 self.buf.is_empty()
1278 }
1279}
1280
1281pub fn iter_packets(buf: &[u8]) -> impl Iterator<Item = TsPacket<'_>> {
1299 buf.chunks_exact(TS_PACKET_SIZE)
1300 .filter_map(|chunk| TsPacket::parse(chunk).ok())
1301}
1302
1303pub fn extract_ts_payload(pkt: &[u8]) -> Option<&[u8]> {
1313 if pkt.len() < 4 {
1314 return None;
1315 }
1316 let header = TsHeader::parse(&pkt[..4]).ok()?;
1317 if !header.has_payload {
1318 return None;
1319 }
1320 let cursor = 4 + adaptation_field_skip(pkt, header.has_adaptation);
1321 if cursor < pkt.len() {
1322 Some(&pkt[cursor..])
1323 } else {
1324 None
1325 }
1326}
1327
1328#[cfg(test)]
1329mod tests {
1330 use super::*;
1331 use alloc::string::ToString;
1332 use alloc::vec;
1333 use alloc::vec::Vec;
1334
1335 fn make_packet(b1: u8, b2: u8, b3: u8, payload_data: &[u8]) -> [u8; TS_PACKET_SIZE] {
1337 let mut pkt = [0u8; TS_PACKET_SIZE];
1338 pkt[0] = TS_SYNC_BYTE;
1339 pkt[1] = b1;
1340 pkt[2] = b2;
1341 pkt[3] = b3;
1342 let payload_start = 4;
1343 let end = (payload_start + payload_data.len()).min(TS_PACKET_SIZE);
1344 let len = (end - payload_start).min(payload_data.len());
1345 pkt[payload_start..payload_start + len].copy_from_slice(&payload_data[..len]);
1346 pkt
1347 }
1348
1349 #[test]
1350 fn parse_rejects_non_0x47_sync_byte() {
1351 let mut pkt = [0u8; TS_PACKET_SIZE];
1352 pkt[0] = 0x46; let err = TsPacket::parse(&pkt).unwrap_err();
1354 match err {
1355 Error::InvalidSyncByte { found } => assert_eq!(found, 0x46),
1356 other => panic!("expected InvalidSyncByte, got {other:?}"),
1357 }
1358 }
1359
1360 #[test]
1361 fn ts_header_round_trip() {
1362 let cases = [
1365 TsHeader {
1366 tei: false,
1367 pusi: true,
1368 pid: Pid::new(0x0000),
1369 scrambling: 0,
1370 has_adaptation: false,
1371 has_payload: true,
1372 continuity_counter: 0,
1373 },
1374 TsHeader {
1375 tei: true,
1376 pusi: false,
1377 pid: Pid::new(0x1FFF),
1378 scrambling: 0b11,
1379 has_adaptation: true,
1380 has_payload: true,
1381 continuity_counter: 0x0F,
1382 },
1383 TsHeader {
1384 tei: false,
1385 pusi: false,
1386 pid: Pid::new(0x0100),
1387 scrambling: 0b10,
1388 has_adaptation: true,
1389 has_payload: false,
1390 continuity_counter: 7,
1391 },
1392 ];
1393 for h in cases {
1394 let mut buf = [0u8; 4];
1395 assert_eq!(h.serialize_into(&mut buf).unwrap(), 4);
1396 assert_eq!(TsHeader::parse(&buf).unwrap(), h, "round-trip mismatch");
1397 }
1398 }
1399
1400 #[test]
1401 fn parse_extracts_pid_and_continuity_counter() {
1402 let pkt = make_packet(0x12, 0x34, 0x05, &[]);
1408 let pkt = TsPacket::parse(&pkt).unwrap();
1409 assert_eq!(pkt.header.pid, Pid::new(0x1234));
1410 assert_eq!(pkt.header.continuity_counter, 5);
1411 }
1412
1413 #[test]
1414 fn payload_unit_start_indicator_flag_extracted() {
1415 let pkt1 = make_packet(0x40, 0x00, 0x00, &[]);
1417 let pkt1 = TsPacket::parse(&pkt1).unwrap();
1418 assert!(pkt1.header.pusi);
1419
1420 let pkt2 = make_packet(0x00, 0x00, 0x00, &[]);
1422 let pkt2 = TsPacket::parse(&pkt2).unwrap();
1423 assert!(!pkt2.header.pusi);
1424 }
1425
1426 fn build_pusi_payload(pointer_field: u8, previous_tail: &[u8], section: &[u8]) -> Vec<u8> {
1431 assert_eq!(pointer_field as usize, previous_tail.len());
1432 let mut v = Vec::with_capacity(1 + previous_tail.len() + section.len());
1433 v.push(pointer_field);
1434 v.extend_from_slice(previous_tail);
1435 v.extend_from_slice(section);
1436 v
1437 }
1438
1439 fn build_section(table_id: u8, body_after_length: &[u8]) -> Vec<u8> {
1443 let section_length = body_after_length.len() as u16;
1444 let mut v = Vec::with_capacity(3 + section_length as usize);
1445 v.push(table_id);
1446 v.push(0xB0 | ((section_length >> 8) as u8 & 0x0F));
1448 v.push((section_length & 0xFF) as u8);
1449 v.extend_from_slice(body_after_length);
1450 v
1451 }
1452
1453 #[test]
1459 fn reassembler_accumulates_multi_packet_section() {
1460 let body = vec![0xAAu8; 197];
1462 let section = build_section(0x02, &body);
1463 assert_eq!(section.len(), 200);
1464
1465 let first_chunk = 100;
1466 let payload1 = build_pusi_payload(0, &[], §ion[..first_chunk]);
1467 let payload2 = section[first_chunk..].to_vec();
1468
1469 let mut reasm = SectionReassembler::default();
1470 reasm.feed(&payload1, true);
1471 reasm.feed(&payload2, false);
1472
1473 let out = reasm.pop_section().expect("section should be ready");
1474 assert_eq!(out.len(), 200);
1475 assert_eq!(out.as_ref(), §ion[..]);
1476 }
1477
1478 #[test]
1479 fn reassembler_yields_complete_section_once_length_satisfied() {
1480 let section = build_section(0x42, &[0xAA]);
1482 assert_eq!(section.len(), 4);
1483 let payload = build_pusi_payload(0, &[], §ion);
1484
1485 let mut reasm = SectionReassembler::default();
1486 reasm.feed(&payload, true);
1487
1488 let out = reasm
1489 .pop_section()
1490 .expect("single-packet section should pop");
1491 assert_eq!(out.as_ref(), §ion[..]);
1492 }
1493
1494 #[test]
1495 fn reassembler_extracts_all_concatenated_sections_in_one_payload() {
1496 let s1 = build_section(0x42, &[0x11, 0x22]); let s2 = build_section(0x46, &[0x33]); let s3 = build_section(0x4A, &[0x44, 0x55, 0x66]); let mut concat = Vec::new();
1505 concat.extend_from_slice(&s1);
1506 concat.extend_from_slice(&s2);
1507 concat.extend_from_slice(&s3);
1508 let payload = build_pusi_payload(0, &[], &concat);
1509
1510 let mut reasm = SectionReassembler::default();
1511 reasm.feed(&payload, true);
1512
1513 let got: Vec<_> = core::iter::from_fn(|| reasm.pop_section()).collect();
1515 assert_eq!(got.len(), 3, "all three concatenated sections must pop");
1516 assert_eq!(got[0].as_ref(), &s1[..]);
1517 assert_eq!(got[1].as_ref(), &s2[..]);
1518 assert_eq!(got[2].as_ref(), &s3[..]);
1519 }
1520
1521 #[test]
1522 fn reassembler_stops_at_stuffing_after_concatenated_sections() {
1523 let s1 = build_section(0x42, &[0xAA]); let s2 = build_section(0x46, &[0xBB, 0xCC]); let mut concat = Vec::new();
1529 concat.extend_from_slice(&s1);
1530 concat.extend_from_slice(&s2);
1531 concat.extend_from_slice(&[0xFF, 0xFF, 0xFF, 0xFF]); let payload = build_pusi_payload(0, &[], &concat);
1533
1534 let mut reasm = SectionReassembler::default();
1535 reasm.feed(&payload, true);
1536
1537 let got: Vec<_> = core::iter::from_fn(|| reasm.pop_section()).collect();
1538 assert_eq!(got.len(), 2);
1539 assert_eq!(got[0].as_ref(), &s1[..]);
1540 assert_eq!(got[1].as_ref(), &s2[..]);
1541 assert!(
1542 reasm.is_empty(),
1543 "stuffing tail must be discarded, not buffered"
1544 );
1545 }
1546
1547 #[test]
1548 fn reassembler_concatenated_then_spanning_tail() {
1549 let s1 = build_section(0x42, &[0x01, 0x02]); let s2 = build_section(0x46, &[0x09u8; 60]); let split = 30;
1555
1556 let mut head = Vec::new();
1557 head.extend_from_slice(&s1);
1558 head.extend_from_slice(&s2[..split]);
1559 let payload1 = build_pusi_payload(0, &[], &head);
1560 let payload2 = s2[split..].to_vec();
1561
1562 let mut reasm = SectionReassembler::default();
1563 reasm.feed(&payload1, true);
1564 let first = reasm.pop_section().expect("first section pops at once");
1565 assert_eq!(first.as_ref(), &s1[..]);
1566 assert!(reasm.pop_section().is_none(), "second is still partial");
1567
1568 reasm.feed(&payload2, false);
1569 let second = reasm.pop_section().expect("second pops after continuation");
1570 assert_eq!(second.as_ref(), &s2[..]);
1571 }
1572
1573 #[test]
1574 fn reassembler_completes_section_spanning_into_pusi_packet() {
1575 let spanning = build_section(0x42, &[0x5Au8; 62]); let head = 41;
1583 let tail = &spanning[head..]; assert_eq!(tail.len(), 24);
1585
1586 let next = build_section(0x46, &[0x77, 0x88]); let payload_a = build_pusi_payload(0, &[], &spanning[..head]);
1591 let payload_b = build_pusi_payload(24, tail, &next);
1593
1594 let mut reasm = SectionReassembler::default();
1595 reasm.feed(&payload_a, true);
1596 assert!(reasm.pop_section().is_none(), "head alone is incomplete");
1597
1598 reasm.feed(&payload_b, true);
1599 let got: Vec<_> = core::iter::from_fn(|| reasm.pop_section()).collect();
1600 assert_eq!(got.len(), 2, "spanning section + new section must both pop");
1601 assert_eq!(
1602 got[0].as_ref(),
1603 &spanning[..],
1604 "spanning section completed from B's pointer tail"
1605 );
1606 assert_eq!(got[1].as_ref(), &next[..]);
1607 }
1608
1609 #[test]
1610 fn reassembler_pusi_pointer_spans_whole_payload() {
1611 let spanning = build_section(0x42, &[0x33u8; 40]); let head = 20;
1616 let payload_a = build_pusi_payload(0, &[], &spanning[..head]);
1617 let tail = &spanning[head..]; let mut reasm = SectionReassembler::default();
1620 reasm.feed(&payload_a, true);
1621 reasm.feed(&build_pusi_payload_pointer_spanning_all(tail), true);
1623
1624 let out = reasm.pop_section().expect("spanning section completes");
1625 assert_eq!(out.as_ref(), &spanning[..]);
1626 assert!(reasm.pop_section().is_none());
1627 }
1628
1629 fn build_pusi_payload_pointer_spanning_all(tail: &[u8]) -> Vec<u8> {
1632 let mut v = Vec::with_capacity(1 + tail.len());
1633 v.push(tail.len() as u8);
1634 v.extend_from_slice(tail);
1635 v
1636 }
1637
1638 #[test]
1639 fn reassembler_completes_max_length_section_and_stays_usable() {
1640 let mut section = Vec::with_capacity(MAX_SECTION_SIZE);
1646 section.push(0x00); section.push(0xB0 | ((4095u16 >> 8) as u8 & 0x0F));
1648 section.push(0xFF); section.resize(MAX_SECTION_SIZE, 0u8);
1650 assert_eq!(section.len(), MAX_SECTION_SIZE);
1651
1652 let mut reasm = SectionReassembler::default();
1653 let mut first = vec![0x00u8]; first.extend_from_slice(§ion[..183]);
1655 reasm.feed(&first, true);
1656 assert!(
1657 reasm.pop_section().is_none(),
1658 "incomplete until the declared length arrives"
1659 );
1660
1661 for chunk in section[183..].chunks(184) {
1662 reasm.feed(chunk, false);
1663 }
1664 let out = reasm
1665 .pop_section()
1666 .expect("max-length section completes at its declared length");
1667 assert_eq!(out.len(), MAX_SECTION_SIZE);
1668 assert_eq!(out.as_ref(), §ion[..]);
1669 assert!(reasm.is_empty());
1670
1671 reasm.feed(&[0u8; 184], false);
1675 assert!(reasm.pop_section().is_none());
1676
1677 let valid_section = build_section(0x00, &[0xAA]);
1679 let payload2 = build_pusi_payload(0, &[], &valid_section);
1680 reasm.feed(&payload2, true);
1681 let out = reasm
1682 .pop_section()
1683 .expect("fresh section should pop after reset");
1684 assert_eq!(out.as_ref(), &valid_section[..]);
1685 }
1686
1687 #[test]
1688 fn reassembler_handles_pusi_with_nonzero_pointer_field() {
1689 let prior_tail = vec![0x11, 0x22, 0x33];
1691 let new_section = build_section(0x02, &[0xBB]);
1692 assert_eq!(new_section.len(), 4);
1693 let payload = build_pusi_payload(3, &prior_tail, &new_section);
1694
1695 let mut reasm = SectionReassembler::default();
1696 reasm.feed(&payload, true);
1697
1698 let out = reasm
1699 .pop_section()
1700 .expect("section after pointer_field skip should pop");
1701 assert_eq!(out.as_ref(), &new_section[..]);
1702 }
1703
1704 #[test]
1705 fn reassembler_ignores_continuation_before_pusi() {
1706 let pkt = make_packet(0x00, 0x00, PAYLOAD_FLAG, &[0xAA, 0xBB, 0xCC]);
1709
1710 let mut reasm = SectionReassembler::default();
1711 reasm.feed(&pkt[4..], false); assert!(
1714 reasm.pop_section().is_none(),
1715 "no section should appear without prior PUSI"
1716 );
1717 assert!(
1718 reasm.pop_section().is_none(),
1719 "second pop should also be none"
1720 );
1721 }
1722
1723 #[test]
1726 fn reassembler_empty_pusi_payload_does_not_panic() {
1727 let mut reasm = SectionReassembler::default();
1728 reasm.feed(&[], true);
1729 assert!(reasm.pop_section().is_none());
1730 let payload = vec![0x00u8, 0x72, 0x70, 0x01, 0x00];
1732 reasm.feed(&payload, true);
1733 assert!(reasm.pop_section().is_some());
1734 }
1735
1736 #[test]
1740 fn reassembler_accepts_maximal_private_section() {
1741 let mut section = vec![0x80u8, 0x7F, 0xFF]; section.resize(3 + 0xFFF, 0xAB);
1743
1744 let mut reasm = SectionReassembler::default();
1745 let mut first = vec![0x00];
1747 first.extend_from_slice(§ion[..183]);
1748 reasm.feed(&first, true);
1749 for chunk in section[183..].chunks(184) {
1750 reasm.feed(chunk, false);
1751 }
1752 let out = reasm.pop_section().expect("4098-byte section should pop");
1753 assert_eq!(out.len(), 4098);
1754 assert_eq!(out.as_ref(), §ion[..]);
1755 }
1756
1757 #[test]
1762 fn reassembler_completes_large_section_with_trailing_stuffing() {
1763 let body = vec![0x5Au8; 4096 - 3];
1764 let section = build_section(0x50, &body); assert_eq!(section.len(), 4096);
1766
1767 let mut reasm = SectionReassembler::default();
1768 let mut first = vec![0x00u8];
1770 first.extend_from_slice(§ion[..183]);
1771 reasm.feed(&first, true);
1772
1773 let mut pos = 183usize;
1777 while pos < section.len() {
1778 let take = (section.len() - pos).min(184);
1779 let mut payload = section[pos..pos + take].to_vec();
1780 if take < 184 {
1781 payload.resize(184, 0xFF); }
1783 reasm.feed(&payload, false);
1784 pos += take;
1785 }
1786
1787 let out = reasm
1788 .pop_section()
1789 .expect("4096-byte section must complete despite trailing stuffing (#148)");
1790 assert_eq!(out.len(), 4096);
1791 assert_eq!(out.as_ref(), §ion[..]);
1792 assert!(reasm.is_empty(), "stuffing tail must be discarded");
1793 }
1794
1795 #[test]
1798 fn pcr_as_27mhz_known_value() {
1799 assert_eq!(
1800 Pcr {
1801 base: 10_000,
1802 extension: 0
1803 }
1804 .as_27mhz(),
1805 3_000_000
1806 );
1807 assert_eq!(
1809 Pcr {
1810 base: 1,
1811 extension: 100
1812 }
1813 .as_27mhz(),
1814 400
1815 );
1816 }
1817
1818 #[test]
1819 fn pcr_decode_from_bytes() {
1820 let af = [0x10u8, 0x00, 0x00, 0x13, 0x88, 0x7E, 0x00];
1822 let pcr = Pcr::parse(&af, 1).expect("6 bytes present");
1823 assert_eq!(
1824 pcr,
1825 Pcr {
1826 base: 10_000,
1827 extension: 0
1828 }
1829 );
1830 assert_eq!(pcr.as_27mhz(), 3_000_000);
1831 }
1832
1833 #[test]
1834 fn adaptation_field_flags_and_pcr() {
1835 let mut raw = [0xAAu8; TS_PACKET_SIZE];
1836 raw[0] = TS_SYNC_BYTE;
1837 raw[1] = 0x01; raw[2] = 0x00;
1839 raw[3] = ADAPTATION_FLAG | PAYLOAD_FLAG;
1840 raw[4] = 7; raw[5] = AF_DISCONTINUITY | AF_PCR_FLAG;
1842 raw[6..12].copy_from_slice(&[0x00, 0x00, 0x13, 0x88, 0x7E, 0x00]);
1843 let pkt = TsPacket::parse(&raw).expect("valid packet");
1846 let af = pkt
1847 .adaptation_field()
1848 .expect("has adaptation field")
1849 .expect("adaptation field parses");
1850 assert!(af.discontinuity_indicator);
1851 assert!(!af.random_access_indicator);
1852 assert_eq!(
1853 af.pcr,
1854 Some(Pcr {
1855 base: 10_000,
1856 extension: 0
1857 })
1858 );
1859 assert_eq!(af.pcr.unwrap().as_27mhz(), 3_000_000);
1860 assert!(af.opcr.is_none());
1861 assert!(af.splice_countdown.is_none());
1862 let payload = pkt.payload.expect("payload present");
1864 assert_eq!(payload.len(), TS_PACKET_SIZE - 12);
1865 assert_eq!(payload[0], 0xAA);
1866 }
1867
1868 #[test]
1869 fn oversized_adaptation_field_length_is_rejected_not_truncated() {
1870 let mut raw = [0xAAu8; TS_PACKET_SIZE];
1876 raw[0] = TS_SYNC_BYTE;
1877 raw[1] = 0x01;
1878 raw[2] = 0x00;
1879 raw[3] = ADAPTATION_FLAG; raw[4] = 200; let pkt = TsPacket::parse(&raw).expect("header + af_len byte still parse");
1883 assert!(
1884 pkt.adaptation_field().is_none(),
1885 "an over-long adaptation field must be rejected, not truncated"
1886 );
1887 assert!(pkt.payload.is_none());
1888
1889 let owned = crate::owned::OwnedTsPacket::parse(raw).unwrap();
1891 assert!(owned.adaptation_field().is_none());
1892 }
1893
1894 #[test]
1895 fn no_adaptation_returns_none() {
1896 let mut raw = [0x00u8; TS_PACKET_SIZE];
1897 raw[0] = TS_SYNC_BYTE;
1898 raw[1] = 0x01;
1899 raw[3] = PAYLOAD_FLAG; let pkt = TsPacket::parse(&raw).expect("valid");
1901 assert!(pkt.adaptation_field().is_none());
1902 assert!(pkt.adaptation.is_none());
1903 }
1904
1905 #[test]
1906 fn adaptation_field_splice_countdown_negative() {
1907 let mut raw = [0xAAu8; TS_PACKET_SIZE];
1908 raw[0] = TS_SYNC_BYTE;
1909 raw[1] = 0x01;
1910 raw[2] = 0x00;
1911 raw[3] = ADAPTATION_FLAG | PAYLOAD_FLAG;
1912 raw[4] = 2; raw[5] = AF_SPLICING_FLAG;
1914 raw[6] = 0xFB; let pkt = TsPacket::parse(&raw).expect("valid");
1916 let af = pkt.adaptation_field().unwrap().unwrap();
1917 assert_eq!(af.splice_countdown, Some(-5));
1918 assert!(af.pcr.is_none());
1919 }
1920
1921 #[test]
1924 fn scrambling_control_all_values() {
1925 assert_eq!(
1926 ScramblingControl::from_bits(0b00),
1927 ScramblingControl::NotScrambled
1928 );
1929 assert_eq!(
1930 ScramblingControl::from_bits(0b01),
1931 ScramblingControl::Reserved
1932 );
1933 assert_eq!(
1934 ScramblingControl::from_bits(0b10),
1935 ScramblingControl::EvenKey
1936 );
1937 assert_eq!(
1938 ScramblingControl::from_bits(0b11),
1939 ScramblingControl::OddKey
1940 );
1941 assert_eq!(ScramblingControl::NotScrambled.name(), "not_scrambled");
1943 assert_eq!(ScramblingControl::Reserved.name(), "reserved");
1944 assert_eq!(ScramblingControl::EvenKey.name(), "even_key");
1945 assert_eq!(ScramblingControl::OddKey.name(), "odd_key");
1946 assert_eq!(ScramblingControl::NotScrambled.to_string(), "not_scrambled");
1948 assert_eq!(ScramblingControl::OddKey.to_string(), "odd_key");
1949 assert_eq!(
1951 ScramblingControl::from_bits(0xFF),
1952 ScramblingControl::OddKey
1953 );
1954 }
1955
1956 #[test]
1957 fn adaptation_field_control_all_values() {
1958 assert_eq!(
1959 AdaptationFieldControl::from_flags(false, false),
1960 AdaptationFieldControl::Reserved
1961 );
1962 assert_eq!(
1963 AdaptationFieldControl::from_flags(false, true),
1964 AdaptationFieldControl::PayloadOnly
1965 );
1966 assert_eq!(
1967 AdaptationFieldControl::from_flags(true, false),
1968 AdaptationFieldControl::AdaptationOnly
1969 );
1970 assert_eq!(
1971 AdaptationFieldControl::from_flags(true, true),
1972 AdaptationFieldControl::AdaptationAndPayload
1973 );
1974 assert_eq!(AdaptationFieldControl::Reserved.name(), "reserved");
1976 assert_eq!(AdaptationFieldControl::PayloadOnly.name(), "payload_only");
1977 assert_eq!(
1978 AdaptationFieldControl::AdaptationOnly.name(),
1979 "adaptation_only"
1980 );
1981 assert_eq!(
1982 AdaptationFieldControl::AdaptationAndPayload.name(),
1983 "adaptation_and_payload"
1984 );
1985 assert_eq!(
1987 AdaptationFieldControl::PayloadOnly.to_string(),
1988 "payload_only"
1989 );
1990 }
1991
1992 #[test]
1993 fn ts_header_scrambling_control_accessor() {
1994 let hdr = TsHeader {
1995 tei: false,
1996 pusi: false,
1997 pid: Pid::new(0x0100),
1998 scrambling: 0b10,
1999 has_adaptation: false,
2000 has_payload: true,
2001 continuity_counter: 0,
2002 };
2003 assert_eq!(hdr.scrambling_control(), ScramblingControl::EvenKey);
2004 }
2005
2006 #[test]
2007 fn ts_header_adaptation_field_control_accessor() {
2008 let hdr_payload_only = TsHeader {
2009 tei: false,
2010 pusi: false,
2011 pid: Pid::new(0x0100),
2012 scrambling: 0,
2013 has_adaptation: false,
2014 has_payload: true,
2015 continuity_counter: 0,
2016 };
2017 assert_eq!(
2018 hdr_payload_only.adaptation_field_control(),
2019 AdaptationFieldControl::PayloadOnly
2020 );
2021
2022 let hdr_both = TsHeader {
2023 tei: false,
2024 pusi: false,
2025 pid: Pid::new(0x0100),
2026 scrambling: 0,
2027 has_adaptation: true,
2028 has_payload: true,
2029 continuity_counter: 0,
2030 };
2031 assert_eq!(
2032 hdr_both.adaptation_field_control(),
2033 AdaptationFieldControl::AdaptationAndPayload
2034 );
2035 }
2036
2037 #[test]
2040 fn iter_packets_yields_valid_and_skips_bad_sync() {
2041 let pkt1 = make_packet(0x00, 0x00, PAYLOAD_FLAG, &[0xAA; 10]);
2043 let pkt2 = make_packet(0x40, 0x64, PAYLOAD_FLAG, &[0xBB; 10]);
2044 let mut bad = [0u8; TS_PACKET_SIZE];
2045 bad[0] = 0x00; let mut buf = Vec::new();
2048 buf.extend_from_slice(&pkt1);
2049 buf.extend_from_slice(&pkt2);
2050 buf.extend_from_slice(&bad);
2051
2052 let pkts: Vec<_> = super::iter_packets(&buf).collect();
2053 assert_eq!(pkts.len(), 2, "bad sync packet must be skipped");
2054 assert_eq!(pkts[0].header.pid, Pid::new(0x0000));
2055 assert_eq!(pkts[1].header.pid, Pid::new(0x0064));
2056 }
2057
2058 #[test]
2059 fn extract_ts_payload_payload_only() {
2060 let pkt = make_packet(0x00, 0x00, PAYLOAD_FLAG, &[0xABu8; 10]);
2061 let p = super::extract_ts_payload(&pkt).expect("payload present");
2062 assert_eq!(p[0], 0xAB);
2063 assert_eq!(p.len(), TS_PACKET_SIZE - 4);
2064 }
2065
2066 #[test]
2067 fn extract_ts_payload_adaptation_only_returns_none() {
2068 let pkt = make_packet(0x00, 0x00, ADAPTATION_FLAG, &[]);
2069 assert!(super::extract_ts_payload(&pkt).is_none());
2070 }
2071
2072 #[test]
2077 fn pcr_from_27mhz_round_trips() {
2078 for &ticks in &[0u64, 1, 300, 27_000_000, u64::from(u32::MAX), 8_589_934_591] {
2079 let pcr = Pcr::from_27mhz(ticks);
2080 assert_eq!(pcr.as_27mhz(), ticks, "ticks={ticks}");
2081 }
2082 }
2083
2084 #[test]
2086 fn pcr_to_field_bytes_round_trips_parse() {
2087 let cases = [
2088 Pcr {
2089 base: 0,
2090 extension: 0,
2091 },
2092 Pcr {
2093 base: 10_000,
2094 extension: 0,
2095 },
2096 Pcr {
2097 base: 1,
2098 extension: 100,
2099 },
2100 Pcr {
2101 base: 0x1_FFFF_FFFF,
2102 extension: 0x1FF,
2103 },
2104 ];
2105 for pcr in cases {
2106 let bytes = pcr.to_field_bytes();
2107 let mut af = [0u8; 7];
2110 af[1..7].copy_from_slice(&bytes);
2111 let decoded = Pcr::parse(&af, 1).expect("parse round-trip");
2112 assert_eq!(decoded, pcr, "round-trip failed for {pcr:?}");
2113 }
2114 }
2115
2116 #[test]
2119 fn pcr_to_field_bytes_known_vector() {
2120 let pcr = Pcr {
2121 base: 10_000,
2122 extension: 0,
2123 };
2124 let bytes = pcr.to_field_bytes();
2125 assert_eq!(bytes, [0x00, 0x00, 0x13, 0x88, 0x7E, 0x00]);
2126 }
2127
2128 #[test]
2131 fn scrambling_control_to_bits_inverse_of_from_bits() {
2132 for bits in 0u8..=3 {
2133 let sc = ScramblingControl::from_bits(bits);
2134 assert_eq!(sc.to_bits(), bits, "to_bits() != from_bits() for {bits}");
2135 }
2136 }
2137
2138 #[test]
2141 fn adaptation_field_control_to_bits_inverse_of_from_flags() {
2142 let cases = [
2143 (false, false, 0b00u8),
2144 (false, true, 0b01),
2145 (true, false, 0b10),
2146 (true, true, 0b11),
2147 ];
2148 for (has_af, has_pl, expected_bits) in cases {
2149 let afc = AdaptationFieldControl::from_flags(has_af, has_pl);
2150 assert_eq!(afc.to_bits(), expected_bits);
2151 assert_eq!(afc.to_flags(), (has_af, has_pl));
2152 }
2153 }
2154
2155 #[test]
2159 fn adaptation_field_serialize_round_trip_with_pcr() {
2160 let original = AdaptationField {
2161 discontinuity_indicator: true,
2162 random_access_indicator: false,
2163 elementary_stream_priority_indicator: false,
2164 pcr: Some(Pcr {
2165 base: 10_000,
2166 extension: 0,
2167 }),
2168 opcr: None,
2169 splice_countdown: None,
2170 transport_private_data: None,
2171 extension: None,
2172 stuffing: &[],
2173 pcr_reserved: PCR_RESERVED_VALUE,
2174 opcr_reserved: PCR_RESERVED_VALUE,
2175 };
2176 let len = original.serialized_len();
2177 assert_eq!(len, 7); let mut buf = vec![0u8; len];
2179 let written = original.serialize_into(&mut buf).expect("serialize");
2180 assert_eq!(written, len);
2181 let decoded = AdaptationField::parse(&buf).expect("parse round-trip");
2182 assert_eq!(decoded, original);
2183 }
2184
2185 #[test]
2189 fn transport_private_data_over_255_bytes_rejected_not_wrapped() {
2190 let data = vec![0u8; 256];
2191 let af = AdaptationField {
2192 discontinuity_indicator: false,
2193 random_access_indicator: false,
2194 elementary_stream_priority_indicator: false,
2195 pcr: None,
2196 opcr: None,
2197 splice_countdown: None,
2198 transport_private_data: Some(&data),
2199 extension: None,
2200 stuffing: &[],
2201 pcr_reserved: PCR_RESERVED_VALUE,
2202 opcr_reserved: PCR_RESERVED_VALUE,
2203 };
2204 let mut buf = vec![0u8; af.serialized_len()];
2205 assert!(af.serialize_into(&mut buf).is_err());
2206 }
2207
2208 #[test]
2210 fn adaptation_field_serialize_produces_known_bytes() {
2211 let af = AdaptationField {
2215 discontinuity_indicator: true,
2216 random_access_indicator: false,
2217 elementary_stream_priority_indicator: false,
2218 pcr: Some(Pcr {
2219 base: 10_000,
2220 extension: 0,
2221 }),
2222 opcr: None,
2223 splice_countdown: None,
2224 transport_private_data: None,
2225 extension: None,
2226 stuffing: &[],
2227 pcr_reserved: PCR_RESERVED_VALUE,
2228 opcr_reserved: PCR_RESERVED_VALUE,
2229 };
2230 let mut buf = [0u8; 7];
2231 af.serialize_into(&mut buf).unwrap();
2232 assert_eq!(buf[0], AF_DISCONTINUITY | AF_PCR_FLAG);
2233 assert_eq!(&buf[1..7], &[0x00, 0x00, 0x13, 0x88, 0x7E, 0x00]);
2234 }
2235
2236 #[test]
2238 fn adaptation_field_serialize_round_trip_opcr_and_splice() {
2239 let original = AdaptationField {
2240 discontinuity_indicator: false,
2241 random_access_indicator: true,
2242 elementary_stream_priority_indicator: true,
2243 pcr: Some(Pcr {
2244 base: 1,
2245 extension: 100,
2246 }),
2247 opcr: Some(Pcr {
2248 base: 999,
2249 extension: 5,
2250 }),
2251 splice_countdown: Some(-3),
2252 transport_private_data: None,
2253 extension: None,
2254 stuffing: &[],
2255 pcr_reserved: PCR_RESERVED_VALUE,
2256 opcr_reserved: PCR_RESERVED_VALUE,
2257 };
2258 let len = original.serialized_len();
2259 assert_eq!(len, 1 + 6 + 6 + 1); let mut buf = vec![0u8; len];
2261 original.serialize_into(&mut buf).unwrap();
2262 let decoded = AdaptationField::parse(&buf).expect("parse");
2263 assert_eq!(decoded, original);
2264 }
2265
2266 #[test]
2268 fn adaptation_field_serialize_flags_only() {
2269 let af = AdaptationField {
2270 discontinuity_indicator: false,
2271 random_access_indicator: true,
2272 elementary_stream_priority_indicator: false,
2273 pcr: None,
2274 opcr: None,
2275 splice_countdown: None,
2276 transport_private_data: None,
2277 extension: None,
2278 stuffing: &[],
2279 pcr_reserved: PCR_RESERVED_VALUE,
2280 opcr_reserved: PCR_RESERVED_VALUE,
2281 };
2282 assert_eq!(af.serialized_len(), 1);
2283 let mut buf = [0u8; 1];
2284 af.serialize_into(&mut buf).unwrap();
2285 assert_eq!(buf[0], AF_RANDOM_ACCESS);
2286 let decoded = AdaptationField::parse(&buf).unwrap();
2287 assert_eq!(decoded, af);
2288 }
2289
2290 #[test]
2292 fn adaptation_field_serialize_rejects_small_buffer() {
2293 let af = AdaptationField {
2294 discontinuity_indicator: false,
2295 random_access_indicator: false,
2296 elementary_stream_priority_indicator: false,
2297 pcr: Some(Pcr {
2298 base: 0,
2299 extension: 0,
2300 }),
2301 opcr: None,
2302 splice_countdown: None,
2303 transport_private_data: None,
2304 extension: None,
2305 stuffing: &[],
2306 pcr_reserved: PCR_RESERVED_VALUE,
2307 opcr_reserved: PCR_RESERVED_VALUE,
2308 };
2309 let mut buf = [0u8; 3]; assert!(matches!(
2311 af.serialize_into(&mut buf),
2312 Err(Error::OutputBufferTooSmall { .. })
2313 ));
2314 }
2315
2316 #[test]
2320 fn adaptation_field_extension_ltw_round_trip() {
2321 let ext = AdaptationFieldExtension {
2322 ltw: Some(Ltw {
2323 ltw_valid_flag: true,
2324 ltw_offset: 0x1234,
2325 }),
2326 piecewise_rate: None,
2327 seamless_splice: None,
2328 ..AdaptationFieldExtension::new()
2329 };
2330 let mut buf = vec![0u8; ext.serialized_len()];
2331 ext.serialize_into(&mut buf).unwrap();
2332 let af = AdaptationField {
2335 discontinuity_indicator: false,
2336 random_access_indicator: false,
2337 elementary_stream_priority_indicator: false,
2338 pcr: None,
2339 opcr: None,
2340 splice_countdown: None,
2341 transport_private_data: None,
2342 extension: Some(ext),
2343 stuffing: &[],
2344 pcr_reserved: PCR_RESERVED_VALUE,
2345 opcr_reserved: PCR_RESERVED_VALUE,
2346 };
2347 let len = af.serialized_len();
2348 let mut abuf = vec![0u8; len];
2349 af.serialize_into(&mut abuf).unwrap();
2350 let decoded = AdaptationField::parse(&abuf).unwrap();
2351 assert_eq!(decoded.extension, Some(ext));
2352 }
2353
2354 #[test]
2356 fn adaptation_field_extension_piecewise_rate_round_trip() {
2357 let af = AdaptationField {
2358 discontinuity_indicator: false,
2359 random_access_indicator: false,
2360 elementary_stream_priority_indicator: false,
2361 pcr: None,
2362 opcr: None,
2363 splice_countdown: None,
2364 transport_private_data: None,
2365 extension: Some(AdaptationFieldExtension {
2366 ltw: None,
2367 piecewise_rate: Some(0x3FFFFF), seamless_splice: None,
2369 ..AdaptationFieldExtension::new()
2370 }),
2371 stuffing: &[],
2372 pcr_reserved: PCR_RESERVED_VALUE,
2373 opcr_reserved: PCR_RESERVED_VALUE,
2374 };
2375 let mut buf = vec![0u8; af.serialized_len()];
2376 af.serialize_into(&mut buf).unwrap();
2377 let decoded = AdaptationField::parse(&buf).unwrap();
2378 assert_eq!(decoded.extension.unwrap().piecewise_rate, Some(0x3FFFFF));
2379 }
2380
2381 #[test]
2383 fn adaptation_field_extension_seamless_splice_round_trip() {
2384 let af = AdaptationField {
2385 discontinuity_indicator: false,
2386 random_access_indicator: false,
2387 elementary_stream_priority_indicator: false,
2388 pcr: None,
2389 opcr: None,
2390 splice_countdown: None,
2391 transport_private_data: None,
2392 extension: Some(AdaptationFieldExtension {
2393 ltw: None,
2394 piecewise_rate: None,
2395 seamless_splice: Some(SeamlessSplice::new(0xA, 0x1_2345_6789)),
2396 ..AdaptationFieldExtension::new()
2397 }),
2398 stuffing: &[],
2399 pcr_reserved: PCR_RESERVED_VALUE,
2400 opcr_reserved: PCR_RESERVED_VALUE,
2401 };
2402 let mut buf = vec![0u8; af.serialized_len()];
2403 af.serialize_into(&mut buf).unwrap();
2404 let decoded = AdaptationField::parse(&buf).unwrap();
2405 let ss = decoded.extension.unwrap().seamless_splice.unwrap();
2406 assert_eq!(ss.splice_type, 0xA);
2407 assert_eq!(ss.dts_next_au, 0x1_2345_6789);
2408 }
2409
2410 #[test]
2412 fn adaptation_field_transport_private_data_round_trip() {
2413 let tpd = [0xDE, 0xAD, 0xBE, 0xEF];
2414 let af = AdaptationField {
2415 discontinuity_indicator: false,
2416 random_access_indicator: false,
2417 elementary_stream_priority_indicator: false,
2418 pcr: None,
2419 opcr: None,
2420 splice_countdown: None,
2421 transport_private_data: Some(&tpd),
2422 extension: None,
2423 stuffing: &[],
2424 pcr_reserved: PCR_RESERVED_VALUE,
2425 opcr_reserved: PCR_RESERVED_VALUE,
2426 };
2427 let mut buf = vec![0u8; af.serialized_len()];
2428 af.serialize_into(&mut buf).unwrap();
2429 let decoded = AdaptationField::parse(&buf).unwrap();
2430 assert_eq!(decoded.transport_private_data, Some(tpd.as_slice()));
2431 }
2432
2433 #[test]
2436 fn adaptation_field_stuffing_round_trip() {
2437 let af = AdaptationField {
2438 discontinuity_indicator: false,
2439 random_access_indicator: false,
2440 elementary_stream_priority_indicator: false,
2441 pcr: Some(Pcr {
2442 base: 12_345,
2443 extension: 7,
2444 }),
2445 opcr: None,
2446 splice_countdown: None,
2447 transport_private_data: None,
2448 extension: None,
2449 stuffing: &[0xFF; 20],
2450 pcr_reserved: PCR_RESERVED_VALUE,
2451 opcr_reserved: PCR_RESERVED_VALUE,
2452 };
2453 assert_eq!(af.serialized_len(), 27);
2455 let mut buf = vec![0u8; af.serialized_len()];
2456 af.serialize_into(&mut buf).unwrap();
2457 assert!(buf[7..27].iter().all(|&b| b == 0xFF));
2459 let decoded = AdaptationField::parse(&buf).unwrap();
2460 assert_eq!(decoded.stuffing.len(), 20);
2461 assert_eq!(decoded, af);
2462 let pure = AdaptationField {
2464 discontinuity_indicator: false,
2465 random_access_indicator: false,
2466 elementary_stream_priority_indicator: false,
2467 pcr: None,
2468 opcr: None,
2469 splice_countdown: None,
2470 transport_private_data: None,
2471 extension: None,
2472 stuffing: &[0xFF; 5],
2473 pcr_reserved: PCR_RESERVED_VALUE,
2474 opcr_reserved: PCR_RESERVED_VALUE,
2475 };
2476 let mut pbuf = vec![0u8; pure.serialized_len()];
2477 pure.serialize_into(&mut pbuf).unwrap();
2478 assert_eq!(pbuf, vec![0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]);
2479 assert_eq!(AdaptationField::parse(&pbuf).unwrap(), pure);
2480 }
2481
2482 #[test]
2484 fn adaptation_field_all_fields_round_trip() {
2485 let tpd = [0x01u8, 0x02, 0x03];
2486 let af = AdaptationField {
2487 discontinuity_indicator: true,
2488 random_access_indicator: false,
2489 elementary_stream_priority_indicator: false,
2490 pcr: Some(Pcr {
2491 base: 90_000,
2492 extension: 50,
2493 }),
2494 opcr: None,
2495 splice_countdown: Some(10),
2496 transport_private_data: Some(&tpd),
2497 extension: Some(AdaptationFieldExtension {
2498 ltw: Some(Ltw {
2499 ltw_valid_flag: false,
2500 ltw_offset: 500,
2501 }),
2502 piecewise_rate: Some(12345),
2503 seamless_splice: None,
2504 ..AdaptationFieldExtension::new()
2505 }),
2506 stuffing: &[],
2507 pcr_reserved: PCR_RESERVED_VALUE,
2508 opcr_reserved: PCR_RESERVED_VALUE,
2509 };
2510 let len = af.serialized_len();
2511 let mut buf = vec![0u8; len];
2512 af.serialize_into(&mut buf).unwrap();
2513 let decoded = AdaptationField::parse(&buf).unwrap();
2514 assert_eq!(decoded.pcr, af.pcr);
2515 assert_eq!(decoded.splice_countdown, af.splice_countdown);
2516 assert_eq!(decoded.transport_private_data, af.transport_private_data);
2517 assert_eq!(decoded.extension, af.extension);
2518 assert!(decoded.discontinuity_indicator);
2519 }
2520
2521 #[test]
2524 fn adaptation_field_serialize_from_real_packet_bytes() {
2525 let mut raw = [0xAAu8; TS_PACKET_SIZE];
2527 raw[0] = TS_SYNC_BYTE;
2528 raw[1] = 0x01;
2529 raw[2] = 0x00;
2530 raw[3] = ADAPTATION_FLAG | PAYLOAD_FLAG;
2531 raw[4] = 7;
2532 raw[5] = AF_DISCONTINUITY | AF_PCR_FLAG;
2533 raw[6..12].copy_from_slice(&[0x00, 0x00, 0x13, 0x88, 0x7E, 0x00]);
2534
2535 let pkt = TsPacket::parse(&raw).unwrap();
2536 let af = pkt.adaptation_field().unwrap().unwrap();
2537
2538 let mut ser = vec![0u8; af.serialized_len()];
2540 af.serialize_into(&mut ser).unwrap();
2541 let decoded = AdaptationField::parse(&ser).unwrap();
2542 assert_eq!(
2543 decoded.pcr,
2544 Some(Pcr {
2545 base: 10_000,
2546 extension: 0
2547 })
2548 );
2549 assert!(decoded.discontinuity_indicator);
2550 }
2551}