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:
- https://filesamples.com/samples/video/mpg/sample_960x400_ocean_with_audio.mpg
- https://filesamples.com/samples/video/mpg/sample_1280x720_surfing_with_audio.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;
// }