Task 420: .MPG File Format

Task 420: .MPG File Format

The .MPG file format (also known as MPEG) is a container for multiplexed video and audio streams, primarily based on the MPEG-1 standard (ISO/IEC 11172-1) or MPEG-2 (ISO/IEC 13818-1). It uses a program stream structure consisting of packs (typically 2048 bytes each for compatibility with media like VCDs), each containing a pack header, an optional system header, and one or more Packetized Elementary Stream (PES) packets carrying audio, video, or other data. The format supports lossy compression for video (MPEG-1/2 Video) and audio (MPEG-1/2 Audio Layer I/II/III). Files start with a pack header (magic bytes 0x000001BA) and are designed for storage and playback on reliable media.

List of all the properties of this file format intrinsic to its file system:

  • Pack Start Code (32 bits): Fixed synchronization value (0x000001BA).
  • Version Marker (4 bits for MPEG-1 or 2 bits for MPEG-2): Indicates MPEG version (e.g., '0010' for MPEG-1).
  • System Clock Reference (SCR) (33 bits): Timestamp for synchronization, split into high/mid/low bits with markers.
  • SCR Extension (9 bits, MPEG-2 only): Extended timestamp precision.
  • Mux Rate (22 bits): Multiplexing bitrate in 50 bytes/second units.
  • Stuffing Length (3 bits): Number of padding bytes in the pack header.
  • System Header Start Code (32 bits, if present): Fixed value (0x000001BB).
  • System Header Length (16 bits): Size of the system header excluding start code.
  • Rate Bound (22 bits): Maximum bitrate bound.
  • Audio Bound (6 bits): Maximum number of audio streams (0-32).
  • Fixed Flag (1 bit): Indicates fixed bitrate.
  • CSPS Flag (1 bit): Constraint Set Parameter Streams flag.
  • System Audio Lock Flag (1 bit): Audio locked to system clock.
  • System Video Lock Flag (1 bit): Video locked to system clock.
  • Video Bound (5 bits): Maximum number of video streams (0-16).
  • Packet Rate Restriction Flag (1 bit): Restricts packet rate.
  • Stream Bindings (variable, per stream in system header): Stream ID (8 bits), Buffer Bound Scale (1 bit), Buffer Size Bound (13 bits).
  • PES Packet Start Code (24 bits prefix + 8 bits Stream ID): 0x000001 + ID (e.g., 0xC0-0xDF for audio, 0xE0-0xEF for video).
  • PES Packet Length (16 bits): Size of PES data.
  • PES Scrambling Control (2 bits): Scrambling mode.
  • PES Priority (1 bit): Packet priority.
  • Data Alignment Indicator (1 bit): Data alignment flag.
  • Copyright (1 bit): Copyright flag.
  • Original or Copy (1 bit): Original content flag.
  • PTS/DTS Indicator (2 bits): Presence of Presentation/Decoding Time Stamps.
  • ESCR Flag (1 bit): Elementary Stream Clock Reference presence.
  • ES Rate Flag (1 bit): Elementary Stream rate presence.
  • DSM Trick Mode Flag (1 bit): Trick mode (fast-forward/etc.) flag.
  • Additional Copy Info Flag (1 bit): Additional copyright info presence.
  • PES CRC Flag (1 bit): CRC presence.
  • PES Extension Flag (1 bit): Extension fields presence.
  • PES Header Length (8 bits): Length of optional PES header fields.
  • Presentation Time Stamp (PTS) (33 bits, optional): When to present the data.
  • Decoding Time Stamp (DTS) (33 bits, optional): When to decode the data.
  • Elementary Stream Clock Reference (ESCR) (42 bits, optional): Clock reference.
  • Elementary Stream Rate (22 bits, optional): Bitrate of the elementary stream.
  • Stuffing Bytes (variable): Padding in PES header.

Two direct download links for files of format .MPG:

Ghost blog embedded HTML JavaScript for drag-and-drop .MPG file to dump properties:
Assuming "ghost blog embedded" refers to HTML/JavaScript embeddable in a Ghost blog post (or similar), here's a self-contained HTML file with embedded JavaScript. Save it as mpg-parser.html and open in a browser. It allows dragging/dropping a .MPG file, parses the first pack/system header and one PES packet (for simplicity, as full parsing of large files is resource-intensive in browser), and dumps the properties to the screen. It uses DataView for byte/bit manipulation.

