1use crate::error::{Error, Result};
4use crate::stream_id::StreamId;
5use crate::timestamp::{self, Dts, Pts};
6use crate::PACKET_START_CODE_PREFIX;
7
8const MIN_LEN: usize = 6; const HEADER_FIXED: usize = 3; #[derive(Debug, Clone, PartialEq, Eq)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize))]
17pub struct PesHeader<'a> {
18 pub scrambling_control: u8,
20 pub pes_priority: bool,
22 pub data_alignment_indicator: bool,
24 pub copyright: bool,
26 pub original_or_copy: bool,
28 pub escr_flag: bool,
30 pub es_rate_flag: bool,
32 pub dsm_trick_mode_flag: bool,
34 pub additional_copy_info_flag: bool,
36 pub pes_crc_flag: bool,
38 pub pes_extension_flag: bool,
40 pub pts: Option<Pts>,
42 pub dts: Option<Dts>,
44 #[cfg_attr(feature = "serde", serde(skip))]
47 pub optional_fields: &'a [u8],
48}
49
50#[derive(Debug, Clone, PartialEq, Eq)]
52#[cfg_attr(feature = "serde", derive(serde::Serialize))]
53pub struct PesPacket<'a> {
54 pub stream_id: StreamId,
56 pub pes_packet_length: u16,
58 pub header: Option<PesHeader<'a>>,
60 #[cfg_attr(feature = "serde", serde(skip))]
62 pub payload: &'a [u8],
63}
64
65impl<'a> PesPacket<'a> {
66 pub fn parse(b: &'a [u8]) -> Result<Self> {
68 if b.len() < MIN_LEN {
69 return Err(Error::BufferTooShort {
70 need: MIN_LEN,
71 have: b.len(),
72 what: "PES packet header",
73 });
74 }
75 if b[0..3] != PACKET_START_CODE_PREFIX {
76 return Err(Error::BadStartCode(
77 (u32::from(b[0]) << 16) | (u32::from(b[1]) << 8) | u32::from(b[2]),
78 ));
79 }
80 let stream_id = StreamId(b[3]);
81 let pes_packet_length = u16::from_be_bytes([b[4], b[5]]);
82 let payload_end = if pes_packet_length == 0 {
84 b.len()
85 } else {
86 (MIN_LEN + pes_packet_length as usize).min(b.len())
87 };
88
89 if !stream_id.has_optional_header() {
90 return Ok(PesPacket {
91 stream_id,
92 pes_packet_length,
93 header: None,
94 payload: &b[MIN_LEN..payload_end],
95 });
96 }
97
98 if b.len() < MIN_LEN + HEADER_FIXED {
99 return Err(Error::BufferTooShort {
100 need: MIN_LEN + HEADER_FIXED,
101 have: b.len(),
102 what: "PES optional header",
103 });
104 }
105 let f1 = b[6];
106 let f2 = b[7];
107 let hdl = usize::from(b[8]);
108 let hdr_start = MIN_LEN + HEADER_FIXED;
109 let hdr_end = hdr_start + hdl;
110 if b.len() < hdr_end {
111 return Err(Error::BufferTooShort {
112 need: hdr_end,
113 have: b.len(),
114 what: "PES_header_data_length",
115 });
116 }
117 let optional_fields = &b[hdr_start..hdr_end];
118
119 let pts_dts_flags = (f2 >> 6) & 0x03;
120 let (pts, dts) = match pts_dts_flags {
121 0b10 => (
122 Some(Pts(timestamp::read(optional_fields, 0b0010, "PTS")?)),
123 None,
124 ),
125 0b11 => {
126 let pts = Pts(timestamp::read(optional_fields, 0b0011, "PTS")?);
127 let dts_bytes = optional_fields.get(5..).unwrap_or(&[]);
128 let dts = Dts(timestamp::read(dts_bytes, 0b0001, "DTS")?);
129 (Some(pts), Some(dts))
130 }
131 _ => (None, None),
132 };
133
134 let header = PesHeader {
135 scrambling_control: (f1 >> 4) & 0x03,
136 pes_priority: f1 & 0x08 != 0,
137 data_alignment_indicator: f1 & 0x04 != 0,
138 copyright: f1 & 0x02 != 0,
139 original_or_copy: f1 & 0x01 != 0,
140 escr_flag: f2 & 0x20 != 0,
141 es_rate_flag: f2 & 0x10 != 0,
142 dsm_trick_mode_flag: f2 & 0x08 != 0,
143 additional_copy_info_flag: f2 & 0x04 != 0,
144 pes_crc_flag: f2 & 0x02 != 0,
145 pes_extension_flag: f2 & 0x01 != 0,
146 pts,
147 dts,
148 optional_fields,
149 };
150
151 Ok(PesPacket {
152 stream_id,
153 pes_packet_length,
154 header: Some(header),
155 payload: &b[hdr_end.min(payload_end)..payload_end],
156 })
157 }
158
159 #[must_use]
161 pub fn serialized_len(&self) -> usize {
162 let hdr = self
163 .header
164 .as_ref()
165 .map_or(0, |h| HEADER_FIXED + h.optional_fields.len());
166 MIN_LEN + hdr + self.payload.len()
167 }
168
169 pub fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
171 let len = self.serialized_len();
172 if buf.len() < len {
173 return Err(Error::BufferTooShort {
174 need: len,
175 have: buf.len(),
176 what: "PES serialize output",
177 });
178 }
179 buf[0..3].copy_from_slice(&PACKET_START_CODE_PREFIX);
180 buf[3] = self.stream_id.0;
181 buf[4..6].copy_from_slice(&self.pes_packet_length.to_be_bytes());
182 let payload_at = match &self.header {
183 None => MIN_LEN,
184 Some(h) => {
185 if h.optional_fields.len() > 255 {
186 return Err(Error::OptionalFieldsTooLarge(h.optional_fields.len()));
187 }
188 let f1 = 0x80
189 | ((h.scrambling_control & 0x03) << 4)
190 | (u8::from(h.pes_priority) << 3)
191 | (u8::from(h.data_alignment_indicator) << 2)
192 | (u8::from(h.copyright) << 1)
193 | u8::from(h.original_or_copy);
194 let pts_dts_flags = match (h.pts.is_some(), h.dts.is_some()) {
195 (true, true) => 0b11,
196 (true, false) => 0b10,
197 _ => 0b00,
198 };
199 let f2 = (pts_dts_flags << 6)
200 | (u8::from(h.escr_flag) << 5)
201 | (u8::from(h.es_rate_flag) << 4)
202 | (u8::from(h.dsm_trick_mode_flag) << 3)
203 | (u8::from(h.additional_copy_info_flag) << 2)
204 | (u8::from(h.pes_crc_flag) << 1)
205 | u8::from(h.pes_extension_flag);
206 buf[6] = f1;
207 buf[7] = f2;
208 buf[8] = h.optional_fields.len() as u8;
209 let hdr_end = MIN_LEN + HEADER_FIXED + h.optional_fields.len();
210 buf[MIN_LEN + HEADER_FIXED..hdr_end].copy_from_slice(h.optional_fields);
211 hdr_end
212 }
213 };
214 buf[payload_at..len].copy_from_slice(self.payload);
215 Ok(len)
216 }
217}
218
219#[cfg(test)]
220mod tests {
221 use super::*;
222 extern crate alloc;
223 use alloc::vec;
224
225 fn round_trip(b: &[u8]) {
226 let pkt = PesPacket::parse(b).unwrap();
227 let mut out = vec![0u8; pkt.serialized_len()];
228 pkt.serialize_into(&mut out).unwrap();
229 assert_eq!(&out[..], b, "round-trip mismatch");
230 assert_eq!(PesPacket::parse(&out).unwrap(), pkt);
231 }
232
233 #[test]
234 fn video_pts_only() {
235 let b = [
237 0x00, 0x00, 0x01, 0xE0, 0x00, 0x0A, 0x80, 0x80, 0x05, 0x21, 0x00, 0x01, 0x00, 0x01,
238 0xAA, 0xBB,
239 ];
240 let pkt = PesPacket::parse(&b).unwrap();
241 assert_eq!(pkt.stream_id, StreamId(0xE0));
242 let h = pkt.header.as_ref().unwrap();
243 assert_eq!(h.pts, Some(Pts(0)));
244 assert!(h.dts.is_none());
245 assert_eq!(pkt.payload, &[0xAA, 0xBB]);
246 round_trip(&b);
247 }
248
249 #[test]
250 fn pts_and_dts() {
251 let b = [
253 0x00, 0x00, 0x01, 0xE0, 0x00, 0x0F, 0x80, 0xC0, 0x0A, 0x31, 0x00, 0x03, 0x00, 0x01,
254 0x11, 0x00, 0x05, 0x00, 0x01, 0xCC,
255 ];
256 let pkt = PesPacket::parse(&b).unwrap();
257 let h = pkt.header.as_ref().unwrap();
258 assert!(h.pts.is_some());
259 assert!(h.dts.is_some());
260 round_trip(&b);
261 }
262
263 #[test]
264 fn special_stream_no_header() {
265 let b = [0x00, 0x00, 0x01, 0xBE, 0x00, 0x03, 0xFF, 0xFF, 0xFF];
267 let pkt = PesPacket::parse(&b).unwrap();
268 assert!(pkt.header.is_none());
269 assert_eq!(pkt.payload, &[0xFF, 0xFF, 0xFF]);
270 round_trip(&b);
271 }
272
273 #[test]
274 fn unbounded_length_zero() {
275 let b = [
277 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x80, 0x80, 0x05, 0x21, 0x00, 0x01, 0x00, 0x01,
278 0x01, 0x02, 0x03,
279 ];
280 let pkt = PesPacket::parse(&b).unwrap();
281 assert_eq!(pkt.pes_packet_length, 0);
282 assert_eq!(pkt.payload, &[0x01, 0x02, 0x03]);
283 round_trip(&b);
284 }
285
286 #[test]
287 fn rejects_bad_start_code() {
288 let err = PesPacket::parse(&[0x00, 0x00, 0x02, 0xE0, 0x00, 0x00]).unwrap_err();
289 assert!(matches!(err, Error::BadStartCode(0x000002)));
290 }
291
292 #[test]
293 fn rejects_short() {
294 let err = PesPacket::parse(&[0x00, 0x00, 0x01]).unwrap_err();
295 assert!(matches!(err, Error::BufferTooShort { .. }));
296 }
297
298 #[test]
299 fn serialize_rejects_oversized_optional_fields() {
300 let big = vec![0u8; 256];
303 let pkt = PesPacket {
304 stream_id: StreamId(0xE0),
305 pes_packet_length: 0,
306 header: Some(PesHeader {
307 scrambling_control: 0,
308 pes_priority: false,
309 data_alignment_indicator: false,
310 copyright: false,
311 original_or_copy: false,
312 escr_flag: false,
313 es_rate_flag: false,
314 dsm_trick_mode_flag: false,
315 additional_copy_info_flag: false,
316 pes_crc_flag: false,
317 pes_extension_flag: false,
318 pts: None,
319 dts: None,
320 optional_fields: &big,
321 }),
322 payload: &[],
323 };
324 let mut out = vec![0u8; pkt.serialized_len()];
325 assert!(matches!(
326 pkt.serialize_into(&mut out),
327 Err(Error::OptionalFieldsTooLarge(256))
328 ));
329 }
330}