Skip to main content

Racjin PS2 DSI container multiplexer/demultiplexer

Project description

DSI Muxer

Multiplexer/demultiplexer for the Racjin PS2 DSI container format.

If this helped you, consider buying me a coffee

DSI is a proprietary streaming container used by Racjin for PS2 cutscenes in games like:

  • Fullmetal Alchemist and the Broken Angel
  • Fullmetal Alchemist 2: Curse of the Crimson Elixir
  • Busin 0: Wizardry Alternative NEO

No DSI muxer existed before this tool. VGMToolbox could demux DSI files but not create them.

Install

pip install dsi-muxer

Usage

Command Line

# Extract video and audio from a DSI file
dsi-muxer demux M004.DSI --video M004.m2v --audio M004.adpcm

# Create a new DSI from video + audio (auto-calculates block count)
dsi-muxer mux --video subtitled.m2v --audio jp_audio.adpcm -o M004_new.DSI

# Or specify block count manually
dsi-muxer mux --video subtitled.m2v --audio jp_audio.adpcm --blocks 307 -o M004_new.DSI

# Show DSI file info
dsi-muxer info M004.DSI

Python API

from dsi_muxer import DSI
from dsi_muxer.container import ensure_end_of_sequence

# Demux
dsi = DSI.from_file("M004.DSI")
video = dsi.extract_video()   # MPEG-2 elementary stream
audio = dsi.extract_audio()   # PS2 SPU ADPCM

# Mux with proportional audio (for perfect A/V sync)
video = ensure_end_of_sequence(video)
new_dsi = DSI.mux(video, audio)  # auto block count
# or: DSI.mux(video, audio, nblocks=307)  # explicit
new_dsi.to_file("M004_new.DSI")

# Inspect
for block in new_dsi.block_info():
    print(f"Block {block['block']}: {block['frames']}f, "
          f"aud={block['audio_size']}, vid={block['video_size']}")

How It Works

The DSI Format

DSI files are divided into fixed 0x40000 byte (256 KB) blocks. Each block contains:

  • A 32-byte header identifying two streams (audio + video) with type tags and sizes
  • 32 bytes of zero padding
  • Interleaved audio and video data

Audio uses PS2 SPU ADPCM (44100 Hz, stereo, 0x100 interleave). Video is MPEG-2 Main Profile (512x448, 29.97 fps).

Proportional Audio Muxing

The key to perfect A/V sync in DSI is proportional audio distribution:

audio_per_block = frames_in_block * (total_audio / total_frames)

Blocks with more video frames get more audio. This ensures each block's audio duration matches its video duration. The PS2's SPU2 buffer smooths per-block variation.

The video is byte-sliced as a continuous stream — GOPs flow freely across block boundaries, just like the original game files. No per-block re-encoding or extra sequence headers.

Why This Matters

Unlike Sony's standard PSS format (which has timestamps for A/V sync), DSI has no timestamps. Sync is entirely determined by the audio/video ratio per block. Getting this ratio wrong causes audible desync during PS2 playback.

Format Reference

Block Header (32 bytes, little-endian)

Offset Type Field
0x00 uint32 Stream count (always 2)
0x04 uint32 Stream 1 offset (always 64)
0x08 int32 Stream 1 type (-8192=audio, -16384=video)
0x0C uint32 Stream 1 size
0x10 uint32 Stream 2 offset
0x14 int32 Stream 2 type
0x18 uint32 Stream 2 size
0x1C uint32 Reserved (always 0)

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dsi_muxer-1.3.0.tar.gz (11.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dsi_muxer-1.3.0-py3-none-any.whl (8.7 kB view details)

Uploaded Python 3

File details

Details for the file dsi_muxer-1.3.0.tar.gz.

File metadata

  • Download URL: dsi_muxer-1.3.0.tar.gz
  • Upload date:
  • Size: 11.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for dsi_muxer-1.3.0.tar.gz
Algorithm Hash digest
SHA256 238b4914540ba81593a331bbf5f56a1545b5084e9c03ee9c9973e38fc1ee3225
MD5 4af04352c5d16be1a61454de089fcbe2
BLAKE2b-256 bbe0703c2b22a9cdd5a89425afe7e25734ea3c9dc47d4466ea7d76defe7fc86f

See more details on using hashes here.

File details

Details for the file dsi_muxer-1.3.0-py3-none-any.whl.

File metadata

  • Download URL: dsi_muxer-1.3.0-py3-none-any.whl
  • Upload date:
  • Size: 8.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for dsi_muxer-1.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e85d9b6b0e690c27884c26e04ae196c0314b0d016bca92498ed49b290a01586a
MD5 468cb2cade4b3ef95688b96ecfab41ab
BLAKE2b-256 cd33cd3775ec19ee14b130d2117d89653d50591860c056a2763aa498be041562

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page