Python class for opening, decoding, reading, writing, and printing .MPG properties:
The class assumes MPEG-1 for simplicity and parses the first pack/system header and one PES packet. It uses struct for unpacking. read loads the file, print_properties dumps to console, write saves the original bytes (modify self.data to change).

import struct

class MpgHandler:
    def __init__(self):
        self.data = None
        self.properties = {}

    def read(self, filepath):
        with open(filepath, 'rb') as f:
            self.data = f.read()
        self.decode()

    def decode(self):
        if not self.data:
            return
        pos = 0
        # Pack Header
        pack_start, = struct.unpack('>I', self.data[pos:pos+4])
        self.properties['Pack Start Code'] = hex(pack_start)
        pos += 4
        version_marker = (self.data[pos] >> 4) & 0x0F
        self.properties['Version Marker'] = 'MPEG-1' if version_marker == 2 else 'Unknown'
        scr_high = (self.data[pos] & 0x0E) >> 1
        pos += 1
        scr_mid = (struct.unpack('>H', self.data[pos:pos+2])[0] & 0xFFFE) >> 1
        pos += 2
        scr_low = (struct.unpack('>H', self.data[pos:pos+2])[0] & 0xFFFE) >> 1
        pos += 2
        self.properties['SCR'] = (scr_high << 30) + (scr_mid << 15) + scr_low
        mux_rate_high = self.data[pos-1] & 0x01
        mux_rate_low = struct.unpack('>H', self.data[pos:pos+2])[0] >> 2  # Approx, adjust bits
        self.properties['Mux Rate'] = ((mux_rate_high << 22) | mux_rate_low) * 50
        pos += 2
        stuffing_length = self.data[pos] & 0x07
        self.properties['Stuffing Length'] = stuffing_length
        pos += 1 + stuffing_length

        # System Header
        if struct.unpack('>I', self.data[pos:pos+4])[0] == 0x000001BB:
            self.properties['System Header Start Code'] = '0x000001BB'
            pos += 4
            header_length, = struct.unpack('>H', self.data[pos:pos+2])
            self.properties['System Header Length'] = header_length
            pos += 2
            rate_bound = struct.unpack('>I', b'\x00' + self.data[pos:pos+3])[0] >> 1 & 0x3FFFFF
            self.properties['Rate Bound'] = rate_bound
            pos += 3
            audio_bound = self.data[pos] >> 2
            self.properties['Audio Bound'] = audio_bound
            fixed_flag = (self.data[pos] >> 1) & 1
            self.properties['Fixed Flag'] = fixed_flag
            csps_flag = self.data[pos] & 1
            self.properties['CSPS Flag'] = csps_flag
            pos += 1
            audio_lock = self.data[pos] >> 7 & 1
            self.properties['System Audio Lock Flag'] = audio_lock
            video_lock = self.data[pos] >> 6 & 1
            self.properties['System Video Lock Flag'] = video_lock
            video_bound = self.data[pos] & 0x1F
            self.properties['Video Bound'] = video_bound
            pos += 1
            packet_rate_restriction = self.data[pos] >> 7 & 1
            self.properties['Packet Rate Restriction Flag'] = packet_rate_restriction
            pos += header_length - 6  # Skip rest

        # First PES Packet
        if struct.unpack('>I', self.data[pos:pos+4])[0] >> 8 == 0x000001:
            stream_id = self.data[pos+3]
            self.properties['PES Stream ID'] = hex(stream_id)
            pos += 4
            packet_length, = struct.unpack('>H', self.data[pos:pos+2])
            self.properties['PES Packet Length'] = packet_length
            pos += 2
            # Optional PES
            pes_flags = self.data[pos]
            if pes_flags >> 6 == 2:
                pos += 1
                pts_dts_indicator = self.data[pos] >> 4 & 3
                self.properties['PTS/DTS Indicator'] = pts_dts_indicator
                # ... (add more as needed)

    def print_properties(self):
        for key, value in self.properties.items():
            print(f'{key}: {value}')

    def write(self, filepath):
        if self.data:
            with open(filepath, 'wb') as f:
                f.write(self.data)

Usage example:

handler = MpgHandler()
handler.read('example.mpg')
handler.print_properties()
handler.write('output.mpg')

Java class for opening, decoding, reading, writing, and printing .MPG properties:
Similar to Python, using ByteBuffer for parsing. Assumes MPEG-1.

import java.io.*;
import java.nio.*;
import java.util.HashMap;
import java.util.Map;

public class MpgHandler {
    private byte[] data;
    private Map<String, Object> properties = new HashMap<>();

