# mpeg-pes
[](https://crates.io/crates/mpeg-pes)
[](https://docs.rs/mpeg-pes)
[](https://blog.rust-lang.org/)
[](#license)
**PES (Packetized Elementary Stream) depacketization + PTS/DTS** — the sublayer
between an MPEG-TS packet layer and an elementary-stream consumer. Per ISO/IEC
13818-1 (Rec. ITU-T H.222.0) §2.4.3.6 / §2.4.3.7.
`#![no_std]` (+ `alloc`), depends only on `broadcast-common`, WASM-clean. Pairs with
[`dvb-si`](https://crates.io/crates/dvb-si) for the TS/PSI layer:
```text
TsPacket payload + payload_unit_start ──► mpeg-pes ──► PesPacket { stream_id, pts, dts, payload }
```
## Quickstart
```rust
use mpeg_pes::{PesPacket, StreamId};
let bytes = [
0x00, 0x00, 0x01, 0xE0, 0x00, 0x0A, 0x80, 0x80, 0x05,
0x21, 0x00, 0x01, 0x00, 0x01, // PTS = 0
0xAA, 0xBB, // ES payload
];
let pkt = PesPacket::parse(&bytes)?;
assert_eq!(pkt.stream_id, StreamId(0xE0));
assert!(pkt.stream_id.is_video());
assert_eq!(pkt.header.unwrap().pts.unwrap().ticks(), 0);
assert_eq!(pkt.payload, &[0xAA, 0xBB]);
# Ok::<(), mpeg_pes::Error>(())
```
## Features
| `std` | ✅ | Link `std`. Off → `#![no_std]` + `alloc`. |
| `serde` | – | `serde::Serialize` on the public types. |
## Scope
In: PES packet header, `stream_id`, `PES_packet_length` (incl. unbounded video
`0`), the optional header flags, and **PTS/DTS** (33-bit @ 90 kHz). Out:
elementary-stream codec bitstream parsing (the consumer's job); network transport
(see `dvb-stream`).
## Examples
Run with `cargo run -p mpeg-pes --example <name>`:
- **`parse_pes_packet`** — parse one PES packet from raw bytes (stream_id + PTS + payload).
- **`extract_pts`** — depacketize a real capture, reassemble PES on a PID, and report the PTS timeline.
- **`build_pes_header`** — construct a PES packet header from typed fields (PTS+DTS, ESCR, DSM trick mode), serialize, re-parse, and verify round-trip.
### Building & editing PES headers
The [`PesPacket::serialize_into`] method lets you re-serialize a parsed or
hand-built packet byte-for-byte. Because [`PesHeader`] is `#[non_exhaustive]`,
constructors from outside the crate currently need to assemble the wire bytes
using the public typed field encoders and then parse:
```rust,ignore
// Build raw bytes with PTS+DTS using the typed field encoders, then parse.
let pts = Pts(90_000);
let dts = mpeg_pes::Dts(45_000);
// (full example: `cargo run -p mpeg-pes --example build_pes_header`)
// Once parsed, round-trip through serialize_into:
let pkt = PesPacket::parse(&bytes).unwrap();
let mut buf = vec![0u8; pkt.serialized_len()];
pkt.serialize_into(&mut buf).unwrap();
let re_pkt = PesPacket::parse(&buf).unwrap();
assert_eq!(re_pkt.header.unwrap().pts.unwrap().ticks(), 90_000);
```
Run the worked example:
```sh
cargo run -p mpeg-pes --example build_pes_header
```
## License
MIT OR Apache-2.0.