Escape 124
The ESCAPE 124 codec is a slightly enhanced version of Eidos' previous [Escape 122] codec. Most important difference is the native 16-bits (15-bits, actually) color support. While general codec principle remains the same, few new techniques has been added. For example, instead of coding of each color triplet, they all are stored in several lookup tables (think about VQ or huge palette).
Each frame chunks begins with a new 8-bytes header:
dword frame_flags - frame flags, must be passed to the decoder dword frame_size - size of the frame chunk, including this header
In the available sample files, frames usually grouped together in to one-second bundles, followed by sound stream (i.e., 15 fps movie will have 15 frames in a row, then 1 sec of sound data.) Original decoder throws away any frames whose frame_flags has no bits 2, 4 or 8 set ( & 0x114 ).
Video portion
At first, you need to check if any of bits 23..26 of frame_flags is set. If none of them is set, just leave last decoded frame unchanged. (These bits are specific to 124 decoder, unlike bits 2, 4, 8, described above).
Next, unpack 3 codebooks. Each codebook contains variable number of 2x2 macroblocks. You should maintain all three codebooks between frames.
if bit 17 of frame_flags is set read 4 bits of codebook 1 indice depth from the stream codebook 1 size is the 2^depth (power of) codebook1 = Unpack_Codebook() if bit 18 of frame_flags is set read 4 bits of codebook 2 indice depth from the stream codebook 2 size is the 2^depth (power of) * total number of superblocks in the frame codebook2 = Unpack_Codebook() if bit 19 of frame_flags is set read 20 bits of codebook 3 size from the stream evaluate codebook 3 indice depth as the index of most significant bit of size codebook3 = Unpack_Codebook() initialize codebook_index to zero
Proceed the frame decoding:
repeat skip_value = RICE_Decode() skip skip_value number of 8x8 superblocks (keep them unchanged from the last frame) if all blocks drawn/skipped finish multi_mask = 0 while next bit of the stream is zero new_block = Decode_MacroBlock() mask = read 4*4 (number of macroblocks in superblock) bits multi_mask = multi_mask or'ed with mask for each macroblock of superblock (left to right, top to bottom) if corresponding bit of mask (see below) is set macroblock = new_block if next bit of the stream is zero inv_mask = read 4 bits from the stream for each bit of inv_mask (from low to high) if bit is set invert next 4 bits of multi_mask else read next 4 bits of multi_mask from the stream for each macroblock of superblock (left to right, top to bottom) if corresponding bit of multi_mask (see below) is set macroblock = Decode_MacroBlock() else if bit 16 of frame_flags is set while next bit of the stream is zero new_block = Decode_MacroBlock() block_index = read next 4 bits from the stream set macroblock block_index of superblock to new_block advance to the next superblock
Superblock's macroblock bit mask matrix (in hex):
---- ---- ---- ---- | 1| 2| 10| 20| ---- ---- ---- ---- | 4| 8| 40| 80| ---- ---- ---- ---- | 100| 200|1000|2000| ---- ---- ---- ---- | 400| 800|4000|8000| ---- ---- ---- ----
Decode_Macroblock selects 2x2 macroblock from one of codebooks:
if next bit of stream is set if next bit of stream is set decrement codebook_index else increment codebook_index clamp codebook_index within 0..3 range if codebook_index is 0 macroblock = codebook2[superblock_index * 2^depth + next codebook 2 depth bits of the stream] else if codebook_index is 1 macroblock = codebook1[next codebook 1 depth bits of the stream] else macroblock = codebook3[next codebook 3 depth bits of the stream]
Unpack_Codebook loads macroblocks codebook:
for each macroblock of codebook read 2*2 (number of pixels in macroblock) mask bits from the stream read 5+5+5 bits of color0 RGB triplet read 5+5+5 bits of color1 RGB triplet for each pixel of macroblock (left to right, top to bottom) if next bit of mask (from low to high) is set pixel = color1 else pixel = color0