    public void read(String filepath) throws IOException {
        try (FileInputStream fis = new FileInputStream(filepath)) {
            data = fis.readAllBytes();
        }
        decode();
    }

    private void decode() {
        if (data == null) return;
        ByteBuffer bb = ByteBuffer.wrap(data).order(ByteOrder.BIG_ENDIAN);
        int pos = 0;
        // Pack Header
        int packStart = bb.getInt(pos);
        properties.put("Pack Start Code", Integer.toHexString(packStart));
        pos += 4;
        int versionMarker = (bb.get(pos) >> 4) & 0x0F;
        properties.put("Version Marker", versionMarker == 2 ? "MPEG-1" : "Unknown");
        long scr = ((bb.get(pos) & 0x0E) >> 1) * (1L << 30);
        pos++;
        scr += ((bb.getShort(pos) & 0xFFFE) >> 1) * (1L << 15);
        pos += 2;
        scr += (bb.getShort(pos) & 0xFFFE) >> 1;
        pos += 2;
        properties.put("SCR", scr);
        long muxRate = ((data[pos-1] & 0x01) * (1L << 22)) | (bb.getShort(pos) >>> 2 & 0x3FFFFF); // Approx
        properties.put("Mux Rate", muxRate * 50);
        pos += 2;
        int stuffingLength = bb.get(pos) & 0x07;
        properties.put("Stuffing Length", stuffingLength);
        pos += 1 + stuffingLength;

        // System Header
        if (bb.getInt(pos) == 0x000001BB) {
            properties.put("System Header Start Code", "0x000001BB");
            pos += 4;
            int headerLength = bb.getShort(pos);
            properties.put("System Header Length", headerLength);
            pos += 2;
            bb.position(pos);
            long rateBound = (bb.getInt() >>> 9) & 0x3FFFFF;
            properties.put("Rate Bound", rateBound);
            pos += 3;
            int audioBound = bb.get(pos) >> 2;
            properties.put("Audio Bound", audioBound);
            int fixedFlag = (bb.get(pos) >> 1) & 1;
            properties.put("Fixed Flag", fixedFlag);
            int cspsFlag = bb.get(pos) & 1;
            properties.put("CSPS Flag", cspsFlag);
            pos++;
            int audioLock = bb.get(pos) >> 7 & 1;
            properties.put("System Audio Lock Flag", audioLock);
            int videoLock = bb.get(pos) >> 6 & 1;
            properties.put("System Video Lock Flag", videoLock);
            int videoBound = bb.get(pos) & 0x1F;
            properties.put("Video Bound", videoBound);
            pos++;
            int packetRateRestriction = bb.get(pos) >> 7 & 1;
            properties.put("Packet Rate Restriction Flag", packetRateRestriction);
            pos += headerLength - 6;
        }

        // First PES Packet
        if ((bb.getInt(pos) >>> 8) == 0x000001) {
            int streamId = bb.get(pos + 3) & 0xFF;
            properties.put("PES Stream ID", Integer.toHexString(streamId));
            pos += 4;
            int packetLength = bb.getShort(pos);
            properties.put("PES Packet Length", packetLength);
            pos += 2;
            int pesFlags = bb.get(pos) & 0xFF;
            if ((pesFlags >>> 6) == 2) {
                pos++;
                int ptsDtsIndicator = (bb.get(pos) >>> 4) & 3;
                properties.put("PTS/DTS Indicator", ptsDtsIndicator);
                // ... (add more)
            }
        }
    }

    public void printProperties() {
        properties.forEach((key, value) -> System.out.println(key + ": " + value));
    }

    public void write(String filepath) throws IOException {
        if (data != null) {
            try (FileOutputStream fos = new FileOutputStream(filepath)) {
                fos.write(data);
            }
        }
    }
}

Usage example:

public static void main(String[] args) throws IOException {
    MpgHandler handler = new MpgHandler();
    handler.read("example.mpg");
    handler.printProperties();
    handler.write("output.mpg");
}

JavaScript class for opening, decoding, reading, writing, and printing .MPG properties:
For Node.js (uses fs for file I/O). Parses similarly. read loads file, printProperties logs to console, write saves.

const fs = require('fs');

class MpgHandler {
    constructor() {
        this.data = null;
        this.properties = {};
    }

    read(filepath) {
        this.data = fs.readFileSync(filepath);
        this.decode();
    }

