Skip to main content

Racjin PS2 DSI container multiplexer/demultiplexer

Project description

DSI Muxer

Multiplexer/demultiplexer for the Racjin PS2 DSI container format.

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
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, nblocks=307)
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.0.0.tar.gz (8.4 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.0.0-py3-none-any.whl (8.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: dsi_muxer-1.0.0.tar.gz
  • Upload date:
  • Size: 8.4 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.0.0.tar.gz
Algorithm Hash digest
SHA256 f7fbe4fbd950296bdd38c9d89da1fd8a12b86817aaf51c213224b4656066858c
MD5 35667d8a9a89a247060487742c5a67e9
BLAKE2b-256 59332200d746abb598cda2fab673bde14d942738973f50ca767e852389bdee63

See more details on using hashes here.

File details

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

File metadata

  • Download URL: dsi_muxer-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 8.0 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.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7119994c3ce85b8721aed442a0eb84f112be2f96845eae8bca692875f69fb074
MD5 c2e927b275dd03806700e60353625cc4
BLAKE2b-256 65ba371112693ff20505804dfb47cb9b10600c36a4ee00fd668aa1d616c4f9c7

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