1use crate::PACKET_START_CODE_PREFIX;
4use crate::error::{Error, Result};
5use crate::stream_id::StreamId;
6use crate::timestamp::{self, Dts, Pts};
7
8const MIN_LEN: usize = 6; const HEADER_FIXED: usize = 3; const PES_HEADER_STUFFING_BYTE: u8 = 0xFF;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize))]
23pub struct Escr {
24 pub base: u64,
26 pub extension: u16,
28}
29
30impl Escr {
31 #[must_use]
33 pub fn as_27mhz(self) -> u64 {
34 self.base * 300 + self.extension as u64
35 }
36
37 #[must_use]
39 pub fn from_27mhz(ticks: u64) -> Self {
40 const BASE_MASK: u64 = 0x1_FFFF_FFFF;
41 const EXT_MASK: u16 = 0x1FF;
42 Self {
43 base: (ticks / 300) & BASE_MASK,
44 extension: ((ticks % 300) as u16) & EXT_MASK,
45 }
46 }
47
48 pub fn from_field_bytes(b: &[u8; 6]) -> Result<Self> {
58 let base = ((((b[0] >> 3) & 0x07) as u64) << 30) | (((b[0] & 0x03) as u64) << 28) | ((b[1] as u64) << 20) | ((((b[2] >> 3) & 0x1F) as u64) << 15) | (((b[2] & 0x03) as u64) << 13) | ((b[3] as u64) << 5) | (((b[4] >> 3) & 0x1F) as u64); let extension = ((((b[4] & 0x03) as u16) << 7) | ((b[5] >> 1) as u16)) & 0x1FF;
66 Ok(Self { base, extension })
67 }
68
69 #[must_use]
74 pub fn to_field_bytes(self) -> [u8; 6] {
75 let b = self.base & 0x1_FFFF_FFFF;
76 let e = (self.extension & 0x1FF) as u64;
77 [
78 0xC0 | (((b >> 30) & 0x07) as u8) << 3 | 0x04 | ((b >> 28) & 0x03) as u8,
80 ((b >> 20) & 0xFF) as u8,
82 (((b >> 15) & 0x1F) as u8) << 3 | 0x04 | ((b >> 13) & 0x03) as u8,
84 ((b >> 5) & 0xFF) as u8,
86 (((b & 0x1F) as u8) << 3) | 0x04 | ((e >> 7) & 0x03) as u8,
88 (((e & 0x7F) as u8) << 1) | 0x01,
90 ]
91 }
92}
93
94#[derive(Debug, Clone, Copy, PartialEq, Eq)]
99#[cfg_attr(feature = "serde", derive(serde::Serialize))]
100pub enum TrickMode {
101 FastForward {
103 field_id: u8,
105 intra_slice_refresh: bool,
107 frequency_truncation: u8,
109 },
110 SlowMotion {
112 rep_cntrl: u8,
114 },
115 FreezeFrame {
117 field_id: u8,
119 },
120 FastReverse {
122 field_id: u8,
124 intra_slice_refresh: bool,
126 frequency_truncation: u8,
128 },
129 SlowReverse {
131 rep_cntrl: u8,
133 },
134 Reserved {
136 trick_mode_control: u8,
138 data: u8,
140 },
141}
142
143impl TrickMode {
144 pub fn from_byte(b: u8) -> Self {
146 let control = (b >> 5) & 0x07;
147 let data = b & 0x1F;
148 match control {
149 0b000 => TrickMode::FastForward {
150 field_id: (data >> 3) & 0x03,
151 intra_slice_refresh: (data >> 2) & 0x01 != 0,
152 frequency_truncation: data & 0x03,
153 },
154 0b001 => TrickMode::SlowMotion { rep_cntrl: data },
155 0b010 => TrickMode::FreezeFrame {
156 field_id: (data >> 3) & 0x03,
157 },
158 0b011 => TrickMode::FastReverse {
159 field_id: (data >> 3) & 0x03,
160 intra_slice_refresh: (data >> 2) & 0x01 != 0,
161 frequency_truncation: data & 0x03,
162 },
163 0b100 => TrickMode::SlowReverse { rep_cntrl: data },
164 _ => TrickMode::Reserved {
165 trick_mode_control: control,
166 data,
167 },
168 }
169 }
170
171 pub fn to_byte(self) -> u8 {
173 match self {
174 TrickMode::FastForward {
175 field_id,
176 intra_slice_refresh,
177 frequency_truncation,
178 } => {
179 ((field_id & 0x03) << 3)
180 | ((intra_slice_refresh as u8) << 2)
181 | (frequency_truncation & 0x03)
182 }
183 TrickMode::SlowMotion { rep_cntrl } => (0b001 << 5) | (rep_cntrl & 0x1F),
184 TrickMode::FreezeFrame { field_id } => (0b010 << 5) | ((field_id & 0x03) << 3),
185 TrickMode::FastReverse {
186 field_id,
187 intra_slice_refresh,
188 frequency_truncation,
189 } => {
190 (0b011 << 5)
191 | ((field_id & 0x03) << 3)
192 | ((intra_slice_refresh as u8) << 2)
193 | (frequency_truncation & 0x03)
194 }
195 TrickMode::SlowReverse { rep_cntrl } => (0b100 << 5) | (rep_cntrl & 0x1F),
196 TrickMode::Reserved {
197 trick_mode_control,
198 data,
199 } => ((trick_mode_control & 0x07) << 5) | (data & 0x1F),
200 }
201 }
202}
203
204#[derive(Debug, Clone, Copy, PartialEq, Eq)]
208#[cfg_attr(feature = "serde", derive(serde::Serialize))]
209pub struct ProgramPacketSequenceCounter {
210 pub counter: u8,
212 pub mpeg1_mpeg2_identifier: bool,
214 pub original_stuff_length: u8,
216}
217
218#[derive(Debug, Clone, Copy, PartialEq, Eq)]
220#[cfg_attr(feature = "serde", derive(serde::Serialize))]
221pub struct PStdBuffer {
222 pub scale: bool,
224 pub size: u16,
226}
227
228#[derive(Debug, Clone, PartialEq, Eq)]
231#[cfg_attr(feature = "serde", derive(serde::Serialize))]
232pub struct PesExtension<'a> {
233 pub pes_private_data: Option<[u8; 16]>,
235 pub pack_header: Option<&'a [u8]>,
237 pub program_packet_sequence_counter: Option<ProgramPacketSequenceCounter>,
239 pub p_std_buffer: Option<PStdBuffer>,
241 pub pes_extension_field: Option<&'a [u8]>,
243}
244
245impl<'a> PesExtension<'a> {
246 fn parse(data: &'a [u8]) -> Result<Self> {
247 if data.is_empty() {
248 return Err(Error::BufferTooShort {
249 need: 1,
250 have: 0,
251 what: "PES_extension flags byte",
252 });
253 }
254 let flags = data[0];
255 let mut cursor = 1usize;
256
257 let pes_private_data = if flags & 0x80 != 0 {
258 let end = cursor + 16;
259 let arr: [u8; 16] = data
260 .get(cursor..end)
261 .and_then(|s| s.try_into().ok())
262 .ok_or(Error::BufferTooShort {
263 need: end,
264 have: data.len(),
265 what: "PES_private_data",
266 })?;
267 cursor = end;
268 Some(arr)
269 } else {
270 None
271 };
272
273 let pack_header = if flags & 0x40 != 0 {
274 let pack_len = *data.get(cursor).ok_or(Error::BufferTooShort {
275 need: cursor + 1,
276 have: data.len(),
277 what: "pack_field_length",
278 })? as usize;
279 cursor += 1;
280 let end = cursor + pack_len;
281 let slice = data.get(cursor..end).ok_or(Error::BufferTooShort {
282 need: end,
283 have: data.len(),
284 what: "pack_header",
285 })?;
286 cursor = end;
287 Some(slice)
288 } else {
289 None
290 };
291
292 let program_packet_sequence_counter = if flags & 0x20 != 0 {
293 if data.len() < cursor + 2 {
294 return Err(Error::BufferTooShort {
295 need: cursor + 2,
296 have: data.len(),
297 what: "program_packet_sequence_counter",
298 });
299 }
300 let b0 = data[cursor];
301 let b1 = data[cursor + 1];
302 cursor += 2;
303 Some(ProgramPacketSequenceCounter {
304 counter: b0 & 0x7F,
305 mpeg1_mpeg2_identifier: (b1 & 0x40) != 0,
306 original_stuff_length: b1 & 0x3F,
307 })
308 } else {
309 None
310 };
311
312 let p_std_buffer = if flags & 0x10 != 0 {
313 if data.len() < cursor + 2 {
314 return Err(Error::BufferTooShort {
315 need: cursor + 2,
316 have: data.len(),
317 what: "P-STD_buffer",
318 });
319 }
320 let b0 = data[cursor];
321 let b1 = data[cursor + 1];
322 cursor += 2;
323 Some(PStdBuffer {
324 scale: (b0 & 0x20) != 0,
325 size: (((b0 & 0x1F) as u16) << 8) | (b1 as u16),
326 })
327 } else {
328 None
329 };
330
331 let pes_extension_field = if flags & 0x01 != 0 {
332 let ext_len = *data.get(cursor).ok_or(Error::BufferTooShort {
333 need: cursor + 1,
334 have: data.len(),
335 what: "PES_extension_field_length",
336 })? as usize;
337 cursor += 1;
338 let end = cursor + ext_len;
339 let slice = data.get(cursor..end).ok_or(Error::BufferTooShort {
340 need: end,
341 have: data.len(),
342 what: "PES_extension_field",
343 })?;
344 cursor = end;
345 Some(slice)
346 } else {
347 None
348 };
349 let _ = cursor;
350
351 Ok(PesExtension {
352 pes_private_data,
353 pack_header,
354 program_packet_sequence_counter,
355 p_std_buffer,
356 pes_extension_field,
357 })
358 }
359
360 pub fn serialized_len(&self) -> usize {
362 let mut n = 1usize; if self.pes_private_data.is_some() {
364 n += 16;
365 }
366 if let Some(ph) = self.pack_header {
367 n += 1 + ph.len();
368 }
369 if self.program_packet_sequence_counter.is_some() {
370 n += 2;
371 }
372 if self.p_std_buffer.is_some() {
373 n += 2;
374 }
375 if let Some(ef) = self.pes_extension_field {
376 n += 1 + ef.len();
377 }
378 n
379 }
380
381 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
382 let need = self.serialized_len();
383 if buf.len() < need {
384 return Err(Error::BufferTooShort {
385 need,
386 have: buf.len(),
387 what: "PES_extension serialize output",
388 });
389 }
390
391 let mut flags = 0u8;
392 if self.pes_private_data.is_some() {
393 flags |= 0x80;
394 }
395 if self.pack_header.is_some() {
396 flags |= 0x40;
397 }
398 if self.program_packet_sequence_counter.is_some() {
399 flags |= 0x20;
400 }
401 if self.p_std_buffer.is_some() {
402 flags |= 0x10;
403 }
404 if self.pes_extension_field.is_some() {
405 flags |= 0x01;
406 }
407 buf[0] = flags;
408 let mut cursor = 1usize;
409
410 if let Some(pd) = &self.pes_private_data {
411 buf[cursor..cursor + 16].copy_from_slice(pd);
412 cursor += 16;
413 }
414 if let Some(ph) = self.pack_header {
415 buf[cursor] = ph.len() as u8;
416 cursor += 1;
417 buf[cursor..cursor + ph.len()].copy_from_slice(ph);
418 cursor += ph.len();
419 }
420 if let Some(ppsc) = self.program_packet_sequence_counter {
421 buf[cursor] = 0x80 | (ppsc.counter & 0x7F);
423 buf[cursor + 1] = 0x80
425 | ((ppsc.mpeg1_mpeg2_identifier as u8) << 6)
426 | (ppsc.original_stuff_length & 0x3F);
427 cursor += 2;
428 }
429 if let Some(ps) = self.p_std_buffer {
430 buf[cursor] = 0x40 | ((ps.scale as u8) << 5) | ((ps.size >> 8) as u8 & 0x1F);
432 buf[cursor + 1] = (ps.size & 0xFF) as u8;
433 cursor += 2;
434 }
435 if let Some(ef) = self.pes_extension_field {
436 buf[cursor] = ef.len() as u8;
437 cursor += 1;
438 buf[cursor..cursor + ef.len()].copy_from_slice(ef);
439 cursor += ef.len();
440 }
441 Ok(cursor)
442 }
443}
444
445#[non_exhaustive]
452#[derive(Debug, Clone, PartialEq, Eq)]
453#[cfg_attr(feature = "serde", derive(serde::Serialize))]
454pub struct PesHeader<'a> {
455 pub scrambling_control: u8,
457 pub pes_priority: bool,
459 pub data_alignment_indicator: bool,
461 pub copyright: bool,
463 pub original_or_copy: bool,
465 pub pts: Option<Pts>,
467 pub dts: Option<Dts>,
469 pub escr: Option<Escr>,
471 pub es_rate: Option<u32>,
473 pub dsm_trick_mode: Option<TrickMode>,
475 pub additional_copy_info: Option<u8>,
477 pub pes_crc: Option<u16>,
479 pub pes_extension: Option<PesExtension<'a>>,
481 pub header_stuffing_len: usize,
491}
492
493impl PesHeader<'_> {
494 fn optional_len(&self) -> usize {
497 let mut n = 0usize;
498 if self.pts.is_some() {
499 n += 5;
500 }
501 if self.dts.is_some() {
502 n += 5;
503 }
504 if self.escr.is_some() {
505 n += 6;
506 }
507 if self.es_rate.is_some() {
508 n += 3;
509 }
510 if self.dsm_trick_mode.is_some() {
511 n += 1;
512 }
513 if self.additional_copy_info.is_some() {
514 n += 1;
515 }
516 if self.pes_crc.is_some() {
517 n += 2;
518 }
519 if let Some(ref ext) = self.pes_extension {
520 n += ext.serialized_len();
521 }
522 n += self.header_stuffing_len;
523 n
524 }
525}
526
527#[derive(Debug, Clone, PartialEq, Eq)]
529#[cfg_attr(feature = "serde", derive(serde::Serialize))]
530pub struct PesPacket<'a> {
531 pub stream_id: StreamId,
533 pub pes_packet_length: u16,
535 pub header: Option<PesHeader<'a>>,
537 #[cfg_attr(feature = "serde", serde(skip))]
539 pub payload: &'a [u8],
540}
541
542impl<'a> PesPacket<'a> {
543 pub fn parse(b: &'a [u8]) -> Result<Self> {
545 if b.len() < MIN_LEN {
546 return Err(Error::BufferTooShort {
547 need: MIN_LEN,
548 have: b.len(),
549 what: "PES packet header",
550 });
551 }
552 if b[0..3] != PACKET_START_CODE_PREFIX {
553 return Err(Error::BadStartCode(
554 (u32::from(b[0]) << 16) | (u32::from(b[1]) << 8) | u32::from(b[2]),
555 ));
556 }
557 let stream_id = StreamId(b[3]);
558 let pes_packet_length = u16::from_be_bytes([b[4], b[5]]);
559 let payload_end = if pes_packet_length == 0 {
561 b.len()
562 } else {
563 (MIN_LEN + pes_packet_length as usize).min(b.len())
564 };
565
566 if !stream_id.has_optional_header() {
567 return Ok(PesPacket {
568 stream_id,
569 pes_packet_length,
570 header: None,
571 payload: &b[MIN_LEN..payload_end],
572 });
573 }
574
575 if b.len() < MIN_LEN + HEADER_FIXED {
576 return Err(Error::BufferTooShort {
577 need: MIN_LEN + HEADER_FIXED,
578 have: b.len(),
579 what: "PES optional header",
580 });
581 }
582 let f1 = b[6];
583 let f2 = b[7];
584 let hdl = usize::from(b[8]);
585 let hdr_start = MIN_LEN + HEADER_FIXED; let hdr_end = hdr_start + hdl;
587 if b.len() < hdr_end {
588 return Err(Error::BufferTooShort {
589 need: hdr_end,
590 have: b.len(),
591 what: "PES_header_data_length",
592 });
593 }
594 let opt = &b[hdr_start..hdr_end];
595 let mut cursor = 0usize;
596
597 let pts_dts_flags = (f2 >> 6) & 0x03;
599 let (pts, dts) = match pts_dts_flags {
600 0b10 => {
601 if opt.len() < cursor + 5 {
602 return Err(Error::BufferTooShort {
603 need: cursor + 5,
604 have: opt.len(),
605 what: "PTS",
606 });
607 }
608 let pts = Pts(timestamp::read(&opt[cursor..], 0b0010, "PTS")?);
609 cursor += 5;
610 (Some(pts), None)
611 }
612 0b11 => {
613 if opt.len() < cursor + 10 {
614 return Err(Error::BufferTooShort {
615 need: cursor + 10,
616 have: opt.len(),
617 what: "PTS+DTS",
618 });
619 }
620 let pts = Pts(timestamp::read(&opt[cursor..], 0b0011, "PTS")?);
621 cursor += 5;
622 let dts = Dts(timestamp::read(&opt[cursor..], 0b0001, "DTS")?);
623 cursor += 5;
624 (Some(pts), Some(dts))
625 }
626 _ => (None, None),
627 };
628
629 let escr = if f2 & 0x20 != 0 {
631 if opt.len() < cursor + 6 {
632 return Err(Error::BufferTooShort {
633 need: cursor + 6,
634 have: opt.len(),
635 what: "ESCR",
636 });
637 }
638 let arr: &[u8; 6] = opt[cursor..cursor + 6].try_into().unwrap();
639 let e = Escr::from_field_bytes(arr)?;
640 cursor += 6;
641 Some(e)
642 } else {
643 None
644 };
645
646 let es_rate = if f2 & 0x10 != 0 {
648 if opt.len() < cursor + 3 {
649 return Err(Error::BufferTooShort {
650 need: cursor + 3,
651 have: opt.len(),
652 what: "ES_rate",
653 });
654 }
655 let rate = (((opt[cursor] & 0x7F) as u32) << 15)
656 | ((opt[cursor + 1] as u32) << 7)
657 | ((opt[cursor + 2] >> 1) as u32);
658 cursor += 3;
659 Some(rate)
660 } else {
661 None
662 };
663
664 let dsm_trick_mode = if f2 & 0x08 != 0 {
666 if opt.len() < cursor + 1 {
667 return Err(Error::BufferTooShort {
668 need: cursor + 1,
669 have: opt.len(),
670 what: "trick_mode",
671 });
672 }
673 let tm = TrickMode::from_byte(opt[cursor]);
674 cursor += 1;
675 Some(tm)
676 } else {
677 None
678 };
679
680 let additional_copy_info = if f2 & 0x04 != 0 {
682 if opt.len() < cursor + 1 {
683 return Err(Error::BufferTooShort {
684 need: cursor + 1,
685 have: opt.len(),
686 what: "additional_copy_info",
687 });
688 }
689 let v = opt[cursor] & 0x7F;
690 cursor += 1;
691 Some(v)
692 } else {
693 None
694 };
695
696 let pes_crc = if f2 & 0x02 != 0 {
698 if opt.len() < cursor + 2 {
699 return Err(Error::BufferTooShort {
700 need: cursor + 2,
701 have: opt.len(),
702 what: "PES_CRC",
703 });
704 }
705 let crc = u16::from_be_bytes([opt[cursor], opt[cursor + 1]]);
706 cursor += 2;
707 Some(crc)
708 } else {
709 None
710 };
711
712 let pes_extension = if f2 & 0x01 != 0 {
714 let ext = PesExtension::parse(&opt[cursor..])?;
715 cursor += ext.serialized_len();
716 Some(ext)
717 } else {
718 None
719 };
720
721 let header_stuffing_len = hdl.saturating_sub(cursor);
725
726 let header = PesHeader {
727 scrambling_control: (f1 >> 4) & 0x03,
728 pes_priority: f1 & 0x08 != 0,
729 data_alignment_indicator: f1 & 0x04 != 0,
730 copyright: f1 & 0x02 != 0,
731 original_or_copy: f1 & 0x01 != 0,
732 pts,
733 dts,
734 escr,
735 es_rate,
736 dsm_trick_mode,
737 additional_copy_info,
738 pes_crc,
739 pes_extension,
740 header_stuffing_len,
741 };
742
743 Ok(PesPacket {
744 stream_id,
745 pes_packet_length,
746 header: Some(header),
747 payload: &b[hdr_end.min(payload_end)..payload_end],
748 })
749 }
750
751 #[must_use]
753 pub fn serialized_len(&self) -> usize {
754 let hdr = self
755 .header
756 .as_ref()
757 .map_or(0, |h| HEADER_FIXED + h.optional_len());
758 MIN_LEN + hdr + self.payload.len()
759 }
760
761 pub fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
763 let len = self.serialized_len();
764 if buf.len() < len {
765 return Err(Error::BufferTooShort {
766 need: len,
767 have: buf.len(),
768 what: "PES serialize output",
769 });
770 }
771 buf[0..3].copy_from_slice(&PACKET_START_CODE_PREFIX);
772 buf[3] = self.stream_id.0;
773 buf[4..6].copy_from_slice(&self.pes_packet_length.to_be_bytes());
774 let payload_at = match &self.header {
775 None => MIN_LEN,
776 Some(h) => {
777 let opt_len = h.optional_len();
778 if opt_len > 255 {
779 return Err(Error::OptionalFieldsTooLarge(opt_len));
780 }
781
782 let f1 = 0x80
784 | ((h.scrambling_control & 0x03) << 4)
785 | (u8::from(h.pes_priority) << 3)
786 | (u8::from(h.data_alignment_indicator) << 2)
787 | (u8::from(h.copyright) << 1)
788 | u8::from(h.original_or_copy);
789
790 let pts_dts_flags = match (h.pts.is_some(), h.dts.is_some()) {
793 (true, true) => 0b11u8,
794 (true, false) => 0b10,
795 _ => 0b00,
796 };
797 let f2 = (pts_dts_flags << 6)
798 | (u8::from(h.escr.is_some()) << 5)
799 | (u8::from(h.es_rate.is_some()) << 4)
800 | (u8::from(h.dsm_trick_mode.is_some()) << 3)
801 | (u8::from(h.additional_copy_info.is_some()) << 2)
802 | (u8::from(h.pes_crc.is_some()) << 1)
803 | u8::from(h.pes_extension.is_some());
804
805 buf[6] = f1;
806 buf[7] = f2;
807 buf[8] = opt_len as u8;
808
809 let mut cursor = MIN_LEN + HEADER_FIXED; if let Some(pts) = h.pts {
813 let prefix = if h.dts.is_some() { 0b0011u8 } else { 0b0010u8 };
814 buf[cursor..cursor + 5].copy_from_slice(×tamp::write(pts.0, prefix));
815 cursor += 5;
816 }
817 if let Some(dts) = h.dts {
818 buf[cursor..cursor + 5].copy_from_slice(×tamp::write(dts.0, 0b0001));
819 cursor += 5;
820 }
821 if let Some(escr) = h.escr {
823 buf[cursor..cursor + 6].copy_from_slice(&escr.to_field_bytes());
824 cursor += 6;
825 }
826 if let Some(rate) = h.es_rate {
828 buf[cursor] = 0x80 | ((rate >> 15) as u8 & 0x7F);
829 buf[cursor + 1] = ((rate >> 7) & 0xFF) as u8;
830 buf[cursor + 2] = (((rate & 0x7F) as u8) << 1) | 0x01;
831 cursor += 3;
832 }
833 if let Some(tm) = h.dsm_trick_mode {
835 buf[cursor] = tm.to_byte();
836 cursor += 1;
837 }
838 if let Some(aci) = h.additional_copy_info {
840 buf[cursor] = 0x80 | (aci & 0x7F);
841 cursor += 1;
842 }
843 if let Some(crc) = h.pes_crc {
845 buf[cursor..cursor + 2].copy_from_slice(&crc.to_be_bytes());
846 cursor += 2;
847 }
848 if let Some(ref ext) = h.pes_extension {
850 let written = ext.serialize_into(&mut buf[cursor..])?;
851 cursor += written;
852 }
853
854 for b in buf[cursor..cursor + h.header_stuffing_len].iter_mut() {
857 *b = PES_HEADER_STUFFING_BYTE;
858 }
859 cursor += h.header_stuffing_len;
860
861 cursor
862 }
863 };
864 buf[payload_at..len].copy_from_slice(self.payload);
865 Ok(len)
866 }
867}
868
869#[cfg(test)]
870mod tests {
871 use super::*;
872 extern crate alloc;
873 use alloc::vec;
874
875 fn round_trip(b: &[u8]) {
876 let pkt = PesPacket::parse(b).unwrap();
877 let mut out = vec![0u8; pkt.serialized_len()];
878 pkt.serialize_into(&mut out).unwrap();
879 assert_eq!(&out[..], b, "round-trip mismatch");
880 let re = PesPacket::parse(&out).unwrap();
881 let mut re_out = vec![0u8; re.serialized_len()];
883 re.serialize_into(&mut re_out).unwrap();
884 assert_eq!(out, re_out, "re-parse mismatch");
885 }
886
887 #[test]
888 fn video_pts_only() {
889 let b = [
891 0x00, 0x00, 0x01, 0xE0, 0x00, 0x0A, 0x80, 0x80, 0x05, 0x21, 0x00, 0x01, 0x00, 0x01,
892 0xAA, 0xBB,
893 ];
894 let pkt = PesPacket::parse(&b).unwrap();
895 assert_eq!(pkt.stream_id, StreamId(0xE0));
896 let h = pkt.header.as_ref().unwrap();
897 assert_eq!(h.pts, Some(Pts(0)));
898 assert!(h.dts.is_none());
899 assert_eq!(pkt.payload, &[0xAA, 0xBB]);
900 round_trip(&b);
901 }
902
903 #[test]
904 fn pts_and_dts() {
905 let b = [
907 0x00, 0x00, 0x01, 0xE0, 0x00, 0x0F, 0x80, 0xC0, 0x0A, 0x31, 0x00, 0x03, 0x00, 0x01,
908 0x11, 0x00, 0x05, 0x00, 0x01, 0xCC,
909 ];
910 let pkt = PesPacket::parse(&b).unwrap();
911 let h = pkt.header.as_ref().unwrap();
912 assert!(h.pts.is_some());
913 assert!(h.dts.is_some());
914 round_trip(&b);
915 }
916
917 #[test]
918 fn pes_header_stuffing_round_trip() {
919 let b = [
922 0x00, 0x00, 0x01, 0xE0, 0x00, 0x0C, 0x80, 0x80, 0x08, 0x21, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xAA, ];
927 let pkt = PesPacket::parse(&b).unwrap();
928 let h = pkt.header.as_ref().unwrap();
929 assert!(h.pts.is_some());
930 assert_eq!(
931 h.header_stuffing_len, 3,
932 "3 stuffing bytes after the 5-byte PTS"
933 );
934 assert_eq!(pkt.serialized_len(), b.len());
936 round_trip(&b); }
938
939 #[test]
940 fn special_stream_no_header() {
941 let b = [0x00, 0x00, 0x01, 0xBE, 0x00, 0x03, 0xFF, 0xFF, 0xFF];
943 let pkt = PesPacket::parse(&b).unwrap();
944 assert!(pkt.header.is_none());
945 assert_eq!(pkt.payload, &[0xFF, 0xFF, 0xFF]);
946 round_trip(&b);
947 }
948
949 #[test]
950 fn unbounded_length_zero() {
951 let b = [
953 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x80, 0x80, 0x05, 0x21, 0x00, 0x01, 0x00, 0x01,
954 0x01, 0x02, 0x03,
955 ];
956 let pkt = PesPacket::parse(&b).unwrap();
957 assert_eq!(pkt.pes_packet_length, 0);
958 assert_eq!(pkt.payload, &[0x01, 0x02, 0x03]);
959 round_trip(&b);
960 }
961
962 #[test]
963 fn rejects_bad_start_code() {
964 let err = PesPacket::parse(&[0x00, 0x00, 0x02, 0xE0, 0x00, 0x00]).unwrap_err();
965 assert!(matches!(err, Error::BadStartCode(0x000002)));
966 }
967
968 #[test]
969 fn rejects_short() {
970 let err = PesPacket::parse(&[0x00, 0x00, 0x01]).unwrap_err();
971 assert!(matches!(err, Error::BufferTooShort { .. }));
972 }
973
974 #[test]
975 fn serialize_rejects_oversized_optional_fields() {
976 let _ = Error::OptionalFieldsTooLarge(256);
982 }
983
984 fn build_pes(h: PesHeader<'_>, payload: &[u8]) -> alloc::vec::Vec<u8> {
987 let pkt = PesPacket {
988 stream_id: StreamId(0xE0),
989 pes_packet_length: 0, header: Some(h),
991 payload,
992 };
993 let mut out = vec![0u8; pkt.serialized_len()];
994 pkt.serialize_into(&mut out).unwrap();
995 out
996 }
997
998 fn empty_header<'a>() -> PesHeader<'a> {
999 PesHeader {
1000 scrambling_control: 0,
1001 pes_priority: false,
1002 data_alignment_indicator: false,
1003 copyright: false,
1004 original_or_copy: false,
1005 pts: None,
1006 dts: None,
1007 escr: None,
1008 es_rate: None,
1009 dsm_trick_mode: None,
1010 additional_copy_info: None,
1011 pes_crc: None,
1012 pes_extension: None,
1013 header_stuffing_len: 0,
1014 }
1015 }
1016
1017 #[test]
1019 fn pes_header_escr_round_trip() {
1020 let escr = Escr {
1021 base: 90_000,
1022 extension: 150,
1023 };
1024 let h = PesHeader {
1025 escr: Some(escr),
1026 ..empty_header()
1027 };
1028 let bytes = build_pes(h, &[0xAA]);
1029 let pkt = PesPacket::parse(&bytes).unwrap();
1030 assert_eq!(pkt.header.unwrap().escr, Some(escr));
1031 }
1032
1033 #[test]
1035 fn escr_27mhz_round_trip() {
1036 for ticks in [0u64, 1, 300, 27_000_000, 8_589_934_591] {
1037 let e = Escr::from_27mhz(ticks);
1038 assert_eq!(e.as_27mhz(), ticks, "ticks={ticks}");
1039 }
1040 }
1041
1042 #[test]
1044 fn escr_field_bytes_round_trip() {
1045 for (base, ext) in [
1046 (0u64, 0u16),
1047 (10_000, 0),
1048 (0x1_FFFF_FFFF, 0x1FF),
1049 (1234, 56),
1050 ] {
1051 let e = Escr {
1052 base,
1053 extension: ext,
1054 };
1055 let bytes = e.to_field_bytes();
1056 let decoded = Escr::from_field_bytes(&bytes).unwrap();
1057 assert_eq!(decoded, e, "base={base} ext={ext}");
1058 }
1059 }
1060
1061 #[test]
1063 fn pes_header_es_rate_round_trip() {
1064 let h = PesHeader {
1065 es_rate: Some(0x3FFFFF),
1066 ..empty_header()
1067 };
1068 let bytes = build_pes(h, &[]);
1069 let pkt = PesPacket::parse(&bytes).unwrap();
1070 assert_eq!(pkt.header.unwrap().es_rate, Some(0x3FFFFF));
1071 }
1072
1073 #[test]
1075 fn trick_mode_all_variants_round_trip() {
1076 let cases = [
1077 TrickMode::FastForward {
1078 field_id: 0x2,
1079 intra_slice_refresh: true,
1080 frequency_truncation: 0x3,
1081 },
1082 TrickMode::SlowMotion { rep_cntrl: 0x1F },
1083 TrickMode::FreezeFrame { field_id: 0x1 },
1084 TrickMode::FastReverse {
1085 field_id: 0x0,
1086 intra_slice_refresh: false,
1087 frequency_truncation: 0x1,
1088 },
1089 TrickMode::SlowReverse { rep_cntrl: 0 },
1090 TrickMode::Reserved {
1091 trick_mode_control: 0b101,
1092 data: 0x1A,
1093 },
1094 ];
1095 for tm in cases {
1096 let b = tm.to_byte();
1097 let decoded = TrickMode::from_byte(b);
1098 assert_eq!(decoded, tm, "tm={tm:?}");
1099 }
1100 }
1101
1102 #[test]
1104 fn pes_header_trick_mode_round_trip() {
1105 let tm = TrickMode::FastForward {
1106 field_id: 1,
1107 intra_slice_refresh: false,
1108 frequency_truncation: 2,
1109 };
1110 let h = PesHeader {
1111 dsm_trick_mode: Some(tm),
1112 ..empty_header()
1113 };
1114 let bytes = build_pes(h, &[]);
1115 let pkt = PesPacket::parse(&bytes).unwrap();
1116 assert_eq!(pkt.header.unwrap().dsm_trick_mode, Some(tm));
1117 }
1118
1119 #[test]
1121 fn pes_header_additional_copy_info_round_trip() {
1122 let h = PesHeader {
1123 additional_copy_info: Some(0x7F),
1124 ..empty_header()
1125 };
1126 let bytes = build_pes(h, &[]);
1127 let pkt = PesPacket::parse(&bytes).unwrap();
1128 assert_eq!(pkt.header.unwrap().additional_copy_info, Some(0x7F));
1129 }
1130
1131 #[test]
1133 fn pes_header_pes_crc_round_trip() {
1134 let h = PesHeader {
1135 pes_crc: Some(0xDEAD),
1136 ..empty_header()
1137 };
1138 let bytes = build_pes(h, &[]);
1139 let pkt = PesPacket::parse(&bytes).unwrap();
1140 assert_eq!(pkt.header.unwrap().pes_crc, Some(0xDEAD));
1141 }
1142
1143 #[test]
1145 fn pes_extension_ppsc_round_trip() {
1146 let ppsc = ProgramPacketSequenceCounter {
1147 counter: 42,
1148 mpeg1_mpeg2_identifier: true,
1149 original_stuff_length: 7,
1150 };
1151 let ext = PesExtension {
1152 pes_private_data: None,
1153 pack_header: None,
1154 program_packet_sequence_counter: Some(ppsc),
1155 p_std_buffer: None,
1156 pes_extension_field: None,
1157 };
1158 let h = PesHeader {
1159 pes_extension: Some(ext),
1160 ..empty_header()
1161 };
1162 let bytes = build_pes(h, &[]);
1163 let pkt = PesPacket::parse(&bytes).unwrap();
1164 let decoded_ext = pkt.header.unwrap().pes_extension.unwrap();
1165 assert_eq!(decoded_ext.program_packet_sequence_counter, Some(ppsc));
1166 }
1167
1168 #[test]
1170 fn pes_extension_p_std_buffer_round_trip() {
1171 let pstd = PStdBuffer {
1172 scale: true,
1173 size: 0x1FFF,
1174 };
1175 let ext = PesExtension {
1176 pes_private_data: None,
1177 pack_header: None,
1178 program_packet_sequence_counter: None,
1179 p_std_buffer: Some(pstd),
1180 pes_extension_field: None,
1181 };
1182 let h = PesHeader {
1183 pes_extension: Some(ext),
1184 ..empty_header()
1185 };
1186 let bytes = build_pes(h, &[]);
1187 let pkt = PesPacket::parse(&bytes).unwrap();
1188 let decoded_ext = pkt.header.unwrap().pes_extension.unwrap();
1189 assert_eq!(decoded_ext.p_std_buffer, Some(pstd));
1190 }
1191
1192 #[test]
1194 fn pes_extension_private_data_round_trip() {
1195 let pd: [u8; 16] = [
1196 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
1197 0x0F, 0x10,
1198 ];
1199 let ext = PesExtension {
1200 pes_private_data: Some(pd),
1201 pack_header: None,
1202 program_packet_sequence_counter: None,
1203 p_std_buffer: None,
1204 pes_extension_field: None,
1205 };
1206 let h = PesHeader {
1207 pes_extension: Some(ext),
1208 ..empty_header()
1209 };
1210 let bytes = build_pes(h, &[]);
1211 let pkt = PesPacket::parse(&bytes).unwrap();
1212 let decoded_ext = pkt.header.unwrap().pes_extension.unwrap();
1213 assert_eq!(decoded_ext.pes_private_data, Some(pd));
1214 }
1215
1216 #[test]
1218 fn pes_header_all_fields_round_trip() {
1219 let ppsc = ProgramPacketSequenceCounter {
1220 counter: 1,
1221 mpeg1_mpeg2_identifier: false,
1222 original_stuff_length: 0,
1223 };
1224 let ext = PesExtension {
1225 pes_private_data: None,
1226 pack_header: None,
1227 program_packet_sequence_counter: Some(ppsc),
1228 p_std_buffer: Some(PStdBuffer {
1229 scale: false,
1230 size: 100,
1231 }),
1232 pes_extension_field: None,
1233 };
1234 let h = PesHeader {
1235 scrambling_control: 0,
1236 pes_priority: true,
1237 data_alignment_indicator: false,
1238 copyright: false,
1239 original_or_copy: true,
1240 pts: Some(Pts(90_000)),
1241 dts: Some(Dts(85_000)),
1242 escr: Some(Escr {
1243 base: 1000,
1244 extension: 0,
1245 }),
1246 es_rate: Some(50_000),
1247 dsm_trick_mode: Some(TrickMode::SlowMotion { rep_cntrl: 3 }),
1248 additional_copy_info: Some(5),
1249 pes_crc: Some(0xCAFE),
1250 pes_extension: Some(ext),
1251 header_stuffing_len: 0,
1252 };
1253 let bytes = build_pes(h, &[0xFF]);
1254 let pkt = PesPacket::parse(&bytes).unwrap();
1255 let dh = pkt.header.unwrap();
1256 assert_eq!(dh.pts, Some(Pts(90_000)));
1257 assert_eq!(dh.dts, Some(Dts(85_000)));
1258 assert!(dh.escr.is_some());
1259 assert_eq!(dh.es_rate, Some(50_000));
1260 assert_eq!(
1261 dh.dsm_trick_mode,
1262 Some(TrickMode::SlowMotion { rep_cntrl: 3 })
1263 );
1264 assert_eq!(dh.additional_copy_info, Some(5));
1265 assert_eq!(dh.pes_crc, Some(0xCAFE));
1266 assert!(dh.pes_extension.is_some());
1267 }
1268}