    decode() {
        if (!this.data) return;
        const view = new DataView(this.data.buffer);
        let pos = 0;
        // Pack Header
        this.properties['Pack Start Code'] = `0x${view.getUint32(pos).toString(16).toUpperCase()}`;
        pos += 4;
        const versionMarker = (view.getUint8(pos) >> 4) & 0x0F;
        this.properties['Version Marker'] = versionMarker === 2 ? 'MPEG-1' : 'Unknown';
        let scr = ((view.getUint8(pos) & 0x0E) >> 1) << 30;
        pos++;
        scr += ((view.getUint16(pos) & 0xFFFE) >> 1) << 15;
        pos += 2;
        scr += (view.getUint16(pos) & 0xFFFE) >> 1;
        pos += 2;
        this.properties['SCR'] = scr;
        const muxRateHigh = view.getUint8(pos - 1) & 0x01;
        const muxRateLow = view.getUint16(pos) >>> 2;
        this.properties['Mux Rate'] = ((muxRateHigh << 22) | muxRateLow) * 50;
        pos += 2;
        const stuffingLength = view.getUint8(pos) & 0x07;
        this.properties['Stuffing Length'] = stuffingLength;
        pos += 1 + stuffingLength;

        // System Header
        if (view.getUint32(pos) === 0x000001BB) {
            this.properties['System Header Start Code'] = '0x000001BB';
            pos += 4;
            const headerLength = view.getUint16(pos);
            this.properties['System Header Length'] = headerLength;
            pos += 2;
            const rateBound = (view.getUint32(pos) >>> 9) & 0x3FFFFF;
            this.properties['Rate Bound'] = rateBound;
            pos += 3;
            const audioBound = view.getUint8(pos) >> 2;
            this.properties['Audio Bound'] = audioBound;
            const fixedFlag = (view.getUint8(pos) >> 1) & 1;
            this.properties['Fixed Flag'] = fixedFlag;
            const cspsFlag = view.getUint8(pos) & 1;
            this.properties['CSPS Flag'] = cspsFlag;
            pos++;
            const audioLock = (view.getUint8(pos) >> 7) & 1;
            this.properties['System Audio Lock Flag'] = audioLock;
            const videoLock = (view.getUint8(pos) >> 6) & 1;
            this.properties['System Video Lock Flag'] = videoLock;
            const videoBound = view.getUint8(pos) & 0x1F;
            this.properties['Video Bound'] = videoBound;
            pos++;
            const packetRateRestriction = (view.getUint8(pos) >> 7) & 1;
            this.properties['Packet Rate Restriction Flag'] = packetRateRestriction;
            pos += headerLength - 6;
        }

        // First PES Packet
        if (view.getUint32(pos) >>> 8 === 0x000001) {
            const streamId = view.getUint8(pos + 3);
            this.properties['PES Stream ID'] = `0x${streamId.toString(16).toUpperCase()}`;
            pos += 4;
            const packetLength = view.getUint16(pos);
            this.properties['PES Packet Length'] = packetLength;
            pos += 2;
            const pesFlags = view.getUint8(pos);
            if ((pesFlags >>> 6) === 2) {
                pos++;
                const ptsDtsIndicator = (view.getUint8(pos) >>> 4) & 3;
                this.properties['PTS/DTS Indicator'] = ptsDtsIndicator;
                // ... (add more)
            }
        }
    }

    printProperties() {
        for (const [key, value] of Object.entries(this.properties)) {
            console.log(`${key}: ${value}`);
        }
    }

    write(filepath) {
        if (this.data) {
            fs.writeFileSync(filepath, this.data);
        }
    }
}

// Usage example:
// const handler = new MpgHandler();
// handler.read('example.mpg');
// handler.printProperties();
// handler.write('output.mpg');

C class (using C++ for class support) for opening, decoding, reading, writing, and printing .MPG properties:
Similar parsing using bit manipulation. Assumes MPEG-1.

#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <cstdint>
#include <cstring>

