mirror of
https://github.com/storytold/filmcraft.git
synced 2026-10-14 19:26:59 -04:00
filmcraft-mpegts
Clean-room MPEG-2 Systems demuxer: transport streams and program streams. Layer L0: depends only
on thiserror. Builds for wasm32-unknown-unknown; no unsafe. No GPL/LGPL code (FFmpeg,
libavformat) was consulted; FFmpeg is used only as an external fixture generator and test
oracle.
Specifications
| Document | Edition | Used for |
|---|---|---|
| ITU-T H.222.0 | ISO/IEC 13818-1 | 2000 (second edition) | TS packets, adaptation fields, PCR, PSI (PAT / PMT, CRC-32 of Annex A), PES headers, PTS/DTS, program streams (pack, system header, program stream map), stream types |
| ISO/IEC 11172-1 | 1993 | MPEG-1 system streams (pack header, PES header stuffing / STD buffer / timestamps) |
Blu-ray / AVCHD BDAV MPEG-2 TS layout (192-byte source packets with a 4-byte TP_extra_header; registration HDMV; stream types 0x80-0x92) |
public descriptions | .m2ts / .mts |
| DVD-Video private stream 1 sub-stream layout (AC-3 / DTS 0x80-0x8F with a 3-byte header, LPCM 0xA0-0xAF with a 6-byte header, sub-pictures 0x20-0x3F) | public descriptions | .vob |
| ETSI EN 300 468 (descriptors 0x56, 0x59, 0x6A, 0x7A, 0x7B), ATSC A/52 Annex A (AC-3 in TS) | — | identifying private PES streams |
| ISO/IEC 11172-3, 13818-3 (frame headers), ISO/IEC 13818-7 (ADTS), 14496-3 (LOAS), ATSC A/52 (syncinfo, E-AC-3 frmsiz) | — | audio frame lengths for splitting |
What it does
let file = filmcraft_mpegts::open(&bytes)?; // any ByteSource (file, memory)
for (i, s) in file.streams.iter().enumerate() {
println!("{:?} {} {} units", s.id, s.codec.name(), s.units.len());
}
let v = file.find(Kind::Video, |_| true).unwrap();
let au: Vec<u8> = file.read_unit(&bytes, v, 0)?; // the first access unit
- Transport streams: 188-byte packets, 192-byte BDAV packets (sync byte after a 4-byte arrival timestamp) and 204-byte packets; the packet size is sniffed from five consecutive sync bytes. Lost sync resynchronises on the next aligned run. PSI sections are reassembled across packets and checked with the MPEG CRC-32; the first program of the PAT is demuxed. Continuity counter errors, CRC errors and resyncs are reported as warnings.
- Program streams: MPEG-2 and MPEG-1 packs, system headers, the program stream map (stream types for elementary stream ids), padding, private stream 2 (DVD navigation) skipped, private stream 1 split by sub-stream id. Garbage resynchronises on the next pack or PES start code.
- Streams: MPEG-1/2 video, H.264, HEVC, MPEG audio, AAC (ADTS, LATM/LOAS), AC-3, E-AC-3, DTS, TrueHD, Blu-ray LPCM, DVD LPCM (format from the sub-stream header), PGS / DVB / teletext subtitles; ISO 639 language from the PMT.
- Access units, found while the file is scanned (one pass, streaming; only a few bytes of
each stream are buffered):
- MPEG-1/2 video: a coded frame — a frame picture, or two field pictures (paired by picture_structure) — with the sequence / GOP headers before it; picture type, temporal reference, field structure, top_field_first, repeat_first_field, progressive_frame, closed GOP / broken link. A PTS belongs to the unit whose picture start code is in that PES.
- H.264 / HEVC: PES packets with a timestamp (a PES without one continues the previous unit); random access from IDR / IRAP NAL types; disposable when every slice is a non-reference.
- Audio: one frame per unit from the frame headers (sync re-hunted after garbage; a header found while hunting is confirmed by the next one); a PTS belongs to the first frame starting in the PES.
- LPCM and everything else: one PES packet per unit.
- Timestamps: 33-bit PTS/DTS unwrapped across the wrap (and back, for B pictures shown before a wrap that came earlier); PCR / SCR range.
- Reading: a unit records only the position of its first packet and its offset in that
packet's payload;
read_unitre-reads from there (the index costs a few dozen bytes per unit, not per packet).
Tests
src/tests.rs: a small TS muxer (PAT, PMT with CRC, PES split into 188- or 192-byte packets with adaptation-field stuffing) and PS writer (packs ≤ 2000 bytes, so frames span PES packets; AC-3 in private stream 1): every access unit reads back byte-identical with its PTS, key and disposable flags, field pairs as one unit, audio frames with the first-in-PES timestamp; 33-bit unwrap; truncation every 37 bytes and 400 random mutations never panic.src/es.rs,src/pes.rs: frame sizes (MPEG audio layers I-III, MPEG-2 LSF, AC-3 at all rates), MPEG-2 and MPEG-1 PES headers.crates/codecs/tests/mpeg_oracle.rs: FFmpeg-written TS / M2TS / VOB / MPEG-1 system files — frame counts and every frame's PTS equal ffprobe's, decoded media against FFmpeg (seefilmcraft-codecs).
Gaps
- One program per TS (the first in the PAT); no program switching, no section-based metadata (SDT / EIT), no scrambled streams.
- H.264 / HEVC access units follow PES packets: streams that put several pictures in one PES packet (rare in practice; not seen in broadcast, AVCHD or FFmpeg output) would be indexed as one unit.
- DVD navigation (IFO / NAV packets), multiple VOB concatenation and angle interleaving are not handled; each file opens on its own.