Skip to main content

Crate mpeg_ps

Crate mpeg_ps 

Source
Expand description

MPEG-1/2 Program Stream parsing — ISO/IEC 13818-1 (Rec. ITU-T H.222.0) §2.5.

The Program Stream (.mpg / .vob) framing that wraps PES packets: the PackHeader (42-bit SCR + program_mux_rate), the optional SystemHeader (rate/audio/video bounds + per-stream P-STD buffer bounds), and the ProgramStreamMap (PSM).

PES payloads are parsed via the mpeg-pes crate.

Depends only on dvb-common + mpeg-pes and is #![no_std] (+ alloc).

§Examples

Parse a pack header from bytes:

use mpeg_ps::PackHeader;
use broadcast_common::Parse;

// A minimal pack header: start_code 0x000001BA, SCR=0, mux_rate=3, stuffing=0
let bytes = [
    0x00, 0x00, 0x01, 0xBA,
    0x44, 0x00, 0x04, 0x00, 0x04, 0x01,
    0x40, 0x00, 0x03, 0x00,
];
let h = PackHeader::parse(&bytes).unwrap();
assert_eq!(h.program_mux_rate, 3);
assert_eq!(h.scr.ticks(), 0);

Walk a Program Stream:

let data = fs::read("tests/fixtures/ffmpeg-mpeg2-ps.mpg").unwrap();
let (packs, _trailing) = program_stream::parse_all_packs(&data).unwrap();
println!("Found {} packs", packs.len());
for (i, pack) in packs.iter().enumerate() {
    println!("Pack {}: SCR={} ticks, mux_rate={} B/s",
             i, pack.pack_header.scr.ticks(),
             pack.pack_header.program_mux_rate * 50);
}

§Runnable examples

Run with cargo run -p mpeg-ps --example <name>.

§parse_pack_header

use broadcast_common::Parse;
/// Parse one pack header from inline bytes and print the SCR + mux_rate.
///
/// ```sh
/// cargo run -p mpeg-ps --example parse_pack_header
/// ```
use mpeg_ps::PackHeader;

fn main() {
    // A minimal pack header (from the fixture pattern):
    // start_code 0x000001BA, SCR=0, mux_rate=0x03363B, reserved=0x1F, stuffing=0
    let bytes = [
        0x00, 0x00, 0x01, 0xBA, 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, 0x43, 0x36, 0x3B, 0xF8,
    ];
    let header = PackHeader::parse(&bytes).unwrap();
    println!("pack_start_code:       0x000001BA");
    println!("SCR base:              {}", header.scr.base);
    println!("SCR extension:         {}", header.scr.extension);
    println!("SCR ticks:             {}", header.scr.ticks());
    println!("SCR seconds:           {:.6}", header.scr.seconds());
    println!(
        "program_mux_rate:      {} ({} B/s)",
        header.program_mux_rate,
        header.program_mux_rate * 50
    );
    println!("pack_stuffing_length:  {}", header.stuffing_length);
    println!("reserved:              {}", header.reserved);
}

§walk_ps

/// Walk the real `.mpg` fixture at runtime, report pack count + SCR timeline.
///
/// ```sh
/// cargo run -p mpeg-ps --example walk_ps
/// ```
use std::fs;

use mpeg_ps::program_stream;

fn main() {
    // Resolve relative to the crate so it runs from any cwd.
    let path = concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/tests/fixtures/ffmpeg-mpeg2-ps.mpg"
    );
    let data = match fs::read(path) {
        Ok(d) => d,
        Err(e) => {
            eprintln!("fixture not available ({e}); nothing to do");
            return;
        }
    };
    let (packs, trailing) = program_stream::parse_all_packs(&data).unwrap();

    println!("File: {path}");
    println!("Size: {} bytes", data.len());
    println!("Trailing bytes: {}", trailing.len());
    println!("Packs: {}", packs.len());
    println!();
    println!(
        "{:<6} {:<20} {:<15} {:<10}",
        "Pack", "SCR (ticks)", "SCR (s)", "mux_rate (B/s)"
    );
    println!("{:-<6} {:-<20} {:-<15} {:-<10}", "", "", "", "");

    let mut pes_total = 0usize;
    for (i, pack) in packs.iter().enumerate() {
        let scr_ticks = pack.pack_header.scr.ticks();
        let scr_s = pack.pack_header.scr.seconds();
        let mux_rate = pack.pack_header.program_mux_rate * 50;
        println!("{i:<6} {scr_ticks:<20} {scr_s:<15.6} {mux_rate:<10}",);

        if let Some(ref sh) = pack.system_header {
            println!(
                "       system_header: rate_bound={}, audio_bound={}, video_bound={}, streams={}",
                sh.rate_bound,
                sh.audio_bound,
                sh.video_bound,
                sh.std_buffer_bounds.len(),
            );
        }

        for pes in &pack.pes_packets {
            pes_total += 1;
            if let Some(ref hdr) = pes.header {
                if let Some(pts) = hdr.pts {
                    let pts_s = pts.seconds();
                    println!(
                        "         PES stream_id={:#04x} PTS={:.6}s payload={}B",
                        pes.stream_id.0,
                        pts_s,
                        pes.payload.len(),
                    );
                }
            }
        }
    }

    println!();
    println!("Total PES packets: {pes_total}");
}

Re-exports§

pub use program_stream_map::EsMapEntry;
pub use program_stream_map::ProgramStreamMap;

Modules§

program_stream
Program Stream walker — ISO/IEC 13818-1 §2.5.3.1–2.5.3.3 (Tables 2-37, 2-38).
program_stream_map
Program Stream Map — ISO/IEC 13818-1 §2.5.4, Table 2-41.

Structs§

PackHeader
A parsed pack header.
Scr
System Clock Reference (42-bit total: 33-bit base + 9-bit extension, in 27 MHz units).
StdBufferBound
A per-stream P-STD buffer bound entry.
SystemHeader
A parsed system header.

Enums§

Error
A Program Stream parse error.

Constants§

PACKET_START_CODE_PREFIX
The 3-byte packet_start_code_prefix that opens PES and PSM packets (0x000001).
PROGRAM_END_CODE
MPEG_program_end_code0x000001B9, terminates the program stream.

Type Aliases§

Result
Result alias for Program Stream parsing.