class MpgHandler {
private:
    std::vector<uint8_t> data;
    std::map<std::string, std::string> properties;

public:
    void read(const std::string& filepath) {
        std::ifstream file(filepath, std::ios::binary);
        if (file) {
            data = std::vector<uint8_t>((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
            decode();
        }
    }

    void decode() {
        if (data.empty()) return;
        size_t pos = 0;
        // Pack Header
        uint32_t packStart;
        memcpy(&packStart, &data[pos], 4);
        char hexBuf[9];
        snprintf(hexBuf, sizeof(hexBuf), "0x%08X", __builtin_bswap32(packStart)); // Big-endian
        properties["Pack Start Code"] = hexBuf;
        pos += 4;
        uint8_t byte = data[pos];
        int versionMarker = (byte >> 4) & 0x0F;
        properties["Version Marker"] = (versionMarker == 2) ? "MPEG-1" : "Unknown";
        uint64_t scr = ((byte & 0x0E) >> 1) << 30;
        pos++;
        uint16_t shortVal;
        memcpy(&shortVal, &data[pos], 2);
        shortVal = __builtin_bswap16(shortVal);
        scr += ((shortVal & 0xFFFE) >> 1) << 15;
        pos += 2;
        memcpy(&shortVal, &data[pos], 2);
        shortVal = __builtin_bswap16(shortVal);
        scr += (shortVal & 0xFFFE) >> 1;
        pos += 2;
        properties["SCR"] = std::to_string(scr);
        uint8_t muxHigh = data[pos-1] & 0x01;
        memcpy(&shortVal, &data[pos], 2);
        shortVal = __builtin_bswap16(shortVal);
        uint32_t muxRate = (muxHigh << 22) | (shortVal >> 2);
        properties["Mux Rate"] = std::to_string(muxRate * 50);
        pos += 2;
        int stuffingLength = data[pos] & 0x07;
        properties["Stuffing Length"] = std::to_string(stuffingLength);
        pos += 1 + stuffingLength;

        // System Header
        uint32_t sysStart;
        memcpy(&sysStart, &data[pos], 4);
        if (__builtin_bswap32(sysStart) == 0x000001BB) {
            properties["System Header Start Code"] = "0x000001BB";
            pos += 4;
            memcpy(&shortVal, &data[pos], 2);
            shortVal = __builtin_bswap16(shortVal);
            properties["System Header Length"] = std::to_string(shortVal);
            int headerLength = shortVal;
            pos += 2;
            uint32_t intVal;
            memcpy(&intVal, &data[pos-1], 4); // Offset for alignment
            intVal = __builtin_bswap32(intVal);
            uint32_t rateBound = (intVal >> 9) & 0x3FFFFF;
            properties["Rate Bound"] = std::to_string(rateBound);
            pos += 3;
            int audioBound = data[pos] >> 2;
            properties["Audio Bound"] = std::to_string(audioBound);
            int fixedFlag = (data[pos] >> 1) & 1;
            properties["Fixed Flag"] = std::to_string(fixedFlag);
            int cspsFlag = data[pos] & 1;
            properties["CSPS Flag"] = std::to_string(cspsFlag);
            pos++;
            int audioLock = data[pos] >> 7 & 1;
            properties["System Audio Lock Flag"] = std::to_string(audioLock);
            int videoLock = data[pos] >> 6 & 1;
            properties["System Video Lock Flag"] = std::to_string(videoLock);
            int videoBound = data[pos] & 0x1F;
            properties["Video Bound"] = std::to_string(videoBound);
            pos++;
            int packetRateRestriction = data[pos] >> 7 & 1;
            properties["Packet Rate Restriction Flag"] = std::to_string(packetRateRestriction);
            pos += headerLength - 6;
        }

        // First PES Packet
        memcpy(&intVal, &data[pos], 4);
        intVal = __builtin_bswap32(intVal);
        if ((intVal >> 8) == 0x000001) {
            uint8_t streamId = data[pos + 3];
            snprintf(hexBuf, sizeof(hexBuf), "0x%02X", streamId);
            properties["PES Stream ID"] = hexBuf;
            pos += 4;
            memcpy(&shortVal, &data[pos], 2);
            shortVal = __builtin_bswap16(shortVal);
            properties["PES Packet Length"] = std::to_string(shortVal);
            pos += 2;
            uint8_t pesFlags = data[pos];
            if ((pesFlags >> 6) == 2) {
                pos++;
                int ptsDtsIndicator = (data[pos] >> 4) & 3;
                properties["PTS/DTS Indicator"] = std::to_string(ptsDtsIndicator);
                // ... (add more)
            }
        }
    }

    void printProperties() const {
        for (const auto& prop : properties) {
            std::cout << prop.first << ": " << prop.second << std::endl;
        }
    }

    void write(const std::string& filepath) const {
        if (!data.empty()) {
            std::ofstream file(filepath, std::ios::binary);
            file.write(reinterpret_cast<const char*>(data.data()), data.size());
        }
    }
};

// Usage example:
// int main() {
//     MpgHandler handler;
//     handler.read("example.mpg");
//     handler.printProperties();
//     handler.write("output.mpg");
//     return 0;
// }