Zork PMV
- Extensions: PMV
- Decoder: [1]
This is a format used in MADE engine game Return to Zork.
Container format
Data is organised into chunks with 32-bit payload length following the 4-byte chunk identifier:
MOVE
- root chunkMHED
- headerMFRM
- frame chunk
Header contents:
2 bytes - delay between frames in milliseconds 4 bytes - always zero? 2 bytes - number of frames 4 bytes - always zero? 2 bytes - sample rate 44 bytes - unknown 16-bit words 768 bytes - palette
Frame chunk header:
8 bytes - unknown 4 bytes - audio data offset (from the chunk ID, not from payload start) 4 bytes - image data offset 4 bytes - palette data offset (if present)
Audio part header:
4 bytes - unknown 2 bytes - single chunk size in samples 2 bytes - number of chunks
Image part header:
4 bytes - image part size 4 bytes - unknown 2 bytes - width 2 bytes - height 2 bytes - block type data offset (from the image part start) 2 bytes - block types packed flag (0 or 1) 2 bytes - pixel data offset 2 bytes - pixel data packed flag (0 or 1) 2 bytes - mask data offset 2 bytes - mask data packed flag (0 or 1) 2 bytes - size of opcodes buffer for single image row (e.g. 20 for 320-pixel width)
Palette data starts with "PALT" and 32-bit data sized followed by updates telling at which offset and how many colours to update:
1 byte - number of colours minus one 1 byte - start colour N*3 bytes - colour data
FF FF
means end of palette data.
Frame data segments may be packed with simple RLE scheme signalled by the flag in the header. In that case positive byte value means number of byte to copy minus one and negative value means negated run length minus one (with the next byte being the colour value to repeat).
Video compression
Video is compressed using vector quantisation for 4x4 blocks with various data elements grouped together (command/block type, raw pixels, pixel masks).
Block types are stored in two-bit variables:
- 0 - fill block (read one pixels from the pixel data part and fill block with it)
- 1 - two-colour block (read 2 pixels from the pixel data part and 16-bit mask from the mask data part, arrange pixels using mask)
- 2 - four-colour block (read 4 pixels and 32-bit mask for sixteen 2-bit colour indices)
- 3 - skipped block
Masks are little-endian and read LSB first.
Audio compression
Each audio chunk starts with a byte telling how it should be decoded:
- bits 0-3 - compression type
- bits 6-7 - modifier (1 - decode every odd sample, linearly interpolate every even sample from them, 2 - decode and use for interpolation every fourth sample)
Compression types:
- 0 - zero output
- 1 - no change
- 2-4 - read 2/4/16 U8 samples to delta buffer, for every sample read 1/2/4-bit index, use corresponding delta value to update the previous sample with clipping
- 5 - raw unsigned 8-bit audio data