Z Video Format
The cutscenes in Z use JV files containing indexed-colour video, palette updates and sampled audio.
File format
| Offset | Data type | Name | Description |
|---|---|---|---|
| 0 | char[2] | signature | JV. |
| 2 | BYTE[78] | other header data | Not interpreted by jvInfo. |
| 0x50 | UINT16LE | width | Picture width. |
| 0x52 | UINT16LE | height | Picture height. |
| 0x54 | UINT16LE | frames | Number of index entries. |
| 0x56 | UINT16LE | frameMs | Frame interval in milliseconds. |
| 0x58 | BYTE[4] | unknown | Preserve. |
| 0x5c | UINT32LE | audioRate | Audio sample rate. |
| 0x60 | UINT8 | audioFlags | Bit 0 selects stereo; clear selects mono in the viewer. |
| 0x61 | BYTE[7] | unknown | Preserve. |
| 0x68 | ENTRY[frames] | index | 16-byte frame records. |
Frame index
| Offset | Data type | Name | Description |
|---|---|---|---|
| 0 | UINT32LE | size | Total frame payload size. |
| 4 | UINT32LE | audio | Audio byte count. |
| 8 | UINT32LE | video | Video block-stream count; see type 0 below. |
| 12 | UINT8 | palette | Nonzero: 768-byte palette update. |
| 13 | UINT8 | audio type | Zero supported; compressed audio rejected by viewer. |
| 14 | UINT8 | picture type | 0, 1 or 2. |
| 15 | UINT8 | unknown | Preserve. |
Payloads start immediately after the index, at 104 + frames*16. Each next payload starts after the preceding record's total size. Within a payload, audio comes first, then the optional six-bit RGB palette, then picture data.
Type 2 fills the picture with one byte. Type 1 decodes a block stream into the existing picture. In the repository implementation, type 0 first copies width*height raw pixels and then decodes the following video bytes as a block stream. A zero video count skips picture decoding. Do not use the video field alone as the total number of type-0 picture bytes.
Block stream
The implemented decoder supports 320×200 pictures, traversed as 40×25 blocks of 8×8. Bits are MSB first. Each block has a two-bit code: 0 keeps the previous pixels; 1 fills with a byte colour; 2 uses two byte colours and a bit mask; 3 splits into four smaller blocks in top-left, top-right, bottom-left, bottom-right order. At 2×2, code 3 instead stores four literal pixels.
A two-colour mask selects the second colour for set bits. For 8×8 blocks, two little-endian dwords are read: the second supplies the top four rows, the first the bottom four rows, each consumed MSB first. The 4×4 mask is a little-endian word consumed MSB first; a 2×2 mask is four stream bits.
Audio is unsigned eight-bit PCM in the supported path. Concatenate audio chunks in file order. Audio is front-loaded for streaming and is not independently aligned to the picture in each index record.
Notes
Previous pixels and the current palette persist between frames. Seeking requires decoding earlier frames or restoring a checkpoint. Entrance/exit fades are game effects and are not baked into source frames.
Source code
From re-z, the open-source browser port:
- src/viewer/formats.js – jvInfo
- src/viewer/jv.js – container reader and audio extraction
- src/game/jvdec.js – bit-exact block decoder
- src/game/jv.js – original film player
Credits
This file format was reverse engineered by VorticonCmdr. If you find this information helpful in a project you're working on, please give credit where credit is due. (A link back to this wiki would be nice too!)