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
23#[non_exhaustive]
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33#[cfg_attr(feature = "serde", derive(serde::Serialize))]
34pub enum ScramblingControl {
35 NotScrambled,
37 Reserved,
39 EvenKey,
42 OddKey,
45}
46
47impl ScramblingControl {
48 pub fn from_bits(bits: u8) -> Self {
50 match bits & 0b11 {
51 0b00 => Self::NotScrambled,
52 0b01 => Self::Reserved,
53 0b10 => Self::EvenKey,
54 0b11 => Self::OddKey,
55 _ => unreachable!(),
56 }
57 }
58
59 pub fn to_bits(self) -> u8 {
64 match self {
65 Self::NotScrambled => 0b00,
66 Self::Reserved => 0b01,
67 Self::EvenKey => 0b10,
68 Self::OddKey => 0b11,
69 }
70 }
71
72 pub fn name(&self) -> &'static str {
74 match self {
75 Self::NotScrambled => "not_scrambled",
76 Self::Reserved => "reserved",
77 Self::EvenKey => "even_key",
78 Self::OddKey => "odd_key",
79 }
80 }
81}
82
83broadcast_common::impl_spec_display!(ScramblingControl);
84
85#[non_exhaustive]
91#[derive(Debug, Clone, Copy, PartialEq, Eq)]
92#[cfg_attr(feature = "serde", derive(serde::Serialize))]
93pub enum AdaptationFieldControl {
94 Reserved,
96 PayloadOnly,
98 AdaptationOnly,
100 AdaptationAndPayload,
102}
103
104impl AdaptationFieldControl {
105 pub fn from_flags(has_adaptation: bool, has_payload: bool) -> Self {
107 match (has_adaptation, has_payload) {
108 (false, false) => Self::Reserved,
109 (false, true) => Self::PayloadOnly,
110 (true, false) => Self::AdaptationOnly,
111 (true, true) => Self::AdaptationAndPayload,
112 }
113 }
114
115 pub fn to_bits(self) -> u8 {
121 match self {
122 Self::Reserved => 0b00,
123 Self::PayloadOnly => 0b01,
124 Self::AdaptationOnly => 0b10,
125 Self::AdaptationAndPayload => 0b11,
126 }
127 }
128
129 pub fn to_flags(self) -> (bool, bool) {
132 match self {
133 Self::Reserved => (false, false),
134 Self::PayloadOnly => (false, true),
135 Self::AdaptationOnly => (true, false),
136 Self::AdaptationAndPayload => (true, true),
137 }
138 }
139
140 pub fn name(&self) -> &'static str {
142 match self {
143 Self::Reserved => "reserved",
144 Self::PayloadOnly => "payload_only",
145 Self::AdaptationOnly => "adaptation_only",
146 Self::AdaptationAndPayload => "adaptation_and_payload",
147 }
148 }
149}
150
151broadcast_common::impl_spec_display!(AdaptationFieldControl);
152
153const TEI_MASK: u8 = 0x80;
155const PUSI_MASK: u8 = 0x40;
157pub const PID_MASK_HI: u8 = 0x1F;
159pub const SCRAMBLING_MASK: u8 = 0xC0;
161pub const ADAPTATION_FLAG: u8 = 0x20;
163pub const PAYLOAD_FLAG: u8 = 0x10;
165pub const CC_MASK: u8 = 0x0F;
167
168#[derive(Clone, Debug, PartialEq, Eq)]
170#[cfg_attr(feature = "serde", derive(serde::Serialize))]
171pub struct TsHeader {
172 pub tei: bool,
175 pub pusi: bool,
178 pub pid: u16,
180 pub scrambling: u8,
182 pub has_adaptation: bool,
184 pub has_payload: bool,
186 pub continuity_counter: u8,
188}
189
190#[derive(Clone, Debug)]
196#[cfg_attr(feature = "serde", derive(serde::Serialize))]
197pub struct TsPacket<'a> {
198 pub header: TsHeader,
200 pub payload: Option<&'a [u8]>,
203 #[cfg_attr(feature = "serde", serde(skip))]
206 adaptation: Option<&'a [u8]>,
207 #[cfg_attr(feature = "serde", serde(skip))]
209 pub raw: &'a [u8; TS_PACKET_SIZE],
210}
211
212impl TsHeader {
213 pub fn parse(raw4: &[u8]) -> Result<Self> {
215 if raw4.len() < 4 {
216 return Err(Error::BufferTooShort {
217 need: 4,
218 have: raw4.len(),
219 what: "TsHeader",
220 });
221 }
222 let b1 = raw4[1];
223 let b2 = raw4[2];
224 let b3 = raw4[3];
225
226 let tei = (b1 & TEI_MASK) != 0;
227 let pusi = (b1 & PUSI_MASK) != 0;
228 let pid = (((b1 & PID_MASK_HI) as u16) << 8) | (b2 as u16);
229 let scrambling = (b3 & SCRAMBLING_MASK) >> 6;
230 let has_adaptation = (b3 & ADAPTATION_FLAG) != 0;
231 let has_payload = (b3 & PAYLOAD_FLAG) != 0;
232 let continuity_counter = b3 & CC_MASK;
233
234 Ok(Self {
235 tei,
236 pusi,
237 pid,
238 scrambling,
239 has_adaptation,
240 has_payload,
241 continuity_counter,
242 })
243 }
244
245 pub const fn serialized_len() -> usize {
247 4
248 }
249
250 pub fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
252 if buf.len() < 4 {
253 return Err(Error::OutputBufferTooSmall {
254 need: 4,
255 have: buf.len(),
256 });
257 }
258 buf[0] = TS_SYNC_BYTE;
259 buf[1] = 0;
260 if self.tei {
261 buf[1] |= TEI_MASK;
262 }
263 if self.pusi {
264 buf[1] |= PUSI_MASK;
265 }
266 buf[1] |= ((self.pid >> 8) as u8) & PID_MASK_HI;
267 buf[2] = (self.pid & 0xFF) as u8;
268 buf[3] = (self.scrambling << 6) & SCRAMBLING_MASK;
269 if self.has_adaptation {
270 buf[3] |= ADAPTATION_FLAG;
271 }
272 if self.has_payload {
273 buf[3] |= PAYLOAD_FLAG;
274 }
275 buf[3] |= self.continuity_counter & CC_MASK;
276 Ok(4)
277 }
278
279 pub fn scrambling_control(&self) -> ScramblingControl {
284 ScramblingControl::from_bits(self.scrambling)
285 }
286
287 pub fn adaptation_field_control(&self) -> AdaptationFieldControl {
292 AdaptationFieldControl::from_flags(self.has_adaptation, self.has_payload)
293 }
294}
295
296impl<'a> broadcast_common::Parse<'a> for TsHeader {
297 type Error = Error;
298
299 fn parse(bytes: &'a [u8]) -> Result<Self> {
300 TsHeader::parse(bytes)
301 }
302}
303
304impl broadcast_common::Serialize for TsHeader {
305 type Error = Error;
306
307 fn serialized_len(&self) -> usize {
308 TsHeader::serialized_len()
309 }
310
311 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
312 TsHeader::serialize_into(self, buf)
313 }
314}
315
316impl<'a> TsPacket<'a> {
317 pub fn parse(buf: &'a [u8]) -> Result<Self> {
323 if buf.len() < TS_PACKET_SIZE {
324 return Err(Error::BufferTooShort {
325 need: TS_PACKET_SIZE,
326 have: buf.len(),
327 what: "TsPacket",
328 });
329 }
330 if buf[0] != TS_SYNC_BYTE {
331 return Err(Error::InvalidSyncByte { found: buf[0] });
332 }
333
334 let raw: &[u8; TS_PACKET_SIZE] =
335 buf[..TS_PACKET_SIZE]
336 .try_into()
337 .map_err(|_| Error::BufferTooShort {
338 need: TS_PACKET_SIZE,
339 have: buf.len(),
340 what: "TsPacket::parse (array conversion)",
341 })?;
342
343 let header = TsHeader::parse(&raw[..4])?;
344
345 let mut cursor = 4usize;
346 let mut payload = None;
347 let mut adaptation = None;
348
349 if header.has_adaptation && cursor < TS_PACKET_SIZE {
352 let af_len = raw[cursor] as usize;
353 let af_start = cursor + 1;
354 if af_len > 0 && af_start < TS_PACKET_SIZE {
355 let af_end = (af_start + af_len).min(TS_PACKET_SIZE);
356 adaptation = Some(&raw[af_start..af_end]);
357 }
358 cursor += 1 + af_len;
359 }
360
361 if header.has_payload && cursor < TS_PACKET_SIZE {
362 payload = Some(&raw[cursor..]);
363 }
364
365 Ok(TsPacket {
366 header,
367 payload,
368 adaptation,
369 raw,
370 })
371 }
372
373 pub fn adaptation_field(&self) -> Option<crate::Result<AdaptationField<'a>>> {
379 self.adaptation.map(AdaptationField::parse)
380 }
381}
382
383pub(crate) const AF_DISCONTINUITY: u8 = 0x80;
385pub(crate) const AF_RANDOM_ACCESS: u8 = 0x40;
386pub(crate) const AF_ES_PRIORITY: u8 = 0x20;
387pub const AF_PCR_FLAG: u8 = 0x10;
389pub(crate) const AF_OPCR_FLAG: u8 = 0x08;
390pub(crate) const AF_SPLICING_FLAG: u8 = 0x04;
391pub(crate) const AF_TRANSPORT_PRIVATE_DATA_FLAG: u8 = 0x02;
392pub(crate) const AF_EXTENSION_FLAG: u8 = 0x01;
393pub(crate) const AF_STUFFING_BYTE: u8 = 0xFF;
395pub(crate) const PCR_FIELD_LEN: usize = 6;
397
398#[derive(Clone, Copy, Debug, PartialEq, Eq)]
401#[cfg_attr(feature = "serde", derive(serde::Serialize))]
402pub struct Pcr {
403 pub base: u64,
405 pub extension: u16,
407}
408
409impl Pcr {
410 #[must_use]
414 pub fn as_27mhz(self) -> u64 {
415 self.base * 300 + self.extension as u64
416 }
417
418 #[must_use]
427 pub fn from_27mhz(ticks: u64) -> Self {
428 const BASE_MASK: u64 = 0x1_FFFF_FFFF;
430 const EXT_MASK: u16 = 0x1FF;
432 Self {
433 base: (ticks / 300) & BASE_MASK,
434 extension: ((ticks % 300) as u16) & EXT_MASK,
435 }
436 }
437
438 #[must_use]
447 pub fn to_field_bytes(self) -> [u8; PCR_FIELD_LEN] {
448 let b = self.base;
449 let e = self.extension as u64;
450 [
451 ((b >> 25) & 0xFF) as u8,
452 ((b >> 17) & 0xFF) as u8,
453 ((b >> 9) & 0xFF) as u8,
454 ((b >> 1) & 0xFF) as u8,
455 (((b & 0x01) as u8) << 7) | 0x7E | ((e >> 8) as u8 & 0x01),
457 (e & 0xFF) as u8,
458 ]
459 }
460
461 pub(crate) fn parse(af: &[u8], at: usize) -> Result<Self> {
463 let b: &[u8; PCR_FIELD_LEN] = af
464 .get(at..at + PCR_FIELD_LEN)
465 .and_then(|s| s.try_into().ok())
466 .ok_or(Error::BufferTooShort {
467 need: at + PCR_FIELD_LEN,
468 have: af.len(),
469 what: "adaptation_field PCR",
470 })?;
471 let base = ((b[0] as u64) << 25)
472 | ((b[1] as u64) << 17)
473 | ((b[2] as u64) << 9)
474 | ((b[3] as u64) << 1)
475 | ((b[4] as u64) >> 7);
476 let extension = (((b[4] & 0x01) as u16) << 8) | (b[5] as u16);
477 Ok(Self { base, extension })
478 }
479}
480
481#[derive(Clone, Copy, Debug, PartialEq, Eq)]
488#[cfg_attr(feature = "serde", derive(serde::Serialize))]
489pub struct Ltw {
490 pub ltw_valid_flag: bool,
492 pub ltw_offset: u16,
494}
495
496#[derive(Clone, Copy, Debug, PartialEq, Eq)]
503#[cfg_attr(feature = "serde", derive(serde::Serialize))]
504pub struct SeamlessSplice {
505 pub splice_type: u8,
507 pub dts_next_au: u64,
509}
510
511#[derive(Clone, Copy, Debug, PartialEq, Eq)]
517#[cfg_attr(feature = "serde", derive(serde::Serialize))]
518pub struct AdaptationFieldExtension {
519 pub ltw: Option<Ltw>,
521 pub piecewise_rate: Option<u32>,
523 pub seamless_splice: Option<SeamlessSplice>,
525}
526
527impl AdaptationFieldExtension {
528 fn parse(data: &[u8]) -> Result<Self> {
531 if data.is_empty() {
532 return Err(Error::BufferTooShort {
533 need: 1,
534 have: 0,
535 what: "adaptation_field_extension_length",
536 });
537 }
538 let ext_len = data[0] as usize;
539 if data.len() < 1 + ext_len || ext_len < 1 {
541 return Err(Error::BufferTooShort {
542 need: 2.max(1 + ext_len),
543 have: data.len(),
544 what: "adaptation_field_extension body",
545 });
546 }
547 let ext = &data[1..1 + ext_len]; let flags = ext[0];
549 let mut cursor = 1usize;
550
551 let ltw = if flags & 0x80 != 0 {
552 if ext.len() < cursor + 2 {
553 return Err(Error::BufferTooShort {
554 need: cursor + 2,
555 have: ext.len(),
556 what: "ltw_offset",
557 });
558 }
559 let w0 = ext[cursor];
560 let w1 = ext[cursor + 1];
561 cursor += 2;
562 Some(Ltw {
563 ltw_valid_flag: (w0 & 0x80) != 0,
564 ltw_offset: (((w0 & 0x7F) as u16) << 8) | (w1 as u16),
565 })
566 } else {
567 None
568 };
569
570 let piecewise_rate = if flags & 0x40 != 0 {
571 if ext.len() < cursor + 3 {
572 return Err(Error::BufferTooShort {
573 need: cursor + 3,
574 have: ext.len(),
575 what: "piecewise_rate",
576 });
577 }
578 let r = (((ext[cursor] & 0x3F) as u32) << 16)
579 | ((ext[cursor + 1] as u32) << 8)
580 | (ext[cursor + 2] as u32);
581 cursor += 3;
582 Some(r)
583 } else {
584 None
585 };
586
587 let seamless_splice = if flags & 0x20 != 0 {
589 if ext.len() < cursor + 5 {
590 return Err(Error::BufferTooShort {
591 need: cursor + 5,
592 have: ext.len(),
593 what: "seamless_splice DTS_next_AU",
594 });
595 }
596 let b = &ext[cursor..cursor + 5];
597 let splice_type = (b[0] >> 4) & 0x0F;
598 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;
603 cursor += 5;
604 Some(SeamlessSplice {
605 splice_type,
606 dts_next_au,
607 })
608 } else {
609 None
610 };
611 let _ = cursor; Ok(AdaptationFieldExtension {
614 ltw,
615 piecewise_rate,
616 seamless_splice,
617 })
618 }
619
620 #[must_use]
623 pub fn serialized_len(&self) -> usize {
624 let body = 1 + self.ltw.map_or(0, |_| 2)
626 + self.piecewise_rate.map_or(0, |_| 3)
627 + self.seamless_splice.map_or(0, |_| 5);
628 1 + body }
630
631 pub fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
633 let need = self.serialized_len();
634 if buf.len() < need {
635 return Err(Error::OutputBufferTooSmall {
636 need,
637 have: buf.len(),
638 });
639 }
640 let body_len = need - 1;
641 buf[0] = body_len as u8;
642
643 let mut flags = 0u8;
644 if self.ltw.is_some() {
645 flags |= 0x80;
646 }
647 if self.piecewise_rate.is_some() {
648 flags |= 0x40;
649 }
650 if self.seamless_splice.is_some() {
651 flags |= 0x20;
652 }
653 buf[1] = flags;
654 let mut cursor = 2usize;
655
656 if let Some(ltw) = self.ltw {
657 let ltw_valid = if ltw.ltw_valid_flag { 0x80u8 } else { 0x00 };
658 buf[cursor] = ltw_valid | ((ltw.ltw_offset >> 8) as u8 & 0x7F);
659 buf[cursor + 1] = (ltw.ltw_offset & 0xFF) as u8;
660 cursor += 2;
661 }
662 if let Some(rate) = self.piecewise_rate {
663 buf[cursor] = 0xC0 | ((rate >> 16) as u8 & 0x3F);
665 buf[cursor + 1] = (rate >> 8) as u8;
666 buf[cursor + 2] = rate as u8;
667 cursor += 3;
668 }
669 if let Some(ss) = self.seamless_splice {
670 let ts = ss.dts_next_au & 0x1_FFFF_FFFF;
671 let st = ss.splice_type & 0x0F;
672 buf[cursor] = (st << 4) | ((((ts >> 30) & 0x07) as u8) << 1) | 0x01;
674 buf[cursor + 1] = ((ts >> 22) & 0xFF) as u8;
675 buf[cursor + 2] = ((((ts >> 15) & 0x7F) as u8) << 1) | 0x01;
676 buf[cursor + 3] = ((ts >> 7) & 0xFF) as u8;
677 buf[cursor + 4] = (((ts & 0x7F) as u8) << 1) | 0x01;
678 cursor += 5;
679 }
680 Ok(cursor)
681 }
682}
683
684#[non_exhaustive]
693#[derive(Clone, Debug, PartialEq, Eq)]
694#[cfg_attr(feature = "serde", derive(serde::Serialize))]
695pub struct AdaptationField<'a> {
696 pub discontinuity_indicator: bool,
698 pub random_access_indicator: bool,
700 pub elementary_stream_priority_indicator: bool,
702 pub pcr: Option<Pcr>,
704 pub opcr: Option<Pcr>,
706 pub splice_countdown: Option<i8>,
708 pub transport_private_data: Option<&'a [u8]>,
713 pub extension: Option<AdaptationFieldExtension>,
715 pub stuffing_len: usize,
725}
726
727impl<'a> AdaptationField<'a> {
728 pub(crate) fn parse(af: &'a [u8]) -> Result<Self> {
735 let flags = *af.first().ok_or(Error::BufferTooShort {
736 need: 1,
737 have: 0,
738 what: "adaptation_field flags",
739 })?;
740 let mut cursor = 1usize;
741
742 let pcr = if flags & AF_PCR_FLAG != 0 {
743 let p = Pcr::parse(af, cursor)?;
744 cursor += PCR_FIELD_LEN;
745 Some(p)
746 } else {
747 None
748 };
749 let opcr = if flags & AF_OPCR_FLAG != 0 {
750 let p = Pcr::parse(af, cursor)?;
751 cursor += PCR_FIELD_LEN;
752 Some(p)
753 } else {
754 None
755 };
756 let splice_countdown = if flags & AF_SPLICING_FLAG != 0 {
757 let b = *af.get(cursor).ok_or(Error::BufferTooShort {
758 need: cursor + 1,
759 have: af.len(),
760 what: "adaptation_field splice_countdown",
761 })?;
762 cursor += 1;
763 Some(b as i8)
764 } else {
765 None
766 };
767
768 let transport_private_data = if flags & AF_TRANSPORT_PRIVATE_DATA_FLAG != 0 {
771 let tpd_len = *af.get(cursor).ok_or(Error::BufferTooShort {
772 need: cursor + 1,
773 have: af.len(),
774 what: "transport_private_data_length",
775 })? as usize;
776 cursor += 1;
777 let end = cursor + tpd_len;
778 let slice = af.get(cursor..end).ok_or(Error::BufferTooShort {
779 need: end,
780 have: af.len(),
781 what: "transport_private_data",
782 })?;
783 cursor = end;
784 Some(slice)
785 } else {
786 None
787 };
788
789 let extension = if flags & AF_EXTENSION_FLAG != 0 {
791 let ext_data = af.get(cursor..).ok_or(Error::BufferTooShort {
792 need: cursor + 1,
793 have: af.len(),
794 what: "adaptation_field_extension",
795 })?;
796 let ext = AdaptationFieldExtension::parse(ext_data)?;
797 if !ext_data.is_empty() {
799 let _ext_len = ext_data[0] as usize;
800 cursor += 1 + _ext_len;
801 }
802 Some(ext)
803 } else {
804 None
805 };
806
807 let stuffing_len = af.len().saturating_sub(cursor);
811
812 Ok(AdaptationField {
813 discontinuity_indicator: flags & AF_DISCONTINUITY != 0,
814 random_access_indicator: flags & AF_RANDOM_ACCESS != 0,
815 elementary_stream_priority_indicator: flags & AF_ES_PRIORITY != 0,
816 pcr,
817 opcr,
818 splice_countdown,
819 transport_private_data,
820 extension,
821 stuffing_len,
822 })
823 }
824
825 #[must_use]
831 pub fn serialized_len(&self) -> usize {
832 let mut n = 1usize; if self.pcr.is_some() {
834 n += PCR_FIELD_LEN;
835 }
836 if self.opcr.is_some() {
837 n += PCR_FIELD_LEN;
838 }
839 if self.splice_countdown.is_some() {
840 n += 1;
841 }
842 if let Some(tpd) = self.transport_private_data {
843 n += 1 + tpd.len(); }
845 if let Some(ref ext) = self.extension {
846 n += ext.serialized_len();
847 }
848 n += self.stuffing_len;
849 n
850 }
851
852 pub fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
863 let need = self.serialized_len();
864 if buf.len() < need {
865 return Err(Error::OutputBufferTooSmall {
866 need,
867 have: buf.len(),
868 });
869 }
870
871 let mut flags = 0u8;
873 if self.discontinuity_indicator {
874 flags |= AF_DISCONTINUITY;
875 }
876 if self.random_access_indicator {
877 flags |= AF_RANDOM_ACCESS;
878 }
879 if self.elementary_stream_priority_indicator {
880 flags |= AF_ES_PRIORITY;
881 }
882 if self.pcr.is_some() {
883 flags |= AF_PCR_FLAG;
884 }
885 if self.opcr.is_some() {
886 flags |= AF_OPCR_FLAG;
887 }
888 if self.splice_countdown.is_some() {
889 flags |= AF_SPLICING_FLAG;
890 }
891 if self.transport_private_data.is_some() {
892 flags |= AF_TRANSPORT_PRIVATE_DATA_FLAG;
893 }
894 if self.extension.is_some() {
895 flags |= AF_EXTENSION_FLAG;
896 }
897 buf[0] = flags;
898
899 let mut cursor = 1usize;
900 if let Some(pcr) = self.pcr {
901 buf[cursor..cursor + PCR_FIELD_LEN].copy_from_slice(&pcr.to_field_bytes());
902 cursor += PCR_FIELD_LEN;
903 }
904 if let Some(opcr) = self.opcr {
905 buf[cursor..cursor + PCR_FIELD_LEN].copy_from_slice(&opcr.to_field_bytes());
906 cursor += PCR_FIELD_LEN;
907 }
908 if let Some(sc) = self.splice_countdown {
909 buf[cursor] = sc as u8;
910 cursor += 1;
911 }
912 if let Some(tpd) = self.transport_private_data {
913 buf[cursor] = tpd.len() as u8;
914 cursor += 1;
915 buf[cursor..cursor + tpd.len()].copy_from_slice(tpd);
916 cursor += tpd.len();
917 }
918 if let Some(ref ext) = self.extension {
919 let written = ext.serialize_into(&mut buf[cursor..])?;
920 cursor += written;
921 }
922
923 for b in buf[cursor..cursor + self.stuffing_len].iter_mut() {
926 *b = AF_STUFFING_BYTE;
927 }
928 cursor += self.stuffing_len;
929
930 Ok(cursor)
931 }
932}
933
934#[derive(Default)]
939pub struct SectionReassembler {
940 buf: bytes::BytesMut,
941 ready: alloc::collections::VecDeque<bytes::Bytes>,
942}
943
944impl SectionReassembler {
945 pub fn feed(&mut self, payload: &[u8], pusi: bool) {
953 if pusi {
954 if payload.is_empty() {
957 self.buf.clear();
958 return;
959 }
960 let pointer = payload[0] as usize;
961
962 if !self.buf.is_empty() && pointer > 0 {
970 let avail = payload.len() - 1;
971 let tail_len = pointer.min(avail);
972 if self.buf.len() + tail_len > MAX_SECTION_SIZE {
973 self.buf.clear();
974 } else {
975 self.buf.extend_from_slice(&payload[1..1 + tail_len]);
976 self.drain_complete_sections();
977 }
978 }
979
980 self.buf.clear();
983
984 let start = 1 + pointer;
985 if start >= payload.len() {
986 return;
988 }
989 let new_data = &payload[start..];
990 if new_data.len() > MAX_SECTION_SIZE {
991 return;
992 }
993 self.buf.extend_from_slice(new_data);
994 } else {
995 if self.buf.is_empty() {
996 return;
997 }
998 let take = if self.buf.len() >= SECTION_HEADER_LEN {
1008 let exp = SECTION_HEADER_LEN
1009 + (((self.buf[1] & SECTION_LENGTH_HI_MASK) as usize) << 8
1010 | self.buf[2] as usize);
1011 exp.saturating_sub(self.buf.len()).min(payload.len())
1012 } else {
1013 payload.len().min(MAX_SECTION_SIZE - self.buf.len())
1017 };
1018 self.buf.extend_from_slice(&payload[..take]);
1019 }
1020
1021 self.drain_complete_sections();
1022 }
1023
1024 fn drain_complete_sections(&mut self) {
1035 loop {
1036 if self.buf.len() < SECTION_HEADER_LEN {
1037 break;
1040 }
1041 if self.buf[0] == 0xFF {
1042 self.buf.clear();
1044 break;
1045 }
1046 let exp = SECTION_HEADER_LEN
1047 + (((self.buf[1] & SECTION_LENGTH_HI_MASK) as usize) << 8 | self.buf[2] as usize);
1048 if self.buf.len() >= exp {
1049 let section = self.buf.split_to(exp).freeze();
1052 self.ready.push_back(section);
1053 } else {
1054 break;
1056 }
1057 }
1058 }
1059
1060 pub fn pop_section(&mut self) -> Option<bytes::Bytes> {
1062 self.ready.pop_front()
1063 }
1064
1065 pub fn len(&self) -> usize {
1067 self.buf.len()
1068 }
1069
1070 pub fn is_empty(&self) -> bool {
1072 self.buf.is_empty()
1073 }
1074}
1075
1076pub fn iter_packets(buf: &[u8]) -> impl Iterator<Item = TsPacket<'_>> {
1094 buf.chunks_exact(TS_PACKET_SIZE)
1095 .filter_map(|chunk| TsPacket::parse(chunk).ok())
1096}
1097
1098pub fn extract_ts_payload(pkt: &[u8]) -> Option<&[u8]> {
1108 if pkt.len() < 4 {
1109 return None;
1110 }
1111 let afc = (pkt[3] >> 4) & 0x3;
1112 match afc {
1113 0x1 => {
1114 if pkt.len() > 4 {
1116 Some(&pkt[4..])
1117 } else {
1118 None
1119 }
1120 }
1121 0x3 => {
1122 if pkt.len() < 5 {
1124 return None;
1125 }
1126 let af_len = pkt[4] as usize;
1127 let start = 5 + af_len;
1128 if start < pkt.len() {
1129 Some(&pkt[start..])
1130 } else {
1131 None
1132 }
1133 }
1134 _ => None,
1135 }
1136}
1137
1138#[cfg(test)]
1139mod tests {
1140 use super::*;
1141 use alloc::string::ToString;
1142 use alloc::vec;
1143 use alloc::vec::Vec;
1144
1145 fn make_packet(b1: u8, b2: u8, b3: u8, payload_data: &[u8]) -> [u8; TS_PACKET_SIZE] {
1147 let mut pkt = [0u8; TS_PACKET_SIZE];
1148 pkt[0] = TS_SYNC_BYTE;
1149 pkt[1] = b1;
1150 pkt[2] = b2;
1151 pkt[3] = b3;
1152 let payload_start = 4;
1153 let end = (payload_start + payload_data.len()).min(TS_PACKET_SIZE);
1154 let len = (end - payload_start).min(payload_data.len());
1155 pkt[payload_start..payload_start + len].copy_from_slice(&payload_data[..len]);
1156 pkt
1157 }
1158
1159 #[test]
1160 fn parse_rejects_non_0x47_sync_byte() {
1161 let mut pkt = [0u8; TS_PACKET_SIZE];
1162 pkt[0] = 0x46; let err = TsPacket::parse(&pkt).unwrap_err();
1164 match err {
1165 Error::InvalidSyncByte { found } => assert_eq!(found, 0x46),
1166 other => panic!("expected InvalidSyncByte, got {other:?}"),
1167 }
1168 }
1169
1170 #[test]
1171 fn ts_header_round_trip() {
1172 let cases = [
1175 TsHeader {
1176 tei: false,
1177 pusi: true,
1178 pid: 0x0000,
1179 scrambling: 0,
1180 has_adaptation: false,
1181 has_payload: true,
1182 continuity_counter: 0,
1183 },
1184 TsHeader {
1185 tei: true,
1186 pusi: false,
1187 pid: 0x1FFF,
1188 scrambling: 0b11,
1189 has_adaptation: true,
1190 has_payload: true,
1191 continuity_counter: 0x0F,
1192 },
1193 TsHeader {
1194 tei: false,
1195 pusi: false,
1196 pid: 0x0100,
1197 scrambling: 0b10,
1198 has_adaptation: true,
1199 has_payload: false,
1200 continuity_counter: 7,
1201 },
1202 ];
1203 for h in cases {
1204 let mut buf = [0u8; 4];
1205 assert_eq!(h.serialize_into(&mut buf).unwrap(), 4);
1206 assert_eq!(TsHeader::parse(&buf).unwrap(), h, "round-trip mismatch");
1207 }
1208 }
1209
1210 #[test]
1211 fn parse_extracts_pid_and_continuity_counter() {
1212 let pkt = make_packet(0x12, 0x34, 0x05, &[]);
1218 let pkt = TsPacket::parse(&pkt).unwrap();
1219 assert_eq!(pkt.header.pid, 0x1234);
1220 assert_eq!(pkt.header.continuity_counter, 5);
1221 }
1222
1223 #[test]
1224 fn payload_unit_start_indicator_flag_extracted() {
1225 let pkt1 = make_packet(0x40, 0x00, 0x00, &[]);
1227 let pkt1 = TsPacket::parse(&pkt1).unwrap();
1228 assert!(pkt1.header.pusi);
1229
1230 let pkt2 = make_packet(0x00, 0x00, 0x00, &[]);
1232 let pkt2 = TsPacket::parse(&pkt2).unwrap();
1233 assert!(!pkt2.header.pusi);
1234 }
1235
1236 fn build_pusi_payload(pointer_field: u8, previous_tail: &[u8], section: &[u8]) -> Vec<u8> {
1241 assert_eq!(pointer_field as usize, previous_tail.len());
1242 let mut v = Vec::with_capacity(1 + previous_tail.len() + section.len());
1243 v.push(pointer_field);
1244 v.extend_from_slice(previous_tail);
1245 v.extend_from_slice(section);
1246 v
1247 }
1248
1249 fn build_section(table_id: u8, body_after_length: &[u8]) -> Vec<u8> {
1253 let section_length = body_after_length.len() as u16;
1254 let mut v = Vec::with_capacity(3 + section_length as usize);
1255 v.push(table_id);
1256 v.push(0xB0 | ((section_length >> 8) as u8 & 0x0F));
1258 v.push((section_length & 0xFF) as u8);
1259 v.extend_from_slice(body_after_length);
1260 v
1261 }
1262
1263 #[test]
1269 fn reassembler_accumulates_multi_packet_section() {
1270 let body = vec![0xAAu8; 197];
1272 let section = build_section(0x02, &body);
1273 assert_eq!(section.len(), 200);
1274
1275 let first_chunk = 100;
1276 let payload1 = build_pusi_payload(0, &[], §ion[..first_chunk]);
1277 let payload2 = section[first_chunk..].to_vec();
1278
1279 let mut reasm = SectionReassembler::default();
1280 reasm.feed(&payload1, true);
1281 reasm.feed(&payload2, false);
1282
1283 let out = reasm.pop_section().expect("section should be ready");
1284 assert_eq!(out.len(), 200);
1285 assert_eq!(out.as_ref(), §ion[..]);
1286 }
1287
1288 #[test]
1289 fn reassembler_yields_complete_section_once_length_satisfied() {
1290 let section = build_section(0x42, &[0xAA]);
1292 assert_eq!(section.len(), 4);
1293 let payload = build_pusi_payload(0, &[], §ion);
1294
1295 let mut reasm = SectionReassembler::default();
1296 reasm.feed(&payload, true);
1297
1298 let out = reasm
1299 .pop_section()
1300 .expect("single-packet section should pop");
1301 assert_eq!(out.as_ref(), §ion[..]);
1302 }
1303
1304 #[test]
1305 fn reassembler_extracts_all_concatenated_sections_in_one_payload() {
1306 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();
1315 concat.extend_from_slice(&s1);
1316 concat.extend_from_slice(&s2);
1317 concat.extend_from_slice(&s3);
1318 let payload = build_pusi_payload(0, &[], &concat);
1319
1320 let mut reasm = SectionReassembler::default();
1321 reasm.feed(&payload, true);
1322
1323 let got: Vec<_> = core::iter::from_fn(|| reasm.pop_section()).collect();
1325 assert_eq!(got.len(), 3, "all three concatenated sections must pop");
1326 assert_eq!(got[0].as_ref(), &s1[..]);
1327 assert_eq!(got[1].as_ref(), &s2[..]);
1328 assert_eq!(got[2].as_ref(), &s3[..]);
1329 }
1330
1331 #[test]
1332 fn reassembler_stops_at_stuffing_after_concatenated_sections() {
1333 let s1 = build_section(0x42, &[0xAA]); let s2 = build_section(0x46, &[0xBB, 0xCC]); let mut concat = Vec::new();
1339 concat.extend_from_slice(&s1);
1340 concat.extend_from_slice(&s2);
1341 concat.extend_from_slice(&[0xFF, 0xFF, 0xFF, 0xFF]); let payload = build_pusi_payload(0, &[], &concat);
1343
1344 let mut reasm = SectionReassembler::default();
1345 reasm.feed(&payload, true);
1346
1347 let got: Vec<_> = core::iter::from_fn(|| reasm.pop_section()).collect();
1348 assert_eq!(got.len(), 2);
1349 assert_eq!(got[0].as_ref(), &s1[..]);
1350 assert_eq!(got[1].as_ref(), &s2[..]);
1351 assert!(
1352 reasm.is_empty(),
1353 "stuffing tail must be discarded, not buffered"
1354 );
1355 }
1356
1357 #[test]
1358 fn reassembler_concatenated_then_spanning_tail() {
1359 let s1 = build_section(0x42, &[0x01, 0x02]); let s2 = build_section(0x46, &[0x09u8; 60]); let split = 30;
1365
1366 let mut head = Vec::new();
1367 head.extend_from_slice(&s1);
1368 head.extend_from_slice(&s2[..split]);
1369 let payload1 = build_pusi_payload(0, &[], &head);
1370 let payload2 = s2[split..].to_vec();
1371
1372 let mut reasm = SectionReassembler::default();
1373 reasm.feed(&payload1, true);
1374 let first = reasm.pop_section().expect("first section pops at once");
1375 assert_eq!(first.as_ref(), &s1[..]);
1376 assert!(reasm.pop_section().is_none(), "second is still partial");
1377
1378 reasm.feed(&payload2, false);
1379 let second = reasm.pop_section().expect("second pops after continuation");
1380 assert_eq!(second.as_ref(), &s2[..]);
1381 }
1382
1383 #[test]
1384 fn reassembler_completes_section_spanning_into_pusi_packet() {
1385 let spanning = build_section(0x42, &[0x5Au8; 62]); let head = 41;
1393 let tail = &spanning[head..]; assert_eq!(tail.len(), 24);
1395
1396 let next = build_section(0x46, &[0x77, 0x88]); let payload_a = build_pusi_payload(0, &[], &spanning[..head]);
1401 let payload_b = build_pusi_payload(24, tail, &next);
1403
1404 let mut reasm = SectionReassembler::default();
1405 reasm.feed(&payload_a, true);
1406 assert!(reasm.pop_section().is_none(), "head alone is incomplete");
1407
1408 reasm.feed(&payload_b, true);
1409 let got: Vec<_> = core::iter::from_fn(|| reasm.pop_section()).collect();
1410 assert_eq!(got.len(), 2, "spanning section + new section must both pop");
1411 assert_eq!(
1412 got[0].as_ref(),
1413 &spanning[..],
1414 "spanning section completed from B's pointer tail"
1415 );
1416 assert_eq!(got[1].as_ref(), &next[..]);
1417 }
1418
1419 #[test]
1420 fn reassembler_pusi_pointer_spans_whole_payload() {
1421 let spanning = build_section(0x42, &[0x33u8; 40]); let head = 20;
1426 let payload_a = build_pusi_payload(0, &[], &spanning[..head]);
1427 let tail = &spanning[head..]; let mut reasm = SectionReassembler::default();
1430 reasm.feed(&payload_a, true);
1431 reasm.feed(&build_pusi_payload_pointer_spanning_all(tail), true);
1433
1434 let out = reasm.pop_section().expect("spanning section completes");
1435 assert_eq!(out.as_ref(), &spanning[..]);
1436 assert!(reasm.pop_section().is_none());
1437 }
1438
1439 fn build_pusi_payload_pointer_spanning_all(tail: &[u8]) -> Vec<u8> {
1442 let mut v = Vec::with_capacity(1 + tail.len());
1443 v.push(tail.len() as u8);
1444 v.extend_from_slice(tail);
1445 v
1446 }
1447
1448 #[test]
1449 fn reassembler_completes_max_length_section_and_stays_usable() {
1450 let mut section = Vec::with_capacity(MAX_SECTION_SIZE);
1456 section.push(0x00); section.push(0xB0 | ((4095u16 >> 8) as u8 & 0x0F));
1458 section.push(0xFF); section.resize(MAX_SECTION_SIZE, 0u8);
1460 assert_eq!(section.len(), MAX_SECTION_SIZE);
1461
1462 let mut reasm = SectionReassembler::default();
1463 let mut first = vec![0x00u8]; first.extend_from_slice(§ion[..183]);
1465 reasm.feed(&first, true);
1466 assert!(
1467 reasm.pop_section().is_none(),
1468 "incomplete until the declared length arrives"
1469 );
1470
1471 for chunk in section[183..].chunks(184) {
1472 reasm.feed(chunk, false);
1473 }
1474 let out = reasm
1475 .pop_section()
1476 .expect("max-length section completes at its declared length");
1477 assert_eq!(out.len(), MAX_SECTION_SIZE);
1478 assert_eq!(out.as_ref(), §ion[..]);
1479 assert!(reasm.is_empty());
1480
1481 reasm.feed(&[0u8; 184], false);
1485 assert!(reasm.pop_section().is_none());
1486
1487 let valid_section = build_section(0x00, &[0xAA]);
1489 let payload2 = build_pusi_payload(0, &[], &valid_section);
1490 reasm.feed(&payload2, true);
1491 let out = reasm
1492 .pop_section()
1493 .expect("fresh section should pop after reset");
1494 assert_eq!(out.as_ref(), &valid_section[..]);
1495 }
1496
1497 #[test]
1498 fn reassembler_handles_pusi_with_nonzero_pointer_field() {
1499 let prior_tail = vec![0x11, 0x22, 0x33];
1501 let new_section = build_section(0x02, &[0xBB]);
1502 assert_eq!(new_section.len(), 4);
1503 let payload = build_pusi_payload(3, &prior_tail, &new_section);
1504
1505 let mut reasm = SectionReassembler::default();
1506 reasm.feed(&payload, true);
1507
1508 let out = reasm
1509 .pop_section()
1510 .expect("section after pointer_field skip should pop");
1511 assert_eq!(out.as_ref(), &new_section[..]);
1512 }
1513
1514 #[test]
1515 fn reassembler_ignores_continuation_before_pusi() {
1516 let pkt = make_packet(0x00, 0x00, PAYLOAD_FLAG, &[0xAA, 0xBB, 0xCC]);
1519
1520 let mut reasm = SectionReassembler::default();
1521 reasm.feed(&pkt[4..], false); assert!(
1524 reasm.pop_section().is_none(),
1525 "no section should appear without prior PUSI"
1526 );
1527 assert!(
1528 reasm.pop_section().is_none(),
1529 "second pop should also be none"
1530 );
1531 }
1532
1533 #[test]
1536 fn reassembler_empty_pusi_payload_does_not_panic() {
1537 let mut reasm = SectionReassembler::default();
1538 reasm.feed(&[], true);
1539 assert!(reasm.pop_section().is_none());
1540 let payload = vec![0x00u8, 0x72, 0x70, 0x01, 0x00];
1542 reasm.feed(&payload, true);
1543 assert!(reasm.pop_section().is_some());
1544 }
1545
1546 #[test]
1550 fn reassembler_accepts_maximal_private_section() {
1551 let mut section = vec![0x80u8, 0x7F, 0xFF]; section.resize(3 + 0xFFF, 0xAB);
1553
1554 let mut reasm = SectionReassembler::default();
1555 let mut first = vec![0x00];
1557 first.extend_from_slice(§ion[..183]);
1558 reasm.feed(&first, true);
1559 for chunk in section[183..].chunks(184) {
1560 reasm.feed(chunk, false);
1561 }
1562 let out = reasm.pop_section().expect("4098-byte section should pop");
1563 assert_eq!(out.len(), 4098);
1564 assert_eq!(out.as_ref(), §ion[..]);
1565 }
1566
1567 #[test]
1572 fn reassembler_completes_large_section_with_trailing_stuffing() {
1573 let body = vec![0x5Au8; 4096 - 3];
1574 let section = build_section(0x50, &body); assert_eq!(section.len(), 4096);
1576
1577 let mut reasm = SectionReassembler::default();
1578 let mut first = vec![0x00u8];
1580 first.extend_from_slice(§ion[..183]);
1581 reasm.feed(&first, true);
1582
1583 let mut pos = 183usize;
1587 while pos < section.len() {
1588 let take = (section.len() - pos).min(184);
1589 let mut payload = section[pos..pos + take].to_vec();
1590 if take < 184 {
1591 payload.resize(184, 0xFF); }
1593 reasm.feed(&payload, false);
1594 pos += take;
1595 }
1596
1597 let out = reasm
1598 .pop_section()
1599 .expect("4096-byte section must complete despite trailing stuffing (#148)");
1600 assert_eq!(out.len(), 4096);
1601 assert_eq!(out.as_ref(), §ion[..]);
1602 assert!(reasm.is_empty(), "stuffing tail must be discarded");
1603 }
1604
1605 #[test]
1608 fn pcr_as_27mhz_known_value() {
1609 assert_eq!(
1610 Pcr {
1611 base: 10_000,
1612 extension: 0
1613 }
1614 .as_27mhz(),
1615 3_000_000
1616 );
1617 assert_eq!(
1619 Pcr {
1620 base: 1,
1621 extension: 100
1622 }
1623 .as_27mhz(),
1624 400
1625 );
1626 }
1627
1628 #[test]
1629 fn pcr_decode_from_bytes() {
1630 let af = [0x10u8, 0x00, 0x00, 0x13, 0x88, 0x7E, 0x00];
1632 let pcr = Pcr::parse(&af, 1).expect("6 bytes present");
1633 assert_eq!(
1634 pcr,
1635 Pcr {
1636 base: 10_000,
1637 extension: 0
1638 }
1639 );
1640 assert_eq!(pcr.as_27mhz(), 3_000_000);
1641 }
1642
1643 #[test]
1644 fn adaptation_field_flags_and_pcr() {
1645 let mut raw = [0xAAu8; TS_PACKET_SIZE];
1646 raw[0] = TS_SYNC_BYTE;
1647 raw[1] = 0x01; raw[2] = 0x00;
1649 raw[3] = ADAPTATION_FLAG | PAYLOAD_FLAG;
1650 raw[4] = 7; raw[5] = AF_DISCONTINUITY | AF_PCR_FLAG;
1652 raw[6..12].copy_from_slice(&[0x00, 0x00, 0x13, 0x88, 0x7E, 0x00]);
1653 let pkt = TsPacket::parse(&raw).expect("valid packet");
1656 let af = pkt
1657 .adaptation_field()
1658 .expect("has adaptation field")
1659 .expect("adaptation field parses");
1660 assert!(af.discontinuity_indicator);
1661 assert!(!af.random_access_indicator);
1662 assert_eq!(
1663 af.pcr,
1664 Some(Pcr {
1665 base: 10_000,
1666 extension: 0
1667 })
1668 );
1669 assert_eq!(af.pcr.unwrap().as_27mhz(), 3_000_000);
1670 assert!(af.opcr.is_none());
1671 assert!(af.splice_countdown.is_none());
1672 let payload = pkt.payload.expect("payload present");
1674 assert_eq!(payload.len(), TS_PACKET_SIZE - 12);
1675 assert_eq!(payload[0], 0xAA);
1676 }
1677
1678 #[test]
1679 fn no_adaptation_returns_none() {
1680 let mut raw = [0x00u8; TS_PACKET_SIZE];
1681 raw[0] = TS_SYNC_BYTE;
1682 raw[1] = 0x01;
1683 raw[3] = PAYLOAD_FLAG; let pkt = TsPacket::parse(&raw).expect("valid");
1685 assert!(pkt.adaptation_field().is_none());
1686 assert!(pkt.adaptation.is_none());
1687 }
1688
1689 #[test]
1690 fn adaptation_field_splice_countdown_negative() {
1691 let mut raw = [0xAAu8; TS_PACKET_SIZE];
1692 raw[0] = TS_SYNC_BYTE;
1693 raw[1] = 0x01;
1694 raw[2] = 0x00;
1695 raw[3] = ADAPTATION_FLAG | PAYLOAD_FLAG;
1696 raw[4] = 2; raw[5] = AF_SPLICING_FLAG;
1698 raw[6] = 0xFB; let pkt = TsPacket::parse(&raw).expect("valid");
1700 let af = pkt.adaptation_field().unwrap().unwrap();
1701 assert_eq!(af.splice_countdown, Some(-5));
1702 assert!(af.pcr.is_none());
1703 }
1704
1705 #[test]
1708 fn scrambling_control_all_values() {
1709 assert_eq!(
1710 ScramblingControl::from_bits(0b00),
1711 ScramblingControl::NotScrambled
1712 );
1713 assert_eq!(
1714 ScramblingControl::from_bits(0b01),
1715 ScramblingControl::Reserved
1716 );
1717 assert_eq!(
1718 ScramblingControl::from_bits(0b10),
1719 ScramblingControl::EvenKey
1720 );
1721 assert_eq!(
1722 ScramblingControl::from_bits(0b11),
1723 ScramblingControl::OddKey
1724 );
1725 assert_eq!(ScramblingControl::NotScrambled.name(), "not_scrambled");
1727 assert_eq!(ScramblingControl::Reserved.name(), "reserved");
1728 assert_eq!(ScramblingControl::EvenKey.name(), "even_key");
1729 assert_eq!(ScramblingControl::OddKey.name(), "odd_key");
1730 assert_eq!(ScramblingControl::NotScrambled.to_string(), "not_scrambled");
1732 assert_eq!(ScramblingControl::OddKey.to_string(), "odd_key");
1733 assert_eq!(
1735 ScramblingControl::from_bits(0xFF),
1736 ScramblingControl::OddKey
1737 );
1738 }
1739
1740 #[test]
1741 fn adaptation_field_control_all_values() {
1742 assert_eq!(
1743 AdaptationFieldControl::from_flags(false, false),
1744 AdaptationFieldControl::Reserved
1745 );
1746 assert_eq!(
1747 AdaptationFieldControl::from_flags(false, true),
1748 AdaptationFieldControl::PayloadOnly
1749 );
1750 assert_eq!(
1751 AdaptationFieldControl::from_flags(true, false),
1752 AdaptationFieldControl::AdaptationOnly
1753 );
1754 assert_eq!(
1755 AdaptationFieldControl::from_flags(true, true),
1756 AdaptationFieldControl::AdaptationAndPayload
1757 );
1758 assert_eq!(AdaptationFieldControl::Reserved.name(), "reserved");
1760 assert_eq!(AdaptationFieldControl::PayloadOnly.name(), "payload_only");
1761 assert_eq!(
1762 AdaptationFieldControl::AdaptationOnly.name(),
1763 "adaptation_only"
1764 );
1765 assert_eq!(
1766 AdaptationFieldControl::AdaptationAndPayload.name(),
1767 "adaptation_and_payload"
1768 );
1769 assert_eq!(
1771 AdaptationFieldControl::PayloadOnly.to_string(),
1772 "payload_only"
1773 );
1774 }
1775
1776 #[test]
1777 fn ts_header_scrambling_control_accessor() {
1778 let hdr = TsHeader {
1779 tei: false,
1780 pusi: false,
1781 pid: 0x0100,
1782 scrambling: 0b10,
1783 has_adaptation: false,
1784 has_payload: true,
1785 continuity_counter: 0,
1786 };
1787 assert_eq!(hdr.scrambling_control(), ScramblingControl::EvenKey);
1788 }
1789
1790 #[test]
1791 fn ts_header_adaptation_field_control_accessor() {
1792 let hdr_payload_only = TsHeader {
1793 tei: false,
1794 pusi: false,
1795 pid: 0x0100,
1796 scrambling: 0,
1797 has_adaptation: false,
1798 has_payload: true,
1799 continuity_counter: 0,
1800 };
1801 assert_eq!(
1802 hdr_payload_only.adaptation_field_control(),
1803 AdaptationFieldControl::PayloadOnly
1804 );
1805
1806 let hdr_both = TsHeader {
1807 tei: false,
1808 pusi: false,
1809 pid: 0x0100,
1810 scrambling: 0,
1811 has_adaptation: true,
1812 has_payload: true,
1813 continuity_counter: 0,
1814 };
1815 assert_eq!(
1816 hdr_both.adaptation_field_control(),
1817 AdaptationFieldControl::AdaptationAndPayload
1818 );
1819 }
1820
1821 #[test]
1824 fn iter_packets_yields_valid_and_skips_bad_sync() {
1825 let pkt1 = make_packet(0x00, 0x00, PAYLOAD_FLAG, &[0xAA; 10]);
1827 let pkt2 = make_packet(0x40, 0x64, PAYLOAD_FLAG, &[0xBB; 10]);
1828 let mut bad = [0u8; TS_PACKET_SIZE];
1829 bad[0] = 0x00; let mut buf = Vec::new();
1832 buf.extend_from_slice(&pkt1);
1833 buf.extend_from_slice(&pkt2);
1834 buf.extend_from_slice(&bad);
1835
1836 let pkts: Vec<_> = super::iter_packets(&buf).collect();
1837 assert_eq!(pkts.len(), 2, "bad sync packet must be skipped");
1838 assert_eq!(pkts[0].header.pid, 0x0000);
1839 assert_eq!(pkts[1].header.pid, 0x0064);
1840 }
1841
1842 #[test]
1843 fn extract_ts_payload_payload_only() {
1844 let pkt = make_packet(0x00, 0x00, PAYLOAD_FLAG, &[0xABu8; 10]);
1845 let p = super::extract_ts_payload(&pkt).expect("payload present");
1846 assert_eq!(p[0], 0xAB);
1847 assert_eq!(p.len(), TS_PACKET_SIZE - 4);
1848 }
1849
1850 #[test]
1851 fn extract_ts_payload_adaptation_only_returns_none() {
1852 let pkt = make_packet(0x00, 0x00, ADAPTATION_FLAG, &[]);
1853 assert!(super::extract_ts_payload(&pkt).is_none());
1854 }
1855
1856 #[test]
1861 fn pcr_from_27mhz_round_trips() {
1862 for &ticks in &[0u64, 1, 300, 27_000_000, u64::from(u32::MAX), 8_589_934_591] {
1863 let pcr = Pcr::from_27mhz(ticks);
1864 assert_eq!(pcr.as_27mhz(), ticks, "ticks={ticks}");
1865 }
1866 }
1867
1868 #[test]
1870 fn pcr_to_field_bytes_round_trips_parse() {
1871 let cases = [
1872 Pcr {
1873 base: 0,
1874 extension: 0,
1875 },
1876 Pcr {
1877 base: 10_000,
1878 extension: 0,
1879 },
1880 Pcr {
1881 base: 1,
1882 extension: 100,
1883 },
1884 Pcr {
1885 base: 0x1_FFFF_FFFF,
1886 extension: 0x1FF,
1887 },
1888 ];
1889 for pcr in cases {
1890 let bytes = pcr.to_field_bytes();
1891 let mut af = [0u8; 7];
1894 af[1..7].copy_from_slice(&bytes);
1895 let decoded = Pcr::parse(&af, 1).expect("parse round-trip");
1896 assert_eq!(decoded, pcr, "round-trip failed for {pcr:?}");
1897 }
1898 }
1899
1900 #[test]
1903 fn pcr_to_field_bytes_known_vector() {
1904 let pcr = Pcr {
1905 base: 10_000,
1906 extension: 0,
1907 };
1908 let bytes = pcr.to_field_bytes();
1909 assert_eq!(bytes, [0x00, 0x00, 0x13, 0x88, 0x7E, 0x00]);
1910 }
1911
1912 #[test]
1915 fn scrambling_control_to_bits_inverse_of_from_bits() {
1916 for bits in 0u8..=3 {
1917 let sc = ScramblingControl::from_bits(bits);
1918 assert_eq!(sc.to_bits(), bits, "to_bits() != from_bits() for {bits}");
1919 }
1920 }
1921
1922 #[test]
1925 fn adaptation_field_control_to_bits_inverse_of_from_flags() {
1926 let cases = [
1927 (false, false, 0b00u8),
1928 (false, true, 0b01),
1929 (true, false, 0b10),
1930 (true, true, 0b11),
1931 ];
1932 for (has_af, has_pl, expected_bits) in cases {
1933 let afc = AdaptationFieldControl::from_flags(has_af, has_pl);
1934 assert_eq!(afc.to_bits(), expected_bits);
1935 assert_eq!(afc.to_flags(), (has_af, has_pl));
1936 }
1937 }
1938
1939 #[test]
1943 fn adaptation_field_serialize_round_trip_with_pcr() {
1944 let original = AdaptationField {
1945 discontinuity_indicator: true,
1946 random_access_indicator: false,
1947 elementary_stream_priority_indicator: false,
1948 pcr: Some(Pcr {
1949 base: 10_000,
1950 extension: 0,
1951 }),
1952 opcr: None,
1953 splice_countdown: None,
1954 transport_private_data: None,
1955 extension: None,
1956 stuffing_len: 0,
1957 };
1958 let len = original.serialized_len();
1959 assert_eq!(len, 7); let mut buf = vec![0u8; len];
1961 let written = original.serialize_into(&mut buf).expect("serialize");
1962 assert_eq!(written, len);
1963 let decoded = AdaptationField::parse(&buf).expect("parse round-trip");
1964 assert_eq!(decoded, original);
1965 }
1966
1967 #[test]
1969 fn adaptation_field_serialize_produces_known_bytes() {
1970 let af = AdaptationField {
1974 discontinuity_indicator: true,
1975 random_access_indicator: false,
1976 elementary_stream_priority_indicator: false,
1977 pcr: Some(Pcr {
1978 base: 10_000,
1979 extension: 0,
1980 }),
1981 opcr: None,
1982 splice_countdown: None,
1983 transport_private_data: None,
1984 extension: None,
1985 stuffing_len: 0,
1986 };
1987 let mut buf = [0u8; 7];
1988 af.serialize_into(&mut buf).unwrap();
1989 assert_eq!(buf[0], AF_DISCONTINUITY | AF_PCR_FLAG);
1990 assert_eq!(&buf[1..7], &[0x00, 0x00, 0x13, 0x88, 0x7E, 0x00]);
1991 }
1992
1993 #[test]
1995 fn adaptation_field_serialize_round_trip_opcr_and_splice() {
1996 let original = AdaptationField {
1997 discontinuity_indicator: false,
1998 random_access_indicator: true,
1999 elementary_stream_priority_indicator: true,
2000 pcr: Some(Pcr {
2001 base: 1,
2002 extension: 100,
2003 }),
2004 opcr: Some(Pcr {
2005 base: 999,
2006 extension: 5,
2007 }),
2008 splice_countdown: Some(-3),
2009 transport_private_data: None,
2010 extension: None,
2011 stuffing_len: 0,
2012 };
2013 let len = original.serialized_len();
2014 assert_eq!(len, 1 + 6 + 6 + 1); let mut buf = vec![0u8; len];
2016 original.serialize_into(&mut buf).unwrap();
2017 let decoded = AdaptationField::parse(&buf).expect("parse");
2018 assert_eq!(decoded, original);
2019 }
2020
2021 #[test]
2023 fn adaptation_field_serialize_flags_only() {
2024 let af = AdaptationField {
2025 discontinuity_indicator: false,
2026 random_access_indicator: true,
2027 elementary_stream_priority_indicator: false,
2028 pcr: None,
2029 opcr: None,
2030 splice_countdown: None,
2031 transport_private_data: None,
2032 extension: None,
2033 stuffing_len: 0,
2034 };
2035 assert_eq!(af.serialized_len(), 1);
2036 let mut buf = [0u8; 1];
2037 af.serialize_into(&mut buf).unwrap();
2038 assert_eq!(buf[0], AF_RANDOM_ACCESS);
2039 let decoded = AdaptationField::parse(&buf).unwrap();
2040 assert_eq!(decoded, af);
2041 }
2042
2043 #[test]
2045 fn adaptation_field_serialize_rejects_small_buffer() {
2046 let af = AdaptationField {
2047 discontinuity_indicator: false,
2048 random_access_indicator: false,
2049 elementary_stream_priority_indicator: false,
2050 pcr: Some(Pcr {
2051 base: 0,
2052 extension: 0,
2053 }),
2054 opcr: None,
2055 splice_countdown: None,
2056 transport_private_data: None,
2057 extension: None,
2058 stuffing_len: 0,
2059 };
2060 let mut buf = [0u8; 3]; assert!(matches!(
2062 af.serialize_into(&mut buf),
2063 Err(Error::OutputBufferTooSmall { .. })
2064 ));
2065 }
2066
2067 #[test]
2071 fn adaptation_field_extension_ltw_round_trip() {
2072 let ext = AdaptationFieldExtension {
2073 ltw: Some(Ltw {
2074 ltw_valid_flag: true,
2075 ltw_offset: 0x1234,
2076 }),
2077 piecewise_rate: None,
2078 seamless_splice: None,
2079 };
2080 let mut buf = vec![0u8; ext.serialized_len()];
2081 ext.serialize_into(&mut buf).unwrap();
2082 let af = AdaptationField {
2085 discontinuity_indicator: false,
2086 random_access_indicator: false,
2087 elementary_stream_priority_indicator: false,
2088 pcr: None,
2089 opcr: None,
2090 splice_countdown: None,
2091 transport_private_data: None,
2092 extension: Some(ext),
2093 stuffing_len: 0,
2094 };
2095 let len = af.serialized_len();
2096 let mut abuf = vec![0u8; len];
2097 af.serialize_into(&mut abuf).unwrap();
2098 let decoded = AdaptationField::parse(&abuf).unwrap();
2099 assert_eq!(decoded.extension, Some(ext));
2100 }
2101
2102 #[test]
2104 fn adaptation_field_extension_piecewise_rate_round_trip() {
2105 let af = AdaptationField {
2106 discontinuity_indicator: false,
2107 random_access_indicator: false,
2108 elementary_stream_priority_indicator: false,
2109 pcr: None,
2110 opcr: None,
2111 splice_countdown: None,
2112 transport_private_data: None,
2113 extension: Some(AdaptationFieldExtension {
2114 ltw: None,
2115 piecewise_rate: Some(0x3FFFFF), seamless_splice: None,
2117 }),
2118 stuffing_len: 0,
2119 };
2120 let mut buf = vec![0u8; af.serialized_len()];
2121 af.serialize_into(&mut buf).unwrap();
2122 let decoded = AdaptationField::parse(&buf).unwrap();
2123 assert_eq!(decoded.extension.unwrap().piecewise_rate, Some(0x3FFFFF));
2124 }
2125
2126 #[test]
2128 fn adaptation_field_extension_seamless_splice_round_trip() {
2129 let af = AdaptationField {
2130 discontinuity_indicator: false,
2131 random_access_indicator: false,
2132 elementary_stream_priority_indicator: false,
2133 pcr: None,
2134 opcr: None,
2135 splice_countdown: None,
2136 transport_private_data: None,
2137 extension: Some(AdaptationFieldExtension {
2138 ltw: None,
2139 piecewise_rate: None,
2140 seamless_splice: Some(SeamlessSplice {
2141 splice_type: 0xA,
2142 dts_next_au: 0x1_2345_6789,
2143 }),
2144 }),
2145 stuffing_len: 0,
2146 };
2147 let mut buf = vec![0u8; af.serialized_len()];
2148 af.serialize_into(&mut buf).unwrap();
2149 let decoded = AdaptationField::parse(&buf).unwrap();
2150 let ss = decoded.extension.unwrap().seamless_splice.unwrap();
2151 assert_eq!(ss.splice_type, 0xA);
2152 assert_eq!(ss.dts_next_au, 0x1_2345_6789);
2153 }
2154
2155 #[test]
2157 fn adaptation_field_transport_private_data_round_trip() {
2158 let tpd = [0xDE, 0xAD, 0xBE, 0xEF];
2159 let af = AdaptationField {
2160 discontinuity_indicator: false,
2161 random_access_indicator: false,
2162 elementary_stream_priority_indicator: false,
2163 pcr: None,
2164 opcr: None,
2165 splice_countdown: None,
2166 transport_private_data: Some(&tpd),
2167 extension: None,
2168 stuffing_len: 0,
2169 };
2170 let mut buf = vec![0u8; af.serialized_len()];
2171 af.serialize_into(&mut buf).unwrap();
2172 let decoded = AdaptationField::parse(&buf).unwrap();
2173 assert_eq!(decoded.transport_private_data, Some(tpd.as_slice()));
2174 }
2175
2176 #[test]
2179 fn adaptation_field_stuffing_round_trip() {
2180 let af = AdaptationField {
2181 discontinuity_indicator: false,
2182 random_access_indicator: false,
2183 elementary_stream_priority_indicator: false,
2184 pcr: Some(Pcr {
2185 base: 12_345,
2186 extension: 7,
2187 }),
2188 opcr: None,
2189 splice_countdown: None,
2190 transport_private_data: None,
2191 extension: None,
2192 stuffing_len: 20,
2193 };
2194 assert_eq!(af.serialized_len(), 27);
2196 let mut buf = vec![0u8; af.serialized_len()];
2197 af.serialize_into(&mut buf).unwrap();
2198 assert!(buf[7..27].iter().all(|&b| b == AF_STUFFING_BYTE));
2200 let decoded = AdaptationField::parse(&buf).unwrap();
2201 assert_eq!(decoded.stuffing_len, 20);
2202 assert_eq!(decoded, af);
2203 let pure = AdaptationField {
2205 discontinuity_indicator: false,
2206 random_access_indicator: false,
2207 elementary_stream_priority_indicator: false,
2208 pcr: None,
2209 opcr: None,
2210 splice_countdown: None,
2211 transport_private_data: None,
2212 extension: None,
2213 stuffing_len: 5,
2214 };
2215 let mut pbuf = vec![0u8; pure.serialized_len()];
2216 pure.serialize_into(&mut pbuf).unwrap();
2217 assert_eq!(pbuf, vec![0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]);
2218 assert_eq!(AdaptationField::parse(&pbuf).unwrap(), pure);
2219 }
2220
2221 #[test]
2223 fn adaptation_field_all_fields_round_trip() {
2224 let tpd = [0x01u8, 0x02, 0x03];
2225 let af = AdaptationField {
2226 discontinuity_indicator: true,
2227 random_access_indicator: false,
2228 elementary_stream_priority_indicator: false,
2229 pcr: Some(Pcr {
2230 base: 90_000,
2231 extension: 50,
2232 }),
2233 opcr: None,
2234 splice_countdown: Some(10),
2235 transport_private_data: Some(&tpd),
2236 extension: Some(AdaptationFieldExtension {
2237 ltw: Some(Ltw {
2238 ltw_valid_flag: false,
2239 ltw_offset: 500,
2240 }),
2241 piecewise_rate: Some(12345),
2242 seamless_splice: None,
2243 }),
2244 stuffing_len: 0,
2245 };
2246 let len = af.serialized_len();
2247 let mut buf = vec![0u8; len];
2248 af.serialize_into(&mut buf).unwrap();
2249 let decoded = AdaptationField::parse(&buf).unwrap();
2250 assert_eq!(decoded.pcr, af.pcr);
2251 assert_eq!(decoded.splice_countdown, af.splice_countdown);
2252 assert_eq!(decoded.transport_private_data, af.transport_private_data);
2253 assert_eq!(decoded.extension, af.extension);
2254 assert!(decoded.discontinuity_indicator);
2255 }
2256
2257 #[test]
2260 fn adaptation_field_serialize_from_real_packet_bytes() {
2261 let mut raw = [0xAAu8; TS_PACKET_SIZE];
2263 raw[0] = TS_SYNC_BYTE;
2264 raw[1] = 0x01;
2265 raw[2] = 0x00;
2266 raw[3] = ADAPTATION_FLAG | PAYLOAD_FLAG;
2267 raw[4] = 7;
2268 raw[5] = AF_DISCONTINUITY | AF_PCR_FLAG;
2269 raw[6..12].copy_from_slice(&[0x00, 0x00, 0x13, 0x88, 0x7E, 0x00]);
2270
2271 let pkt = TsPacket::parse(&raw).unwrap();
2272 let af = pkt.adaptation_field().unwrap().unwrap();
2273
2274 let mut ser = vec![0u8; af.serialized_len()];
2276 af.serialize_into(&mut ser).unwrap();
2277 let decoded = AdaptationField::parse(&ser).unwrap();
2278 assert_eq!(
2279 decoded.pcr,
2280 Some(Pcr {
2281 base: 10_000,
2282 extension: 0
2283 })
2284 );
2285 assert!(decoded.discontinuity_indicator);
2286 }
2287}