Karl Morton's Video Codec

From MultimediaWiki
Revision as of 22:17, 2 April 2006 by Multimedia Mike (talk | contribs) (promote from undiscovered -> incomplete)
Jump to navigation Jump to search

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.

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

[TODO]

Method 4 for block 16x16

[TODO]