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.1.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.1.0-py3-none-any.whl (8.1 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: dsi_muxer-1.1.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.1.0.tar.gz
Algorithm Hash digest
SHA256 1f827468bac2aaffa4c013e1af34eb9814b76b4598c8556aae15542bd5e65947
MD5 7f3d1003d2310bf5245a41c059938d9f
BLAKE2b-256 37497be87b99e5c7f36977dee6ec1567bfb6ca910ee54fd177c628045946f106

See more details on using hashes here.

File details

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

File metadata

  • Download URL: dsi_muxer-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 8.1 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.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bae0218e6c85d7e144591468e31fb6c95e795b17a090899aa69f8a1bd0afa02b
MD5 0e224eb09f8aee5385c80459bbd74bc3
BLAKE2b-256 5ba3eac3e3a9bde93e70f4a982cc2b897237282df17f29661ef43082d6f90703

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