This page is based on the document 'Description of the Apple Video (rpza) Codec' by Roberto Togni found at http://multimedia.cx/rpza.txt.
RPZA also goes by the names "Apple Video" and "Roadpizza". The codec is a vector quantizer that operates in a 15-bit RGB555 colorspace.
The RPZA codec is used to compress frames in Apple QuickTime files (although it has been observed in AVI files as well). It's a computationally simple codec that operates on 4x4 pixel blocks using 15-bit RGB color values. Each chunk of data encodes a single frame. No data is shared between chunks.
Basics of RPZA Data and Decoding
All multi-byte values are stored in big-endian format.
An RPZA decoder renders 4x4 pixel blocks from left to right, top to bottom. The source data are 15-bit RGB values, stored as 16-bit words. The most significant bit of color values is either used as a flag or is ignored.
The first byte of a chunk is probably a flags byte. XAnim's comments seem to imply that this byte is always 0xe1. No other value has been observed in this byte. The meaning of this byte is unknown.
Bytes 2-4 comprise the length of the chunk. This value should match the value transported in the QuickTime file's video chunk length atom. After the first 4 bytes, an RPZA chunk contains a stream of opcodes and associated data. The length of the data varies depending on the opcode. The opcode is encoded into the next byte in the stream.
+--------+-----------+--------+---------+------//--+--------+---------+ | 1 byte | 3 bytes | 1 byte | # bytes | ... | 1 byte | # bytes | +--------+-----------+--------+---------+------//--+--------+---------+ | 0xe1 | chunk_len | opcode | data | ... | opcode | data | +--------+-----------+--------+---------+------//--+--------+---------+
opcode: only some bits of this field contain the opcode, the others are part of data field # : data length, depends on opcode. Can be 0.
Standard RPZA opcodes are stored in upper 3 bits (bits 7-5) of the opcode byte. There is also a special opcode where the upper bit (bit 7) is 0.
A standard opcode is made by an opcode value and a block counter. A single opcode can affect up to 32 4x4 blocks.
Standard opcode structure:
+-------+-------+ | 3 bit | 5 bit | +-------+-------+ | opc | blk | +-------+-------+ opc: opcode value blk: block counter -1 (add 1 to blk to get block counter)
0x80: Skip Blocks
This opcode instructs the decoder to skip blocks in the output frame. If there are 4x4 pixel blocks in the previous frame that are the same as in the current frame, there is no point in encoding the blocks again, so these opcodes allow the decoder to skip blocks.
No data field is used by this opcode.
0xA0: Single Color
This opcode instructs the decoder to paint the next n blocks the same color. The color to paint the block is encoded into data field.
Data field is 2 bytes long.
0xC0: 4 Colors With Index
This opcode specifies a quad of colors with which to paint the next n blocks. Two colors are stored in data stream. The remaining colors are computed by the decoder.
Data field is (4 + n*4) bytes long.
The decoder computes 4 color as follows:
- Get two color from data stream and call them colorA and colorB.
- Build the other two color using the following formula, applying it to each color component
- color0 = colorB
- color1 = (11 * colorA + 21 * colorB) / 32
- color2 = (21 * colorA + 11 * colorB) / 32
- color3 = colorA
As an example, red component of color 1 is
(11*Red_colorA+21*Red_colorB) >> 5
For each block to be rendered, there are 4 bytes (called a, b, c and d in this example) in the stream that are arrays of flags which specify which of the 4 colors in the selected pair will paint which pixels in the block. The flags are arranged as follows:
a76 a54 a32 a10 b76 b54 b32 b10 c76 c54 c32 c10 d76 d54 d32 d10
For example, if the lower 2 bits of byte a are 11 (3 decimal), then color 3 of the selected color quad is placed in the upper right corner of the block.
A special opcode is one in which the most significant bit of the opcode byte is 0. Decoder needs to check following bytes in the stream to decide what to do with the data. This class of opcodes affects only one 4x4 block.
This opcode is also the MSB of the two-byte value colorA, the LSB is the next byte from data stream.
The MSB of the next byte tells the decoder what to do:
- MSB is 1:
This opcode is the same as 0xC0 (4 colors with index), using colorA as computed above and entering opcode 0xC0 algorithm where it looks for colorB into the stream.
Data field is (1+2+4) bytes long.
- MSB is 0:
This opcode fills the next block with 16 different colors. The first color is colorA as computed above and the next 15 colors come from data stream.
The data field is (1+15*2) bytes long.
There is an unused value in standard opcode encoding space, 0xE0. I'm not sure if a chunk have to encode all blocks or it can skip last blocks if there is no need to encode them in current frame.