Media & Movie Playback
Relevant source files
The following files were used as context for generating this wiki page:
Media and movie playback in Cyrus provides portable Smacker cinematic decoding, sequential packet management, and audio track synchronization. The system handles native Smacker files and CD-based movie assets from the original game installation.
Cinematic Architecture
The movie playback system utilizes a multi-threaded decoding architecture. The cyrus-media crate provides the low-level Smacker codec interface, while cyrus-startup manages the playback state and frame presentation.
Decoding Lifecycle
- Request: The system receives a
MovieRequestfor either a specific menu cinematic or the New Game introduction. - Preparation: The
MoviePlaybackresource spawns a task to prepare the movie source and metadata. - Decoding: A dedicated thread decodes Smacker packets into pixels and audio samples.
- Presentation: The main thread retrieves decoded frames and applies visual processing like vertical stretching and subtitles.
Sources: crates/cyrus-startup/src/movie.rs:55-75, crates/cyrus-media/README.md
The diagram shows the asynchronous flow from request to final rendering on the main thread.
Smacker Video Processing
Cyrus decodes Smacker frames as deltas and processes them for modern display. The original cinematics often use a 640×240 resolution intended for double-height display.
Frame Stretching
The stretch function converts 640×240 indexed frames into 640×480 RGBA buffers. It applies a vertical bilinear filter where sample centers are calculated as (y + 0.5) / 2 − 0.5. This process ensures visual fidelity when upscaling the original content.
Interlacing and Subtitles
If the user enables the interlace preference (value 505), the system blacks out every other horizontal line. Subtitles are painted directly onto the pixel buffer using the paint_subtitles function, which calculates line breaks and centers text based on the movie's defined subtitle font.
Sources: crates/cyrus-startup/src/movie.rs:136-158, crates/cyrus-startup/src/movie.rs:319-354
Audio Integration
Movie audio is handled via streaming sinks to maintain synchronization with video frames.
Cinematic Audio Synchronization
The system marks cinematic playback entities with the CinematicAudio component. This marker causes the cyrus-audio system to pause background CD music during the movie.
Audio Data Structures
| Field | Type | Description |
|---|---|---|
index | u8 | Zero-based track slot in the source movie. |
sample_rate | u32 | Frequency in Hz. |
channels | u16 | Number of audio channels (1 or 2). |
bits_per_sample | u16 | Sample depth (8 or 16). |
sample_frames | usize | Total number of frames in the track. |
Sources: crates/cyrus-assets/src/lib.rs:325-333, crates/cyrus-audio/README.md
Browser-Based Streaming
In WebAssembly environments, movie playback is implemented using the Web Audio API and Javascript-side streaming.
Packet Handling
The PacketAudio class in Javascript manages bounded PCM blocks. It tracks currentTime and readyState to ensure smooth playback despite network latency. The system uses an AbortController to cancel active downloads when a movie is skipped or closed.
This diagram illustrates the bridge between Rust decoding logic and browser audio hardware.
Sources: crates/cyrus-startup/src/movie_stream.js:3-85
Metadata and Playback Control
Movies are defined by structured metadata that includes skip points and subtitle timings.
MovieMetadata Schema
| Field | Description |
|---|---|
definition | Contains the movie name, skip keys, and subtitles. |
frames | Total frame count. |
frame_micros | Microseconds per frame (defines framerate). |
has_audio | Boolean flag indicating presence of audio tracks. |
font | The cyrus_text::Font used for rendering subtitles. |
Skip Points
The skip_point logic identifies the next authored "key" frame. When a user skips, the system swaps the current decoder for a prefetched decoder initialized at the target skip point. This prevents the need to decode all intervening frames, which are deltas.
Sources: crates/cyrus-assets/src/movie.rs:31-41, crates/cyrus-startup/src/movie.rs:160-162, crates/cyrus-startup/src/movie.rs:250-275
Asset Viewer Integration
The cyrus-viewer application provides a UI for inspecting movie files. It allows developers to browse movie definitions, select audio tracks, and control playback parameters like volume and looping.
Viewer UI Controls
- Audio Track Selection: Users can choose between multiple audio tracks present in the Smacker container.
- Playback Transport: Controls for play, pause, stop, and seeking through the timeline.
- Decoding Status: The UI displays status messages like "Decoding movie frames..." during seeks or high-latency loads.
Sources: crates/cyrus-viewer/src/ui.rs:590-645, crates/cyrus-assets/src/runtime/prepare.rs:528-568
Summary
The Media & Movie Playback system ensures that original Smacker cinematics are reproduced faithfully across platforms. By combining asynchronous decoding threads with portable pixel stretching and subtitle rendering, the system maintains high performance while preserving the aesthetic of the original game's movies.