Difference between revisions of "Karl Morton's Video Codec"

From MultimediaWiki
Jump to: navigation, search
m (Update samples link)
(Method 4 for block 16x16)
 
Line 125: Line 125:
  
 
[[Category:Game Formats]]
 
[[Category:Game Formats]]
[[Category:Incomplete Video Codecs]]
 
 
[[Category:Video Codecs]]
 
[[Category:Video Codecs]]

Latest revision as of 02:04, 15 March 2011

KMVC is used on various Worms PC games.

Common details

This codec operates on 8x8 or 16x16 blocks in 256 colors mode. This codec is also employs exotic bitstream reading: actually you need to read byte and when it's exhausted, read another byte, so flags and other data are very mixed. Two versions of this codec are known: one stores palette in frame, another one also could do this but stores palette in extradata instead. Compression principle is simple: divide frame into sequence of blocks and then either fill it, copy from other position or divide onto four subblocks and do the same.

Palette change frames

Newer version of KVMC has two palette change methods - via 'xxpc' (palette change) chunk in AVI and via special frames (some files has both!).

Frame header consists of two bytes, first one specifies palette start offset (usually 1 or 128) and the second byte is palette block size (= 127 colors). Legal frames have second byte (block size) equal to 8 (or possible 16) when this frames have 0x7F, so this is how they could be distinguished.

Next two bytes are zeroes, and the rest of frame data is 127 palette entries packed in 4-tuples.

Frame structure

Frame consists of the next parts: header byte, palette chunk (if needed), block size (1 byte), compressed blocks.

Header byte may have this bits set:

KPxx MMMM
K - is keyframe
P - palette is present
xx - unused bits
MMMM - compression method (only methods 3 and 4 are known)

Palette size is defined in byte 10 of extradata (usually 127 or rarely 255) and is standard R,G,B triplets. Compressed blocks are decoded with given method until frame is fully decoded.

Method 3 for block 8x8

This is method used in intraframes.

 if(!getbit()){
   val = getbyte();
   fill block 8x8 with val;
 } else {
   for all subblocks 4x4 {
     if(!getbit()){
       if(!getbit()){
         val = getbyte();
         fill block 4x4 with given val;
       } else {
         val = getbyte();
         mx = val & 0xF;
         my = val >> 4;
         copy block 4x4 from offset (-mx, -my)
       }
     } else {
       for all subblocks 2x2 (in subblock 4x4) {
         if(!getbit()){
           if(!getbit()){
             val = getbyte();
             fill block 2x2 with given val;
           } else {
             val = getbyte();
             mx = val & 0xF;
             my = val >> 4;
             copy block 2x2 from offset (-mx, -my)
           }
         } else {
           block[0,0] = getbyte();
           block[0,1] = getbyte();
           block[1,0] = getbyte();
           block[1,1] = getbyte();
         }
       }
     }
   }
 }

Method 4 for block 8x8

This method is used for interframes and has only two differences from method 3:

  • 8x8 block can be not only filled with given value or divided into subblocks but also can be skipped;
  • motion compensation uses previous frame for reference and has motion vactor range -8..7 instead of -15..0.
 if(!getbit()){
   if(!getbit()){
     copy block from previous frame unchanged
   }else{
     val = getbyte();
     fill block 8x8 with val;
   }
 } else {
   for all subblocks 4x4 {
     if(!getbit()){
       if(!getbit()){
         val = getbyte();
         fill block 4x4 with given val;
       } else {
         val = getbyte();
         mx = (val & 0xF) - 8;
         my = (val >> 4) - 8;
         copy block 4x4 from previous frame with offset (mx, my)
       }
     } else {
       for all subblocks 2x2 (in subblock 4x4) {
         if(!getbit()){
           if(!getbit()){
             val = getbyte();
             fill block 2x2 with given val;
           } else {
             val = getbyte();
             mx = val & 0xF;
             my = val >> 4;
             copy block 2x2 from previous frame with offset (mx, my)
           }
         } else {
           block[0,0] = getbyte();
           block[0,1] = getbyte();
           block[1,0] = getbyte();
           block[1,1] = getbyte();
         }
       }
     }
   }
 }

Method 3 for block 16x16

Extended method 3 for 8x8 blocks. There are no known samples to test.

Method 4 for block 16x16

Extended method 4 for 8x8 blocks. There are no known samples to test.