Escape 124

From MultimediaWiki
Jump to navigation Jump to search

ESCAPE 124 is a slightly enhanced version of Eidos Technologies' previous Escape 122 codec. It is usually found encapsulated in ARMovie files bearing the extension RPL. The most important difference is native 16-bits (15-bits, actually) color support. While general principles remain the same, a few new techniques have been added. For example, instead of coding 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 are usually grouped together in 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 the bits 23..26 of frame_flags is set. If none of them is set, just leave the 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 a 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 index depth from the stream
   codebook 1 size is 2^depth (power of)
   codebook1 = Unpack_Codebook()

 if bit 18 of frame_flags is set
   read 4 bits of codebook 2 index depth from the stream
   codebook 2 size is 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 index depth as the 1-based index of most significant bit of (size - 1)
   codebook3 = Unpack_Codebook()

Proceed the frame decoding:

 initialize codebook_index to zero

 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
         XOR next 4 bits of multi_mask by next 4 bits of 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 

 wrap codebook_index within 0..2 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