1use crate::error::{Error, Result};
4
5pub const TS_PACKET_SIZE: usize = 188;
7pub const TS_SYNC_BYTE: u8 = 0x47;
9const MAX_SECTION_SIZE: usize = 4098;
14const SECTION_HEADER_LEN: usize = 3;
18pub(crate) const SECTION_LENGTH_HI_MASK: u8 = 0x0F;
22
23pub(crate) fn section_total_len(bytes: &[u8]) -> Option<usize> {
32 if bytes.len() < SECTION_HEADER_LEN {
33 return None;
34 }
35 let section_length = ((bytes[1] & SECTION_LENGTH_HI_MASK) as usize) << 8 | bytes[2] as usize;
36 Some(SECTION_HEADER_LEN + section_length)
37}
38
39#[non_exhaustive]
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49#[cfg_attr(feature = "serde", derive(serde::Serialize))]
50pub enum ScramblingControl {
51 NotScrambled,
53 Reserved,
55 EvenKey,
58 OddKey,
61}
62
63impl ScramblingControl {
64 pub fn from_bits(bits: u8) -> Self {
66 match bits & 0b11 {
67 0b00 => Self::NotScrambled,
68 0b01 => Self::Reserved,
69 0b10 => Self::EvenKey,
70 0b11 => Self::OddKey,
71 _ => unreachable!(),
72 }
73 }
74
75 pub fn to_bits(self) -> u8 {
80 match self {
81 Self::NotScrambled => 0b00,
82 Self::Reserved => 0b01,
83 Self::EvenKey => 0b10,
84 Self::OddKey => 0b11,
85 }
86 }
87
88 pub fn name(&self) -> &'static str {
90 match self {
91 Self::NotScrambled => "not_scrambled",
92 Self::Reserved => "reserved",
93 Self::EvenKey => "even_key",
94 Self::OddKey => "odd_key",
95 }
96 }
97}
98
99broadcast_common::impl_spec_display!(ScramblingControl);
100
101#[non_exhaustive]
107#[derive(Debug, Clone, Copy, PartialEq, Eq)]
108#[cfg_attr(feature = "serde", derive(serde::Serialize))]
109pub enum AdaptationFieldControl {
110 Reserved,
112 PayloadOnly,
114 AdaptationOnly,
116 AdaptationAndPayload,
118}
119
120impl AdaptationFieldControl {
121 pub fn from_flags(has_adaptation: bool, has_payload: bool) -> Self {
123 match (has_adaptation, has_payload) {
124 (false, false) => Self::Reserved,
125 (false, true) => Self::PayloadOnly,
126 (true, false) => Self::AdaptationOnly,
127 (true, true) => Self::AdaptationAndPayload,
128 }
129 }
130
131 pub fn to_bits(self) -> u8 {
137 match self {
138 Self::Reserved => 0b00,
139 Self::PayloadOnly => 0b01,
140 Self::AdaptationOnly => 0b10,
141 Self::AdaptationAndPayload => 0b11,
142 }
143 }
144
145 pub fn to_flags(self) -> (bool, bool) {
148 match self {
149 Self::Reserved => (false, false),
150 Self::PayloadOnly => (false, true),
151 Self::AdaptationOnly => (true, false),
152 Self::AdaptationAndPayload => (true, true),
153 }
154 }
155
156 pub fn name(&self) -> &'static str {
158 match self {
159 Self::Reserved => "reserved",
160 Self::PayloadOnly => "payload_only",
161 Self::AdaptationOnly => "adaptation_only",
162 Self::AdaptationAndPayload => "adaptation_and_payload",
163 }
164 }
165}
166
167broadcast_common::impl_spec_display!(AdaptationFieldControl);
168
169const TEI_MASK: u8 = 0x80;
171const PUSI_MASK: u8 = 0x40;
173pub const PID_MASK_HI: u8 = 0x1F;
175pub const SCRAMBLING_MASK: u8 = 0xC0;
177pub const ADAPTATION_FLAG: u8 = 0x20;
179pub const PAYLOAD_FLAG: u8 = 0x10;
181pub const CC_MASK: u8 = 0x0F;
183
184#[derive(Clone, Debug, PartialEq, Eq)]
186#[cfg_attr(feature = "serde", derive(serde::Serialize))]
187pub struct TsHeader {
188 pub tei: bool,
191 pub pusi: bool,
194 pub pid: u16,
196 pub scrambling: u8,
198 pub has_adaptation: bool,
200 pub has_payload: bool,
202 pub continuity_counter: u8,
204}
205
206#[derive(Clone, Debug)]
212#[cfg_attr(feature = "serde", derive(serde::Serialize))]
213pub struct TsPacket<'a> {
214 pub header: TsHeader,
216 pub payload: Option<&'a [u8]>,
219 #[cfg_attr(feature = "serde", serde(skip))]
222 adaptation: Option<&'a [u8]>,
223 #[cfg_attr(feature = "serde", serde(skip))]
225 pub raw: &'a [u8; TS_PACKET_SIZE],
226}
227
228impl TsHeader {
229 pub fn parse(raw4: &[u8]) -> Result<Self> {
231 if raw4.len() < 4 {
232 return Err(Error::BufferTooShort {
233 need: 4,
234 have: raw4.len(),
235 what: "TsHeader",
236 });
237 }
238 let b1 = raw4[1];
239 let b2 = raw4[2];
240 let b3 = raw4[3];
241
242 let tei = (b1 & TEI_MASK) != 0;
243 let pusi = (b1 & PUSI_MASK) != 0;
244 let pid = (((b1 & PID_MASK_HI) as u16) << 8) | (b2 as u16);
245 let scrambling = (b3 & SCRAMBLING_MASK) >> 6;
246 let has_adaptation = (b3 & ADAPTATION_FLAG) != 0;
247 let has_payload = (b3 & PAYLOAD_FLAG) != 0;
248 let continuity_counter = b3 & CC_MASK;
249
250 Ok(Self {
251 tei,
252 pusi,
253 pid,
254 scrambling,
255 has_adaptation,
256 has_payload,
257 continuity_counter,
258 })
259 }
260
261 pub const fn serialized_len() -> usize {
263 4
264 }
265
266 pub fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
268 if buf.len() < 4 {
269 return Err(Error::OutputBufferTooSmall {
270 need: 4,
271 have: buf.len(),
272 });
273 }
274 buf[0] = TS_SYNC_BYTE;
275 buf[1] = 0;
276 if self.tei {
277 buf[1] |= TEI_MASK;
278 }
279 if self.pusi {
280 buf[1] |= PUSI_MASK;
281 }
282 buf[1] |= ((self.pid >> 8) as u8) & PID_MASK_HI;
283 buf[2] = self.pid.to_be_bytes()[1];
284 buf[3] = (self.scrambling << 6) & SCRAMBLING_MASK;
285 if self.has_adaptation {
286 buf[3] |= ADAPTATION_FLAG;
287 }
288 if self.has_payload {
289 buf[3] |= PAYLOAD_FLAG;
290 }
291 buf[3] |= self.continuity_counter & CC_MASK;
292 Ok(4)
293 }
294
295 pub fn scrambling_control(&self) -> ScramblingControl {
300 ScramblingControl::from_bits(self.scrambling)
301 }
302
303 pub fn adaptation_field_control(&self) -> AdaptationFieldControl {
308 AdaptationFieldControl::from_flags(self.has_adaptation, self.has_payload)
309 }
310}
311
312impl<'a> broadcast_common::Parse<'a> for TsHeader {
313 type Error = Error;
314
315 fn parse(bytes: &'a [u8]) -> Result<Self> {
316 TsHeader::parse(bytes)
317 }
318}
319
320impl broadcast_common::Serialize for TsHeader {
321 type Error = Error;
322
323 fn serialized_len(&self) -> usize {
324 TsHeader::serialized_len()
325 }
326
327 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
328 TsHeader::serialize_into(self, buf)
329 }
330}
331
332fn adaptation_field_skip(pkt: &[u8], has_adaptation: bool) -> usize {
343 if !has_adaptation || pkt.len() <= 4 {
344 return 0;
345 }
346 let af_len = pkt[4] as usize;
347 1 + af_len
348}
349
350impl<'a> TsPacket<'a> {
351 pub fn parse(buf: &'a [u8]) -> Result<Self> {
357 if buf.len() < TS_PACKET_SIZE {
358 return Err(Error::BufferTooShort {
359 need: TS_PACKET_SIZE,
360 have: buf.len(),
361 what: "TsPacket",
362 });
363 }
364 if buf[0] != TS_SYNC_BYTE {
365 return Err(Error::InvalidSyncByte { found: buf[0] });
366 }
367
368 let raw: &[u8; TS_PACKET_SIZE] =
369 buf[..TS_PACKET_SIZE]
370 .try_into()
371 .map_err(|_| Error::BufferTooShort {
372 need: TS_PACKET_SIZE,
373 have: buf.len(),
374 what: "TsPacket::parse (array conversion)",
375 })?;
376
377 let header = TsHeader::parse(&raw[..4])?;
378
379 let mut cursor = 4usize;
380 let mut payload = None;
381 let mut adaptation = None;
382
383 if header.has_adaptation && cursor < TS_PACKET_SIZE {
396 let af_len = raw[cursor] as usize;
397 let af_start = cursor + 1;
398 if af_len > 0 && af_start < TS_PACKET_SIZE && af_start + af_len <= TS_PACKET_SIZE {
399 adaptation = Some(&raw[af_start..af_start + af_len]);
400 }
401 }
402 cursor += adaptation_field_skip(raw, header.has_adaptation);
407
408 if header.has_payload && cursor < TS_PACKET_SIZE {
409 payload = Some(&raw[cursor..]);
410 }
411
412 Ok(TsPacket {
413 header,
414 payload,
415 adaptation,
416 raw,
417 })
418 }
419
420 pub fn adaptation_field(&self) -> Option<crate::Result<AdaptationField<'a>>> {
426 self.adaptation.map(AdaptationField::parse)
427 }
428}
429
430pub(crate) const AF_DISCONTINUITY: u8 = 0x80;
432pub(crate) const AF_RANDOM_ACCESS: u8 = 0x40;
433pub(crate) const AF_ES_PRIORITY: u8 = 0x20;
434pub const AF_PCR_FLAG: u8 = 0x10;
436pub(crate) const AF_OPCR_FLAG: u8 = 0x08;
437pub(crate) const AF_SPLICING_FLAG: u8 = 0x04;
438pub(crate) const AF_TRANSPORT_PRIVATE_DATA_FLAG: u8 = 0x02;
439pub(crate) const AF_EXTENSION_FLAG: u8 = 0x01;
440pub(crate) const AF_STUFFING_BYTE: u8 = 0xFF;
442const PCR_RESERVED_BITS: u8 = 0x7E;
445pub(crate) const PCR_FIELD_LEN: usize = 6;
447
448#[derive(Clone, Copy, Debug, PartialEq, Eq)]
451#[cfg_attr(feature = "serde", derive(serde::Serialize))]
452pub struct Pcr {
453 pub base: u64,
455 pub extension: u16,
457}
458
459impl Pcr {
460 #[must_use]
464 pub fn as_27mhz(self) -> u64 {
465 self.base * 300 + self.extension as u64
466 }
467
468 #[must_use]
477 pub fn from_27mhz(ticks: u64) -> Self {
478 const BASE_MASK: u64 = 0x1_FFFF_FFFF;
480 const EXT_MASK: u16 = 0x1FF;
482 Self {
483 base: (ticks / 300) & BASE_MASK,
484 extension: ((ticks % 300) as u16) & EXT_MASK,
485 }
486 }
487
488 #[must_use]
497 pub fn to_field_bytes(self) -> [u8; PCR_FIELD_LEN] {
498 let b = self.base;
499 let e = self.extension as u64;
500 [
501 ((b >> 25) & 0xFF) as u8,
502 ((b >> 17) & 0xFF) as u8,
503 ((b >> 9) & 0xFF) as u8,
504 ((b >> 1) & 0xFF) as u8,
505 (((b & 0x01) as u8) << 7) | PCR_RESERVED_BITS | ((e >> 8) as u8 & 0x01),
507 (e & 0xFF) as u8,
508 ]
509 }
510
511 pub(crate) fn parse(af: &[u8], at: usize) -> Result<Self> {
513 let b: &[u8; PCR_FIELD_LEN] = af
514 .get(at..at + PCR_FIELD_LEN)
515 .and_then(|s| s.try_into().ok())
516 .ok_or(Error::BufferTooShort {
517 need: at + PCR_FIELD_LEN,
518 have: af.len(),
519 what: "adaptation_field PCR",
520 })?;
521 let base = ((b[0] as u64) << 25)
522 | ((b[1] as u64) << 17)
523 | ((b[2] as u64) << 9)
524 | ((b[3] as u64) << 1)
525 | ((b[4] as u64) >> 7);
526 let extension = (((b[4] & 0x01) as u16) << 8) | (b[5] as u16);
527 Ok(Self { base, extension })
528 }
529}
530
531#[derive(Clone, Copy, Debug, PartialEq, Eq)]
538#[cfg_attr(feature = "serde", derive(serde::Serialize))]
539pub struct Ltw {
540 pub ltw_valid_flag: bool,
542 pub ltw_offset: u16,
544}
545
546#[derive(Clone, Copy, Debug, PartialEq, Eq)]
553#[cfg_attr(feature = "serde", derive(serde::Serialize))]
554pub struct SeamlessSplice {
555 pub splice_type: u8,
557 pub dts_next_au: u64,
559}
560
561const AFE_LTW_FLAG: u8 = 0x80;
564const AFE_PIECEWISE_RATE_FLAG: u8 = 0x40;
565const AFE_SEAMLESS_SPLICE_FLAG: u8 = 0x20;
566const LTW_OFFSET_HI_MASK: u8 = 0x7F;
568const PIECEWISE_RATE_HI_MASK: u8 = 0x3F;
570const PIECEWISE_RATE_RESERVED_BITS: u8 = 0xC0;
571
572#[derive(Clone, Copy, Debug, PartialEq, Eq)]
578#[cfg_attr(feature = "serde", derive(serde::Serialize))]
579pub struct AdaptationFieldExtension {
580 pub ltw: Option<Ltw>,
582 pub piecewise_rate: Option<u32>,
584 pub seamless_splice: Option<SeamlessSplice>,
586}
587
588impl AdaptationFieldExtension {
589 fn parse(data: &[u8]) -> Result<Self> {
592 if data.is_empty() {
593 return Err(Error::BufferTooShort {
594 need: 1,
595 have: 0,
596 what: "adaptation_field_extension_length",
597 });
598 }
599 let ext_len = data[0] as usize;
600 if data.len() < 1 + ext_len || ext_len < 1 {
602 return Err(Error::BufferTooShort {
603 need: 2.max(1 + ext_len),
604 have: data.len(),
605 what: "adaptation_field_extension body",
606 });
607 }
608 let ext = &data[1..1 + ext_len]; let flags = ext[0];
610 let mut cursor = 1usize;
611
612 let ltw = if flags & AFE_LTW_FLAG != 0 {
613 if ext.len() < cursor + 2 {
614 return Err(Error::BufferTooShort {
615 need: cursor + 2,
616 have: ext.len(),
617 what: "ltw_offset",
618 });
619 }
620 let w0 = ext[cursor];
621 let w1 = ext[cursor + 1];
622 cursor += 2;
623 Some(Ltw {
624 ltw_valid_flag: (w0 & AFE_LTW_FLAG) != 0,
625 ltw_offset: (((w0 & LTW_OFFSET_HI_MASK) as u16) << 8) | (w1 as u16),
626 })
627 } else {
628 None
629 };
630
631 let piecewise_rate = if flags & AFE_PIECEWISE_RATE_FLAG != 0 {
632 if ext.len() < cursor + 3 {
633 return Err(Error::BufferTooShort {
634 need: cursor + 3,
635 have: ext.len(),
636 what: "piecewise_rate",
637 });
638 }
639 let r = (((ext[cursor] & PIECEWISE_RATE_HI_MASK) as u32) << 16)
640 | ((ext[cursor + 1] as u32) << 8)
641 | (ext[cursor + 2] as u32);
642 cursor += 3;
643 Some(r)
644 } else {
645 None
646 };
647
648 let seamless_splice = if flags & AFE_SEAMLESS_SPLICE_FLAG != 0 {
650 if ext.len() < cursor + 5 {
651 return Err(Error::BufferTooShort {
652 need: cursor + 5,
653 have: ext.len(),
654 what: "seamless_splice DTS_next_AU",
655 });
656 }
657 let b = &ext[cursor..cursor + 5];
658 let splice_type = (b[0] >> 4) & 0x0F;
659 let hi = u64::from((b[0] >> 1) & 0x07); let mid = (u64::from(b[1]) << 7) | u64::from(b[2] >> 1); let lo = (u64::from(b[3]) << 7) | u64::from(b[4] >> 1); let dts_next_au = (hi << 30) | (mid << 15) | lo;
664 cursor += 5;
665 Some(SeamlessSplice {
666 splice_type,
667 dts_next_au,
668 })
669 } else {
670 None
671 };
672 let _ = cursor; Ok(AdaptationFieldExtension {
675 ltw,
676 piecewise_rate,
677 seamless_splice,
678 })
679 }
680
681 #[must_use]
684 pub fn serialized_len(&self) -> usize {
685 let body = 1 + self.ltw.map_or(0, |_| 2)
687 + self.piecewise_rate.map_or(0, |_| 3)
688 + self.seamless_splice.map_or(0, |_| 5);
689 1 + body }
691
692 pub fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
694 let need = self.serialized_len();
695 if buf.len() < need {
696 return Err(Error::OutputBufferTooSmall {
697 need,
698 have: buf.len(),
699 });
700 }
701 let body_len = need - 1;
702 buf[0] = body_len as u8;
703
704 let mut flags = 0u8;
705 if self.ltw.is_some() {
706 flags |= AFE_LTW_FLAG;
707 }
708 if self.piecewise_rate.is_some() {
709 flags |= AFE_PIECEWISE_RATE_FLAG;
710 }
711 if self.seamless_splice.is_some() {
712 flags |= AFE_SEAMLESS_SPLICE_FLAG;
713 }
714 buf[1] = flags;
715 let mut cursor = 2usize;
716
717 if let Some(ltw) = self.ltw {
718 let ltw_valid = if ltw.ltw_valid_flag {
719 AFE_LTW_FLAG
720 } else {
721 0x00
722 };
723 buf[cursor] = ltw_valid | ((ltw.ltw_offset >> 8) as u8 & LTW_OFFSET_HI_MASK);
724 buf[cursor + 1] = (ltw.ltw_offset & 0xFF) as u8;
725 cursor += 2;
726 }
727 if let Some(rate) = self.piecewise_rate {
728 buf[cursor] =
730 PIECEWISE_RATE_RESERVED_BITS | ((rate >> 16) as u8 & PIECEWISE_RATE_HI_MASK);
731 buf[cursor + 1] = (rate >> 8) as u8;
732 buf[cursor + 2] = rate as u8;
733 cursor += 3;
734 }
735 if let Some(ss) = self.seamless_splice {
736 let ts = ss.dts_next_au & 0x1_FFFF_FFFF;
737 let st = ss.splice_type & 0x0F;
738 buf[cursor] = (st << 4) | ((((ts >> 30) & 0x07) as u8) << 1) | 0x01;
740 buf[cursor + 1] = ((ts >> 22) & 0xFF) as u8;
741 buf[cursor + 2] = ((((ts >> 15) & 0x7F) as u8) << 1) | 0x01;
742 buf[cursor + 3] = ((ts >> 7) & 0xFF) as u8;
743 buf[cursor + 4] = (((ts & 0x7F) as u8) << 1) | 0x01;
744 cursor += 5;
745 }
746 Ok(cursor)
747 }
748}
749
750#[non_exhaustive]
759#[derive(Clone, Debug, PartialEq, Eq)]
760#[cfg_attr(feature = "serde", derive(serde::Serialize))]
761pub struct AdaptationField<'a> {
762 pub discontinuity_indicator: bool,
764 pub random_access_indicator: bool,
766 pub elementary_stream_priority_indicator: bool,
768 pub pcr: Option<Pcr>,
770 pub opcr: Option<Pcr>,
772 pub splice_countdown: Option<i8>,
774 pub transport_private_data: Option<&'a [u8]>,
779 pub extension: Option<AdaptationFieldExtension>,
781 pub stuffing_len: usize,
791}
792
793impl<'a> AdaptationField<'a> {
794 pub(crate) fn parse(af: &'a [u8]) -> Result<Self> {
801 let flags = *af.first().ok_or(Error::BufferTooShort {
802 need: 1,
803 have: 0,
804 what: "adaptation_field flags",
805 })?;
806 let mut cursor = 1usize;
807
808 let pcr = if flags & AF_PCR_FLAG != 0 {
809 let p = Pcr::parse(af, cursor)?;
810 cursor += PCR_FIELD_LEN;
811 Some(p)
812 } else {
813 None
814 };
815 let opcr = if flags & AF_OPCR_FLAG != 0 {
816 let p = Pcr::parse(af, cursor)?;
817 cursor += PCR_FIELD_LEN;
818 Some(p)
819 } else {
820 None
821 };
822 let splice_countdown = if flags & AF_SPLICING_FLAG != 0 {
823 let b = *af.get(cursor).ok_or(Error::BufferTooShort {
824 need: cursor + 1,
825 have: af.len(),
826 what: "adaptation_field splice_countdown",
827 })?;
828 cursor += 1;
829 Some(b as i8)
830 } else {
831 None
832 };
833
834 let transport_private_data = if flags & AF_TRANSPORT_PRIVATE_DATA_FLAG != 0 {
837 let tpd_len = *af.get(cursor).ok_or(Error::BufferTooShort {
838 need: cursor + 1,
839 have: af.len(),
840 what: "transport_private_data_length",
841 })? as usize;
842 cursor += 1;
843 let end = cursor + tpd_len;
844 let slice = af.get(cursor..end).ok_or(Error::BufferTooShort {
845 need: end,
846 have: af.len(),
847 what: "transport_private_data",
848 })?;
849 cursor = end;
850 Some(slice)
851 } else {
852 None
853 };
854
855 let extension = if flags & AF_EXTENSION_FLAG != 0 {
857 let ext_data = af.get(cursor..).ok_or(Error::BufferTooShort {
858 need: cursor + 1,
859 have: af.len(),
860 what: "adaptation_field_extension",
861 })?;
862 let ext = AdaptationFieldExtension::parse(ext_data)?;
863 if !ext_data.is_empty() {
865 let _ext_len = ext_data[0] as usize;
866 cursor += 1 + _ext_len;
867 }
868 Some(ext)
869 } else {
870 None
871 };
872
873 let stuffing_len = af.len().saturating_sub(cursor);
877
878 Ok(AdaptationField {
879 discontinuity_indicator: flags & AF_DISCONTINUITY != 0,
880 random_access_indicator: flags & AF_RANDOM_ACCESS != 0,
881 elementary_stream_priority_indicator: flags & AF_ES_PRIORITY != 0,
882 pcr,
883 opcr,
884 splice_countdown,
885 transport_private_data,
886 extension,
887 stuffing_len,
888 })
889 }
890
891 #[must_use]
897 pub fn serialized_len(&self) -> usize {
898 let mut n = 1usize; if self.pcr.is_some() {
900 n += PCR_FIELD_LEN;
901 }
902 if self.opcr.is_some() {
903 n += PCR_FIELD_LEN;
904 }
905 if self.splice_countdown.is_some() {
906 n += 1;
907 }
908 if let Some(tpd) = self.transport_private_data {
909 n += 1 + tpd.len(); }
911 if let Some(ref ext) = self.extension {
912 n += ext.serialized_len();
913 }
914 n += self.stuffing_len;
915 n
916 }
917
918 pub fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
929 let need = self.serialized_len();
930 if buf.len() < need {
931 return Err(Error::OutputBufferTooSmall {
932 need,
933 have: buf.len(),
934 });
935 }
936
937 let mut flags = 0u8;
939 if self.discontinuity_indicator {
940 flags |= AF_DISCONTINUITY;
941 }
942 if self.random_access_indicator {
943 flags |= AF_RANDOM_ACCESS;
944 }
945 if self.elementary_stream_priority_indicator {
946 flags |= AF_ES_PRIORITY;
947 }
948 if self.pcr.is_some() {
949 flags |= AF_PCR_FLAG;
950 }
951 if self.opcr.is_some() {
952 flags |= AF_OPCR_FLAG;
953 }
954 if self.splice_countdown.is_some() {
955 flags |= AF_SPLICING_FLAG;
956 }
957 if self.transport_private_data.is_some() {
958 flags |= AF_TRANSPORT_PRIVATE_DATA_FLAG;
959 }
960 if self.extension.is_some() {
961 flags |= AF_EXTENSION_FLAG;
962 }
963 buf[0] = flags;
964
965 let mut cursor = 1usize;
966 if let Some(pcr) = self.pcr {
967 buf[cursor..cursor + PCR_FIELD_LEN].copy_from_slice(&pcr.to_field_bytes());
968 cursor += PCR_FIELD_LEN;
969 }
970 if let Some(opcr) = self.opcr {
971 buf[cursor..cursor + PCR_FIELD_LEN].copy_from_slice(&opcr.to_field_bytes());
972 cursor += PCR_FIELD_LEN;
973 }
974 if let Some(sc) = self.splice_countdown {
975 buf[cursor] = sc as u8;
976 cursor += 1;
977 }
978 if let Some(tpd) = self.transport_private_data {
979 buf[cursor] = broadcast_common::len::fit_u8(
980 tpd.len(),
981 "adaptation_field.transport_private_data_length",
982 )?;
983 cursor += 1;
984 buf[cursor..cursor + tpd.len()].copy_from_slice(tpd);
985 cursor += tpd.len();
986 }
987 if let Some(ref ext) = self.extension {
988 let written = ext.serialize_into(&mut buf[cursor..])?;
989 cursor += written;
990 }
991
992 for b in buf[cursor..cursor + self.stuffing_len].iter_mut() {
995 *b = AF_STUFFING_BYTE;
996 }
997 cursor += self.stuffing_len;
998
999 Ok(cursor)
1000 }
1001}
1002
1003#[derive(Default)]
1008pub struct SectionReassembler {
1009 buf: bytes::BytesMut,
1010 ready: alloc::collections::VecDeque<bytes::Bytes>,
1011}
1012
1013impl SectionReassembler {
1014 pub fn feed(&mut self, payload: &[u8], pusi: bool) {
1022 if pusi {
1023 if payload.is_empty() {
1026 self.buf.clear();
1027 return;
1028 }
1029 let pointer = payload[0] as usize;
1030
1031 if !self.buf.is_empty() && pointer > 0 {
1039 let avail = payload.len() - 1;
1040 let tail_len = pointer.min(avail);
1041 if self.buf.len() + tail_len > MAX_SECTION_SIZE {
1042 self.buf.clear();
1043 } else {
1044 self.buf.extend_from_slice(&payload[1..1 + tail_len]);
1045 self.drain_complete_sections();
1046 }
1047 }
1048
1049 self.buf.clear();
1052
1053 let start = 1 + pointer;
1054 if start >= payload.len() {
1055 return;
1057 }
1058 let new_data = &payload[start..];
1059 if new_data.len() > MAX_SECTION_SIZE {
1060 return;
1061 }
1062 self.buf.extend_from_slice(new_data);
1063 } else {
1064 if self.buf.is_empty() {
1065 return;
1066 }
1067 let take = if let Some(exp) = section_total_len(&self.buf) {
1077 exp.saturating_sub(self.buf.len()).min(payload.len())
1078 } else {
1079 payload.len().min(MAX_SECTION_SIZE - self.buf.len())
1083 };
1084 self.buf.extend_from_slice(&payload[..take]);
1085 }
1086
1087 self.drain_complete_sections();
1088 }
1089
1090 fn drain_complete_sections(&mut self) {
1101 loop {
1102 if self.buf.len() < SECTION_HEADER_LEN {
1103 break;
1106 }
1107 if self.buf[0] == 0xFF {
1108 self.buf.clear();
1110 break;
1111 }
1112 let exp =
1113 section_total_len(&self.buf).expect("checked len >= SECTION_HEADER_LEN above");
1114 if self.buf.len() >= exp {
1115 let section = self.buf.split_to(exp).freeze();
1118 self.ready.push_back(section);
1119 } else {
1120 break;
1122 }
1123 }
1124 }
1125
1126 pub fn pop_section(&mut self) -> Option<bytes::Bytes> {
1128 self.ready.pop_front()
1129 }
1130
1131 pub fn len(&self) -> usize {
1133 self.buf.len()
1134 }
1135
1136 pub fn is_empty(&self) -> bool {
1138 self.buf.is_empty()
1139 }
1140}
1141
1142pub fn iter_packets(buf: &[u8]) -> impl Iterator<Item = TsPacket<'_>> {
1160 buf.chunks_exact(TS_PACKET_SIZE)
1161 .filter_map(|chunk| TsPacket::parse(chunk).ok())
1162}
1163
1164pub fn extract_ts_payload(pkt: &[u8]) -> Option<&[u8]> {
1174 if pkt.len() < 4 {
1175 return None;
1176 }
1177 let header = TsHeader::parse(&pkt[..4]).ok()?;
1178 if !header.has_payload {
1179 return None;
1180 }
1181 let cursor = 4 + adaptation_field_skip(pkt, header.has_adaptation);
1182 if cursor < pkt.len() {
1183 Some(&pkt[cursor..])
1184 } else {
1185 None
1186 }
1187}
1188
1189#[cfg(test)]
1190mod tests {
1191 use super::*;
1192 use alloc::string::ToString;
1193 use alloc::vec;
1194 use alloc::vec::Vec;
1195
1196 fn make_packet(b1: u8, b2: u8, b3: u8, payload_data: &[u8]) -> [u8; TS_PACKET_SIZE] {
1198 let mut pkt = [0u8; TS_PACKET_SIZE];
1199 pkt[0] = TS_SYNC_BYTE;
1200 pkt[1] = b1;
1201 pkt[2] = b2;
1202 pkt[3] = b3;
1203 let payload_start = 4;
1204 let end = (payload_start + payload_data.len()).min(TS_PACKET_SIZE);
1205 let len = (end - payload_start).min(payload_data.len());
1206 pkt[payload_start..payload_start + len].copy_from_slice(&payload_data[..len]);
1207 pkt
1208 }
1209
1210 #[test]
1211 fn parse_rejects_non_0x47_sync_byte() {
1212 let mut pkt = [0u8; TS_PACKET_SIZE];
1213 pkt[0] = 0x46; let err = TsPacket::parse(&pkt).unwrap_err();
1215 match err {
1216 Error::InvalidSyncByte { found } => assert_eq!(found, 0x46),
1217 other => panic!("expected InvalidSyncByte, got {other:?}"),
1218 }
1219 }
1220
1221 #[test]
1222 fn ts_header_round_trip() {
1223 let cases = [
1226 TsHeader {
1227 tei: false,
1228 pusi: true,
1229 pid: 0x0000,
1230 scrambling: 0,
1231 has_adaptation: false,
1232 has_payload: true,
1233 continuity_counter: 0,
1234 },
1235 TsHeader {
1236 tei: true,
1237 pusi: false,
1238 pid: 0x1FFF,
1239 scrambling: 0b11,
1240 has_adaptation: true,
1241 has_payload: true,
1242 continuity_counter: 0x0F,
1243 },
1244 TsHeader {
1245 tei: false,
1246 pusi: false,
1247 pid: 0x0100,
1248 scrambling: 0b10,
1249 has_adaptation: true,
1250 has_payload: false,
1251 continuity_counter: 7,
1252 },
1253 ];
1254 for h in cases {
1255 let mut buf = [0u8; 4];
1256 assert_eq!(h.serialize_into(&mut buf).unwrap(), 4);
1257 assert_eq!(TsHeader::parse(&buf).unwrap(), h, "round-trip mismatch");
1258 }
1259 }
1260
1261 #[test]
1262 fn parse_extracts_pid_and_continuity_counter() {
1263 let pkt = make_packet(0x12, 0x34, 0x05, &[]);
1269 let pkt = TsPacket::parse(&pkt).unwrap();
1270 assert_eq!(pkt.header.pid, 0x1234);
1271 assert_eq!(pkt.header.continuity_counter, 5);
1272 }
1273
1274 #[test]
1275 fn payload_unit_start_indicator_flag_extracted() {
1276 let pkt1 = make_packet(0x40, 0x00, 0x00, &[]);
1278 let pkt1 = TsPacket::parse(&pkt1).unwrap();
1279 assert!(pkt1.header.pusi);
1280
1281 let pkt2 = make_packet(0x00, 0x00, 0x00, &[]);
1283 let pkt2 = TsPacket::parse(&pkt2).unwrap();
1284 assert!(!pkt2.header.pusi);
1285 }
1286
1287 fn build_pusi_payload(pointer_field: u8, previous_tail: &[u8], section: &[u8]) -> Vec<u8> {
1292 assert_eq!(pointer_field as usize, previous_tail.len());
1293 let mut v = Vec::with_capacity(1 + previous_tail.len() + section.len());
1294 v.push(pointer_field);
1295 v.extend_from_slice(previous_tail);
1296 v.extend_from_slice(section);
1297 v
1298 }
1299
1300 fn build_section(table_id: u8, body_after_length: &[u8]) -> Vec<u8> {
1304 let section_length = body_after_length.len() as u16;
1305 let mut v = Vec::with_capacity(3 + section_length as usize);
1306 v.push(table_id);
1307 v.push(0xB0 | ((section_length >> 8) as u8 & 0x0F));
1309 v.push((section_length & 0xFF) as u8);
1310 v.extend_from_slice(body_after_length);
1311 v
1312 }
1313
1314 #[test]
1320 fn reassembler_accumulates_multi_packet_section() {
1321 let body = vec![0xAAu8; 197];
1323 let section = build_section(0x02, &body);
1324 assert_eq!(section.len(), 200);
1325
1326 let first_chunk = 100;
1327 let payload1 = build_pusi_payload(0, &[], §ion[..first_chunk]);
1328 let payload2 = section[first_chunk..].to_vec();
1329
1330 let mut reasm = SectionReassembler::default();
1331 reasm.feed(&payload1, true);
1332 reasm.feed(&payload2, false);
1333
1334 let out = reasm.pop_section().expect("section should be ready");
1335 assert_eq!(out.len(), 200);
1336 assert_eq!(out.as_ref(), §ion[..]);
1337 }
1338
1339 #[test]
1340 fn reassembler_yields_complete_section_once_length_satisfied() {
1341 let section = build_section(0x42, &[0xAA]);
1343 assert_eq!(section.len(), 4);
1344 let payload = build_pusi_payload(0, &[], §ion);
1345
1346 let mut reasm = SectionReassembler::default();
1347 reasm.feed(&payload, true);
1348
1349 let out = reasm
1350 .pop_section()
1351 .expect("single-packet section should pop");
1352 assert_eq!(out.as_ref(), §ion[..]);
1353 }
1354
1355 #[test]
1356 fn reassembler_extracts_all_concatenated_sections_in_one_payload() {
1357 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();
1366 concat.extend_from_slice(&s1);
1367 concat.extend_from_slice(&s2);
1368 concat.extend_from_slice(&s3);
1369 let payload = build_pusi_payload(0, &[], &concat);
1370
1371 let mut reasm = SectionReassembler::default();
1372 reasm.feed(&payload, true);
1373
1374 let got: Vec<_> = core::iter::from_fn(|| reasm.pop_section()).collect();
1376 assert_eq!(got.len(), 3, "all three concatenated sections must pop");
1377 assert_eq!(got[0].as_ref(), &s1[..]);
1378 assert_eq!(got[1].as_ref(), &s2[..]);
1379 assert_eq!(got[2].as_ref(), &s3[..]);
1380 }
1381
1382 #[test]
1383 fn reassembler_stops_at_stuffing_after_concatenated_sections() {
1384 let s1 = build_section(0x42, &[0xAA]); let s2 = build_section(0x46, &[0xBB, 0xCC]); let mut concat = Vec::new();
1390 concat.extend_from_slice(&s1);
1391 concat.extend_from_slice(&s2);
1392 concat.extend_from_slice(&[0xFF, 0xFF, 0xFF, 0xFF]); let payload = build_pusi_payload(0, &[], &concat);
1394
1395 let mut reasm = SectionReassembler::default();
1396 reasm.feed(&payload, true);
1397
1398 let got: Vec<_> = core::iter::from_fn(|| reasm.pop_section()).collect();
1399 assert_eq!(got.len(), 2);
1400 assert_eq!(got[0].as_ref(), &s1[..]);
1401 assert_eq!(got[1].as_ref(), &s2[..]);
1402 assert!(
1403 reasm.is_empty(),
1404 "stuffing tail must be discarded, not buffered"
1405 );
1406 }
1407
1408 #[test]
1409 fn reassembler_concatenated_then_spanning_tail() {
1410 let s1 = build_section(0x42, &[0x01, 0x02]); let s2 = build_section(0x46, &[0x09u8; 60]); let split = 30;
1416
1417 let mut head = Vec::new();
1418 head.extend_from_slice(&s1);
1419 head.extend_from_slice(&s2[..split]);
1420 let payload1 = build_pusi_payload(0, &[], &head);
1421 let payload2 = s2[split..].to_vec();
1422
1423 let mut reasm = SectionReassembler::default();
1424 reasm.feed(&payload1, true);
1425 let first = reasm.pop_section().expect("first section pops at once");
1426 assert_eq!(first.as_ref(), &s1[..]);
1427 assert!(reasm.pop_section().is_none(), "second is still partial");
1428
1429 reasm.feed(&payload2, false);
1430 let second = reasm.pop_section().expect("second pops after continuation");
1431 assert_eq!(second.as_ref(), &s2[..]);
1432 }
1433
1434 #[test]
1435 fn reassembler_completes_section_spanning_into_pusi_packet() {
1436 let spanning = build_section(0x42, &[0x5Au8; 62]); let head = 41;
1444 let tail = &spanning[head..]; assert_eq!(tail.len(), 24);
1446
1447 let next = build_section(0x46, &[0x77, 0x88]); let payload_a = build_pusi_payload(0, &[], &spanning[..head]);
1452 let payload_b = build_pusi_payload(24, tail, &next);
1454
1455 let mut reasm = SectionReassembler::default();
1456 reasm.feed(&payload_a, true);
1457 assert!(reasm.pop_section().is_none(), "head alone is incomplete");
1458
1459 reasm.feed(&payload_b, true);
1460 let got: Vec<_> = core::iter::from_fn(|| reasm.pop_section()).collect();
1461 assert_eq!(got.len(), 2, "spanning section + new section must both pop");
1462 assert_eq!(
1463 got[0].as_ref(),
1464 &spanning[..],
1465 "spanning section completed from B's pointer tail"
1466 );
1467 assert_eq!(got[1].as_ref(), &next[..]);
1468 }
1469
1470 #[test]
1471 fn reassembler_pusi_pointer_spans_whole_payload() {
1472 let spanning = build_section(0x42, &[0x33u8; 40]); let head = 20;
1477 let payload_a = build_pusi_payload(0, &[], &spanning[..head]);
1478 let tail = &spanning[head..]; let mut reasm = SectionReassembler::default();
1481 reasm.feed(&payload_a, true);
1482 reasm.feed(&build_pusi_payload_pointer_spanning_all(tail), true);
1484
1485 let out = reasm.pop_section().expect("spanning section completes");
1486 assert_eq!(out.as_ref(), &spanning[..]);
1487 assert!(reasm.pop_section().is_none());
1488 }
1489
1490 fn build_pusi_payload_pointer_spanning_all(tail: &[u8]) -> Vec<u8> {
1493 let mut v = Vec::with_capacity(1 + tail.len());
1494 v.push(tail.len() as u8);
1495 v.extend_from_slice(tail);
1496 v
1497 }
1498
1499 #[test]
1500 fn reassembler_completes_max_length_section_and_stays_usable() {
1501 let mut section = Vec::with_capacity(MAX_SECTION_SIZE);
1507 section.push(0x00); section.push(0xB0 | ((4095u16 >> 8) as u8 & 0x0F));
1509 section.push(0xFF); section.resize(MAX_SECTION_SIZE, 0u8);
1511 assert_eq!(section.len(), MAX_SECTION_SIZE);
1512
1513 let mut reasm = SectionReassembler::default();
1514 let mut first = vec![0x00u8]; first.extend_from_slice(§ion[..183]);
1516 reasm.feed(&first, true);
1517 assert!(
1518 reasm.pop_section().is_none(),
1519 "incomplete until the declared length arrives"
1520 );
1521
1522 for chunk in section[183..].chunks(184) {
1523 reasm.feed(chunk, false);
1524 }
1525 let out = reasm
1526 .pop_section()
1527 .expect("max-length section completes at its declared length");
1528 assert_eq!(out.len(), MAX_SECTION_SIZE);
1529 assert_eq!(out.as_ref(), §ion[..]);
1530 assert!(reasm.is_empty());
1531
1532 reasm.feed(&[0u8; 184], false);
1536 assert!(reasm.pop_section().is_none());
1537
1538 let valid_section = build_section(0x00, &[0xAA]);
1540 let payload2 = build_pusi_payload(0, &[], &valid_section);
1541 reasm.feed(&payload2, true);
1542 let out = reasm
1543 .pop_section()
1544 .expect("fresh section should pop after reset");
1545 assert_eq!(out.as_ref(), &valid_section[..]);
1546 }
1547
1548 #[test]
1549 fn reassembler_handles_pusi_with_nonzero_pointer_field() {
1550 let prior_tail = vec![0x11, 0x22, 0x33];
1552 let new_section = build_section(0x02, &[0xBB]);
1553 assert_eq!(new_section.len(), 4);
1554 let payload = build_pusi_payload(3, &prior_tail, &new_section);
1555
1556 let mut reasm = SectionReassembler::default();
1557 reasm.feed(&payload, true);
1558
1559 let out = reasm
1560 .pop_section()
1561 .expect("section after pointer_field skip should pop");
1562 assert_eq!(out.as_ref(), &new_section[..]);
1563 }
1564
1565 #[test]
1566 fn reassembler_ignores_continuation_before_pusi() {
1567 let pkt = make_packet(0x00, 0x00, PAYLOAD_FLAG, &[0xAA, 0xBB, 0xCC]);
1570
1571 let mut reasm = SectionReassembler::default();
1572 reasm.feed(&pkt[4..], false); assert!(
1575 reasm.pop_section().is_none(),
1576 "no section should appear without prior PUSI"
1577 );
1578 assert!(
1579 reasm.pop_section().is_none(),
1580 "second pop should also be none"
1581 );
1582 }
1583
1584 #[test]
1587 fn reassembler_empty_pusi_payload_does_not_panic() {
1588 let mut reasm = SectionReassembler::default();
1589 reasm.feed(&[], true);
1590 assert!(reasm.pop_section().is_none());
1591 let payload = vec![0x00u8, 0x72, 0x70, 0x01, 0x00];
1593 reasm.feed(&payload, true);
1594 assert!(reasm.pop_section().is_some());
1595 }
1596
1597 #[test]
1601 fn reassembler_accepts_maximal_private_section() {
1602 let mut section = vec![0x80u8, 0x7F, 0xFF]; section.resize(3 + 0xFFF, 0xAB);
1604
1605 let mut reasm = SectionReassembler::default();
1606 let mut first = vec![0x00];
1608 first.extend_from_slice(§ion[..183]);
1609 reasm.feed(&first, true);
1610 for chunk in section[183..].chunks(184) {
1611 reasm.feed(chunk, false);
1612 }
1613 let out = reasm.pop_section().expect("4098-byte section should pop");
1614 assert_eq!(out.len(), 4098);
1615 assert_eq!(out.as_ref(), §ion[..]);
1616 }
1617
1618 #[test]
1623 fn reassembler_completes_large_section_with_trailing_stuffing() {
1624 let body = vec![0x5Au8; 4096 - 3];
1625 let section = build_section(0x50, &body); assert_eq!(section.len(), 4096);
1627
1628 let mut reasm = SectionReassembler::default();
1629 let mut first = vec![0x00u8];
1631 first.extend_from_slice(§ion[..183]);
1632 reasm.feed(&first, true);
1633
1634 let mut pos = 183usize;
1638 while pos < section.len() {
1639 let take = (section.len() - pos).min(184);
1640 let mut payload = section[pos..pos + take].to_vec();
1641 if take < 184 {
1642 payload.resize(184, 0xFF); }
1644 reasm.feed(&payload, false);
1645 pos += take;
1646 }
1647
1648 let out = reasm
1649 .pop_section()
1650 .expect("4096-byte section must complete despite trailing stuffing (#148)");
1651 assert_eq!(out.len(), 4096);
1652 assert_eq!(out.as_ref(), §ion[..]);
1653 assert!(reasm.is_empty(), "stuffing tail must be discarded");
1654 }
1655
1656 #[test]
1659 fn pcr_as_27mhz_known_value() {
1660 assert_eq!(
1661 Pcr {
1662 base: 10_000,
1663 extension: 0
1664 }
1665 .as_27mhz(),
1666 3_000_000
1667 );
1668 assert_eq!(
1670 Pcr {
1671 base: 1,
1672 extension: 100
1673 }
1674 .as_27mhz(),
1675 400
1676 );
1677 }
1678
1679 #[test]
1680 fn pcr_decode_from_bytes() {
1681 let af = [0x10u8, 0x00, 0x00, 0x13, 0x88, 0x7E, 0x00];
1683 let pcr = Pcr::parse(&af, 1).expect("6 bytes present");
1684 assert_eq!(
1685 pcr,
1686 Pcr {
1687 base: 10_000,
1688 extension: 0
1689 }
1690 );
1691 assert_eq!(pcr.as_27mhz(), 3_000_000);
1692 }
1693
1694 #[test]
1695 fn adaptation_field_flags_and_pcr() {
1696 let mut raw = [0xAAu8; TS_PACKET_SIZE];
1697 raw[0] = TS_SYNC_BYTE;
1698 raw[1] = 0x01; raw[2] = 0x00;
1700 raw[3] = ADAPTATION_FLAG | PAYLOAD_FLAG;
1701 raw[4] = 7; raw[5] = AF_DISCONTINUITY | AF_PCR_FLAG;
1703 raw[6..12].copy_from_slice(&[0x00, 0x00, 0x13, 0x88, 0x7E, 0x00]);
1704 let pkt = TsPacket::parse(&raw).expect("valid packet");
1707 let af = pkt
1708 .adaptation_field()
1709 .expect("has adaptation field")
1710 .expect("adaptation field parses");
1711 assert!(af.discontinuity_indicator);
1712 assert!(!af.random_access_indicator);
1713 assert_eq!(
1714 af.pcr,
1715 Some(Pcr {
1716 base: 10_000,
1717 extension: 0
1718 })
1719 );
1720 assert_eq!(af.pcr.unwrap().as_27mhz(), 3_000_000);
1721 assert!(af.opcr.is_none());
1722 assert!(af.splice_countdown.is_none());
1723 let payload = pkt.payload.expect("payload present");
1725 assert_eq!(payload.len(), TS_PACKET_SIZE - 12);
1726 assert_eq!(payload[0], 0xAA);
1727 }
1728
1729 #[test]
1730 fn oversized_adaptation_field_length_is_rejected_not_truncated() {
1731 let mut raw = [0xAAu8; TS_PACKET_SIZE];
1737 raw[0] = TS_SYNC_BYTE;
1738 raw[1] = 0x01;
1739 raw[2] = 0x00;
1740 raw[3] = ADAPTATION_FLAG; raw[4] = 200; let pkt = TsPacket::parse(&raw).expect("header + af_len byte still parse");
1744 assert!(
1745 pkt.adaptation_field().is_none(),
1746 "an over-long adaptation field must be rejected, not truncated"
1747 );
1748 assert!(pkt.payload.is_none());
1749
1750 let owned = crate::owned::OwnedTsPacket::parse(raw).unwrap();
1752 assert!(owned.adaptation_field().is_none());
1753 }
1754
1755 #[test]
1756 fn no_adaptation_returns_none() {
1757 let mut raw = [0x00u8; TS_PACKET_SIZE];
1758 raw[0] = TS_SYNC_BYTE;
1759 raw[1] = 0x01;
1760 raw[3] = PAYLOAD_FLAG; let pkt = TsPacket::parse(&raw).expect("valid");
1762 assert!(pkt.adaptation_field().is_none());
1763 assert!(pkt.adaptation.is_none());
1764 }
1765
1766 #[test]
1767 fn adaptation_field_splice_countdown_negative() {
1768 let mut raw = [0xAAu8; TS_PACKET_SIZE];
1769 raw[0] = TS_SYNC_BYTE;
1770 raw[1] = 0x01;
1771 raw[2] = 0x00;
1772 raw[3] = ADAPTATION_FLAG | PAYLOAD_FLAG;
1773 raw[4] = 2; raw[5] = AF_SPLICING_FLAG;
1775 raw[6] = 0xFB; let pkt = TsPacket::parse(&raw).expect("valid");
1777 let af = pkt.adaptation_field().unwrap().unwrap();
1778 assert_eq!(af.splice_countdown, Some(-5));
1779 assert!(af.pcr.is_none());
1780 }
1781
1782 #[test]
1785 fn scrambling_control_all_values() {
1786 assert_eq!(
1787 ScramblingControl::from_bits(0b00),
1788 ScramblingControl::NotScrambled
1789 );
1790 assert_eq!(
1791 ScramblingControl::from_bits(0b01),
1792 ScramblingControl::Reserved
1793 );
1794 assert_eq!(
1795 ScramblingControl::from_bits(0b10),
1796 ScramblingControl::EvenKey
1797 );
1798 assert_eq!(
1799 ScramblingControl::from_bits(0b11),
1800 ScramblingControl::OddKey
1801 );
1802 assert_eq!(ScramblingControl::NotScrambled.name(), "not_scrambled");
1804 assert_eq!(ScramblingControl::Reserved.name(), "reserved");
1805 assert_eq!(ScramblingControl::EvenKey.name(), "even_key");
1806 assert_eq!(ScramblingControl::OddKey.name(), "odd_key");
1807 assert_eq!(ScramblingControl::NotScrambled.to_string(), "not_scrambled");
1809 assert_eq!(ScramblingControl::OddKey.to_string(), "odd_key");
1810 assert_eq!(
1812 ScramblingControl::from_bits(0xFF),
1813 ScramblingControl::OddKey
1814 );
1815 }
1816
1817 #[test]
1818 fn adaptation_field_control_all_values() {
1819 assert_eq!(
1820 AdaptationFieldControl::from_flags(false, false),
1821 AdaptationFieldControl::Reserved
1822 );
1823 assert_eq!(
1824 AdaptationFieldControl::from_flags(false, true),
1825 AdaptationFieldControl::PayloadOnly
1826 );
1827 assert_eq!(
1828 AdaptationFieldControl::from_flags(true, false),
1829 AdaptationFieldControl::AdaptationOnly
1830 );
1831 assert_eq!(
1832 AdaptationFieldControl::from_flags(true, true),
1833 AdaptationFieldControl::AdaptationAndPayload
1834 );
1835 assert_eq!(AdaptationFieldControl::Reserved.name(), "reserved");
1837 assert_eq!(AdaptationFieldControl::PayloadOnly.name(), "payload_only");
1838 assert_eq!(
1839 AdaptationFieldControl::AdaptationOnly.name(),
1840 "adaptation_only"
1841 );
1842 assert_eq!(
1843 AdaptationFieldControl::AdaptationAndPayload.name(),
1844 "adaptation_and_payload"
1845 );
1846 assert_eq!(
1848 AdaptationFieldControl::PayloadOnly.to_string(),
1849 "payload_only"
1850 );
1851 }
1852
1853 #[test]
1854 fn ts_header_scrambling_control_accessor() {
1855 let hdr = TsHeader {
1856 tei: false,
1857 pusi: false,
1858 pid: 0x0100,
1859 scrambling: 0b10,
1860 has_adaptation: false,
1861 has_payload: true,
1862 continuity_counter: 0,
1863 };
1864 assert_eq!(hdr.scrambling_control(), ScramblingControl::EvenKey);
1865 }
1866
1867 #[test]
1868 fn ts_header_adaptation_field_control_accessor() {
1869 let hdr_payload_only = TsHeader {
1870 tei: false,
1871 pusi: false,
1872 pid: 0x0100,
1873 scrambling: 0,
1874 has_adaptation: false,
1875 has_payload: true,
1876 continuity_counter: 0,
1877 };
1878 assert_eq!(
1879 hdr_payload_only.adaptation_field_control(),
1880 AdaptationFieldControl::PayloadOnly
1881 );
1882
1883 let hdr_both = TsHeader {
1884 tei: false,
1885 pusi: false,
1886 pid: 0x0100,
1887 scrambling: 0,
1888 has_adaptation: true,
1889 has_payload: true,
1890 continuity_counter: 0,
1891 };
1892 assert_eq!(
1893 hdr_both.adaptation_field_control(),
1894 AdaptationFieldControl::AdaptationAndPayload
1895 );
1896 }
1897
1898 #[test]
1901 fn iter_packets_yields_valid_and_skips_bad_sync() {
1902 let pkt1 = make_packet(0x00, 0x00, PAYLOAD_FLAG, &[0xAA; 10]);
1904 let pkt2 = make_packet(0x40, 0x64, PAYLOAD_FLAG, &[0xBB; 10]);
1905 let mut bad = [0u8; TS_PACKET_SIZE];
1906 bad[0] = 0x00; let mut buf = Vec::new();
1909 buf.extend_from_slice(&pkt1);
1910 buf.extend_from_slice(&pkt2);
1911 buf.extend_from_slice(&bad);
1912
1913 let pkts: Vec<_> = super::iter_packets(&buf).collect();
1914 assert_eq!(pkts.len(), 2, "bad sync packet must be skipped");
1915 assert_eq!(pkts[0].header.pid, 0x0000);
1916 assert_eq!(pkts[1].header.pid, 0x0064);
1917 }
1918
1919 #[test]
1920 fn extract_ts_payload_payload_only() {
1921 let pkt = make_packet(0x00, 0x00, PAYLOAD_FLAG, &[0xABu8; 10]);
1922 let p = super::extract_ts_payload(&pkt).expect("payload present");
1923 assert_eq!(p[0], 0xAB);
1924 assert_eq!(p.len(), TS_PACKET_SIZE - 4);
1925 }
1926
1927 #[test]
1928 fn extract_ts_payload_adaptation_only_returns_none() {
1929 let pkt = make_packet(0x00, 0x00, ADAPTATION_FLAG, &[]);
1930 assert!(super::extract_ts_payload(&pkt).is_none());
1931 }
1932
1933 #[test]
1938 fn pcr_from_27mhz_round_trips() {
1939 for &ticks in &[0u64, 1, 300, 27_000_000, u64::from(u32::MAX), 8_589_934_591] {
1940 let pcr = Pcr::from_27mhz(ticks);
1941 assert_eq!(pcr.as_27mhz(), ticks, "ticks={ticks}");
1942 }
1943 }
1944
1945 #[test]
1947 fn pcr_to_field_bytes_round_trips_parse() {
1948 let cases = [
1949 Pcr {
1950 base: 0,
1951 extension: 0,
1952 },
1953 Pcr {
1954 base: 10_000,
1955 extension: 0,
1956 },
1957 Pcr {
1958 base: 1,
1959 extension: 100,
1960 },
1961 Pcr {
1962 base: 0x1_FFFF_FFFF,
1963 extension: 0x1FF,
1964 },
1965 ];
1966 for pcr in cases {
1967 let bytes = pcr.to_field_bytes();
1968 let mut af = [0u8; 7];
1971 af[1..7].copy_from_slice(&bytes);
1972 let decoded = Pcr::parse(&af, 1).expect("parse round-trip");
1973 assert_eq!(decoded, pcr, "round-trip failed for {pcr:?}");
1974 }
1975 }
1976
1977 #[test]
1980 fn pcr_to_field_bytes_known_vector() {
1981 let pcr = Pcr {
1982 base: 10_000,
1983 extension: 0,
1984 };
1985 let bytes = pcr.to_field_bytes();
1986 assert_eq!(bytes, [0x00, 0x00, 0x13, 0x88, 0x7E, 0x00]);
1987 }
1988
1989 #[test]
1992 fn scrambling_control_to_bits_inverse_of_from_bits() {
1993 for bits in 0u8..=3 {
1994 let sc = ScramblingControl::from_bits(bits);
1995 assert_eq!(sc.to_bits(), bits, "to_bits() != from_bits() for {bits}");
1996 }
1997 }
1998
1999 #[test]
2002 fn adaptation_field_control_to_bits_inverse_of_from_flags() {
2003 let cases = [
2004 (false, false, 0b00u8),
2005 (false, true, 0b01),
2006 (true, false, 0b10),
2007 (true, true, 0b11),
2008 ];
2009 for (has_af, has_pl, expected_bits) in cases {
2010 let afc = AdaptationFieldControl::from_flags(has_af, has_pl);
2011 assert_eq!(afc.to_bits(), expected_bits);
2012 assert_eq!(afc.to_flags(), (has_af, has_pl));
2013 }
2014 }
2015
2016 #[test]
2020 fn adaptation_field_serialize_round_trip_with_pcr() {
2021 let original = AdaptationField {
2022 discontinuity_indicator: true,
2023 random_access_indicator: false,
2024 elementary_stream_priority_indicator: false,
2025 pcr: Some(Pcr {
2026 base: 10_000,
2027 extension: 0,
2028 }),
2029 opcr: None,
2030 splice_countdown: None,
2031 transport_private_data: None,
2032 extension: None,
2033 stuffing_len: 0,
2034 };
2035 let len = original.serialized_len();
2036 assert_eq!(len, 7); let mut buf = vec![0u8; len];
2038 let written = original.serialize_into(&mut buf).expect("serialize");
2039 assert_eq!(written, len);
2040 let decoded = AdaptationField::parse(&buf).expect("parse round-trip");
2041 assert_eq!(decoded, original);
2042 }
2043
2044 #[test]
2048 fn transport_private_data_over_255_bytes_rejected_not_wrapped() {
2049 let data = vec![0u8; 256];
2050 let af = AdaptationField {
2051 discontinuity_indicator: false,
2052 random_access_indicator: false,
2053 elementary_stream_priority_indicator: false,
2054 pcr: None,
2055 opcr: None,
2056 splice_countdown: None,
2057 transport_private_data: Some(&data),
2058 extension: None,
2059 stuffing_len: 0,
2060 };
2061 let mut buf = vec![0u8; af.serialized_len()];
2062 assert!(af.serialize_into(&mut buf).is_err());
2063 }
2064
2065 #[test]
2067 fn adaptation_field_serialize_produces_known_bytes() {
2068 let af = AdaptationField {
2072 discontinuity_indicator: true,
2073 random_access_indicator: false,
2074 elementary_stream_priority_indicator: false,
2075 pcr: Some(Pcr {
2076 base: 10_000,
2077 extension: 0,
2078 }),
2079 opcr: None,
2080 splice_countdown: None,
2081 transport_private_data: None,
2082 extension: None,
2083 stuffing_len: 0,
2084 };
2085 let mut buf = [0u8; 7];
2086 af.serialize_into(&mut buf).unwrap();
2087 assert_eq!(buf[0], AF_DISCONTINUITY | AF_PCR_FLAG);
2088 assert_eq!(&buf[1..7], &[0x00, 0x00, 0x13, 0x88, 0x7E, 0x00]);
2089 }
2090
2091 #[test]
2093 fn adaptation_field_serialize_round_trip_opcr_and_splice() {
2094 let original = AdaptationField {
2095 discontinuity_indicator: false,
2096 random_access_indicator: true,
2097 elementary_stream_priority_indicator: true,
2098 pcr: Some(Pcr {
2099 base: 1,
2100 extension: 100,
2101 }),
2102 opcr: Some(Pcr {
2103 base: 999,
2104 extension: 5,
2105 }),
2106 splice_countdown: Some(-3),
2107 transport_private_data: None,
2108 extension: None,
2109 stuffing_len: 0,
2110 };
2111 let len = original.serialized_len();
2112 assert_eq!(len, 1 + 6 + 6 + 1); let mut buf = vec![0u8; len];
2114 original.serialize_into(&mut buf).unwrap();
2115 let decoded = AdaptationField::parse(&buf).expect("parse");
2116 assert_eq!(decoded, original);
2117 }
2118
2119 #[test]
2121 fn adaptation_field_serialize_flags_only() {
2122 let af = AdaptationField {
2123 discontinuity_indicator: false,
2124 random_access_indicator: true,
2125 elementary_stream_priority_indicator: false,
2126 pcr: None,
2127 opcr: None,
2128 splice_countdown: None,
2129 transport_private_data: None,
2130 extension: None,
2131 stuffing_len: 0,
2132 };
2133 assert_eq!(af.serialized_len(), 1);
2134 let mut buf = [0u8; 1];
2135 af.serialize_into(&mut buf).unwrap();
2136 assert_eq!(buf[0], AF_RANDOM_ACCESS);
2137 let decoded = AdaptationField::parse(&buf).unwrap();
2138 assert_eq!(decoded, af);
2139 }
2140
2141 #[test]
2143 fn adaptation_field_serialize_rejects_small_buffer() {
2144 let af = AdaptationField {
2145 discontinuity_indicator: false,
2146 random_access_indicator: false,
2147 elementary_stream_priority_indicator: false,
2148 pcr: Some(Pcr {
2149 base: 0,
2150 extension: 0,
2151 }),
2152 opcr: None,
2153 splice_countdown: None,
2154 transport_private_data: None,
2155 extension: None,
2156 stuffing_len: 0,
2157 };
2158 let mut buf = [0u8; 3]; assert!(matches!(
2160 af.serialize_into(&mut buf),
2161 Err(Error::OutputBufferTooSmall { .. })
2162 ));
2163 }
2164
2165 #[test]
2169 fn adaptation_field_extension_ltw_round_trip() {
2170 let ext = AdaptationFieldExtension {
2171 ltw: Some(Ltw {
2172 ltw_valid_flag: true,
2173 ltw_offset: 0x1234,
2174 }),
2175 piecewise_rate: None,
2176 seamless_splice: None,
2177 };
2178 let mut buf = vec![0u8; ext.serialized_len()];
2179 ext.serialize_into(&mut buf).unwrap();
2180 let af = AdaptationField {
2183 discontinuity_indicator: false,
2184 random_access_indicator: false,
2185 elementary_stream_priority_indicator: false,
2186 pcr: None,
2187 opcr: None,
2188 splice_countdown: None,
2189 transport_private_data: None,
2190 extension: Some(ext),
2191 stuffing_len: 0,
2192 };
2193 let len = af.serialized_len();
2194 let mut abuf = vec![0u8; len];
2195 af.serialize_into(&mut abuf).unwrap();
2196 let decoded = AdaptationField::parse(&abuf).unwrap();
2197 assert_eq!(decoded.extension, Some(ext));
2198 }
2199
2200 #[test]
2202 fn adaptation_field_extension_piecewise_rate_round_trip() {
2203 let af = AdaptationField {
2204 discontinuity_indicator: false,
2205 random_access_indicator: false,
2206 elementary_stream_priority_indicator: false,
2207 pcr: None,
2208 opcr: None,
2209 splice_countdown: None,
2210 transport_private_data: None,
2211 extension: Some(AdaptationFieldExtension {
2212 ltw: None,
2213 piecewise_rate: Some(0x3FFFFF), seamless_splice: None,
2215 }),
2216 stuffing_len: 0,
2217 };
2218 let mut buf = vec![0u8; af.serialized_len()];
2219 af.serialize_into(&mut buf).unwrap();
2220 let decoded = AdaptationField::parse(&buf).unwrap();
2221 assert_eq!(decoded.extension.unwrap().piecewise_rate, Some(0x3FFFFF));
2222 }
2223
2224 #[test]
2226 fn adaptation_field_extension_seamless_splice_round_trip() {
2227 let af = AdaptationField {
2228 discontinuity_indicator: false,
2229 random_access_indicator: false,
2230 elementary_stream_priority_indicator: false,
2231 pcr: None,
2232 opcr: None,
2233 splice_countdown: None,
2234 transport_private_data: None,
2235 extension: Some(AdaptationFieldExtension {
2236 ltw: None,
2237 piecewise_rate: None,
2238 seamless_splice: Some(SeamlessSplice {
2239 splice_type: 0xA,
2240 dts_next_au: 0x1_2345_6789,
2241 }),
2242 }),
2243 stuffing_len: 0,
2244 };
2245 let mut buf = vec![0u8; af.serialized_len()];
2246 af.serialize_into(&mut buf).unwrap();
2247 let decoded = AdaptationField::parse(&buf).unwrap();
2248 let ss = decoded.extension.unwrap().seamless_splice.unwrap();
2249 assert_eq!(ss.splice_type, 0xA);
2250 assert_eq!(ss.dts_next_au, 0x1_2345_6789);
2251 }
2252
2253 #[test]
2255 fn adaptation_field_transport_private_data_round_trip() {
2256 let tpd = [0xDE, 0xAD, 0xBE, 0xEF];
2257 let af = AdaptationField {
2258 discontinuity_indicator: false,
2259 random_access_indicator: false,
2260 elementary_stream_priority_indicator: false,
2261 pcr: None,
2262 opcr: None,
2263 splice_countdown: None,
2264 transport_private_data: Some(&tpd),
2265 extension: None,
2266 stuffing_len: 0,
2267 };
2268 let mut buf = vec![0u8; af.serialized_len()];
2269 af.serialize_into(&mut buf).unwrap();
2270 let decoded = AdaptationField::parse(&buf).unwrap();
2271 assert_eq!(decoded.transport_private_data, Some(tpd.as_slice()));
2272 }
2273
2274 #[test]
2277 fn adaptation_field_stuffing_round_trip() {
2278 let af = AdaptationField {
2279 discontinuity_indicator: false,
2280 random_access_indicator: false,
2281 elementary_stream_priority_indicator: false,
2282 pcr: Some(Pcr {
2283 base: 12_345,
2284 extension: 7,
2285 }),
2286 opcr: None,
2287 splice_countdown: None,
2288 transport_private_data: None,
2289 extension: None,
2290 stuffing_len: 20,
2291 };
2292 assert_eq!(af.serialized_len(), 27);
2294 let mut buf = vec![0u8; af.serialized_len()];
2295 af.serialize_into(&mut buf).unwrap();
2296 assert!(buf[7..27].iter().all(|&b| b == AF_STUFFING_BYTE));
2298 let decoded = AdaptationField::parse(&buf).unwrap();
2299 assert_eq!(decoded.stuffing_len, 20);
2300 assert_eq!(decoded, af);
2301 let pure = AdaptationField {
2303 discontinuity_indicator: false,
2304 random_access_indicator: false,
2305 elementary_stream_priority_indicator: false,
2306 pcr: None,
2307 opcr: None,
2308 splice_countdown: None,
2309 transport_private_data: None,
2310 extension: None,
2311 stuffing_len: 5,
2312 };
2313 let mut pbuf = vec![0u8; pure.serialized_len()];
2314 pure.serialize_into(&mut pbuf).unwrap();
2315 assert_eq!(pbuf, vec![0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]);
2316 assert_eq!(AdaptationField::parse(&pbuf).unwrap(), pure);
2317 }
2318
2319 #[test]
2321 fn adaptation_field_all_fields_round_trip() {
2322 let tpd = [0x01u8, 0x02, 0x03];
2323 let af = AdaptationField {
2324 discontinuity_indicator: true,
2325 random_access_indicator: false,
2326 elementary_stream_priority_indicator: false,
2327 pcr: Some(Pcr {
2328 base: 90_000,
2329 extension: 50,
2330 }),
2331 opcr: None,
2332 splice_countdown: Some(10),
2333 transport_private_data: Some(&tpd),
2334 extension: Some(AdaptationFieldExtension {
2335 ltw: Some(Ltw {
2336 ltw_valid_flag: false,
2337 ltw_offset: 500,
2338 }),
2339 piecewise_rate: Some(12345),
2340 seamless_splice: None,
2341 }),
2342 stuffing_len: 0,
2343 };
2344 let len = af.serialized_len();
2345 let mut buf = vec![0u8; len];
2346 af.serialize_into(&mut buf).unwrap();
2347 let decoded = AdaptationField::parse(&buf).unwrap();
2348 assert_eq!(decoded.pcr, af.pcr);
2349 assert_eq!(decoded.splice_countdown, af.splice_countdown);
2350 assert_eq!(decoded.transport_private_data, af.transport_private_data);
2351 assert_eq!(decoded.extension, af.extension);
2352 assert!(decoded.discontinuity_indicator);
2353 }
2354
2355 #[test]
2358 fn adaptation_field_serialize_from_real_packet_bytes() {
2359 let mut raw = [0xAAu8; TS_PACKET_SIZE];
2361 raw[0] = TS_SYNC_BYTE;
2362 raw[1] = 0x01;
2363 raw[2] = 0x00;
2364 raw[3] = ADAPTATION_FLAG | PAYLOAD_FLAG;
2365 raw[4] = 7;
2366 raw[5] = AF_DISCONTINUITY | AF_PCR_FLAG;
2367 raw[6..12].copy_from_slice(&[0x00, 0x00, 0x13, 0x88, 0x7E, 0x00]);
2368
2369 let pkt = TsPacket::parse(&raw).unwrap();
2370 let af = pkt.adaptation_field().unwrap().unwrap();
2371
2372 let mut ser = vec![0u8; af.serialized_len()];
2374 af.serialize_into(&mut ser).unwrap();
2375 let decoded = AdaptationField::parse(&ser).unwrap();
2376 assert_eq!(
2377 decoded.pcr,
2378 Some(Pcr {
2379 base: 10_000,
2380 extension: 0
2381 })
2382 );
2383 assert!(decoded.discontinuity_indicator);
2384 }
2385}