Midivid: Difference between revisions

From MultimediaWiki
Jump to navigation Jump to search
m (typo)
(document MidiVid)
Line 1: Line 1:
* FourCCs: MV43, MVDV
* FourCCs: MV43, MVDV, MVLZ
* Company: BlackBox Games
* Company: BlackBox Games
* Website: http://midivid.com/
* Website: http://midivid.com/
Line 7: Line 7:


Midivid is a video codec developed by Jason Dorie of BlackBox Games (later acquired by [[Electronic Arts]]). It reportedly has a lot in common with MPEG-2, while claiming better compression ratios than MPEG-2.
Midivid is a video codec developed by Jason Dorie of BlackBox Games (later acquired by [[Electronic Arts]]). It reportedly has a lot in common with MPEG-2, while claiming better compression ratios than MPEG-2.
== MidiVid ==
First version of MidiVid codec uses LZSS compression, vector quantisation and simple hold-and-modify approach.
Frame header (all data is little-endian):
* 32-bit frame size (can be not set)
* 32-bit always zero?
* 32-bit uncompressed flag (1 means the rest of frame is compressed with LZSS)
Frame data:
* 16-bit number of vectors
* 16-bit intra frame flag (i.e. no update mask present)
* (inter only) 32-bit number of blocks to update
* (inter only) update mask - one bit per each 4x4 block
* vector data (each vector is 2x2 YUV block without any subsampling, so 12 bytes per each vector)
* (for frames with more than 256 vector) top index bits
* index bits (one byte per each 2x2 block)
Decoding process:
  num_vecs = get16le(src); src += 2;
  is_intra = get16le(src); src += 2;
  if (is_intra) {
    num_blocks = (w / 2) * (h / 2);
  } else {
    num_blocks = get32le(src); src += 2;
    update_mask = src;
    src += (w >> 5) * (h >> 2);
  }
  vec_data = src;
  src += num_vecs * 12;
  if (num_vecs <= 256)
    indices = src;
  else {
    idx9data = src;
    indices = idx9data + (num_blocks + 7) / 8;
  }
 
  idx9bits = 0;
  idx9val = 0;
  for (y = 0; y < h; y += 2) {
    for (x = 0; x < w; x += 2) {
      if (!is_intra && update mask bit set for x/4,y/4 block)
        continue;
      if (num_vecs <= 256) {
        idx = *indices++;
      } else {
        if (idx9bits == 0) {
          idx9val = *idx9data++;
          idx9bits = 8;
        }
        idx9bits--;
        idx = *indices++ | (((idx9val >> (7 - idx9bits)) & 1) << 8);
      }
      output vec[idx] as 2x2 block;
    }
  }
=== LZSS Algorithm ===
It's the straightforward implementation. First you have 16-bit flags and then literals or matches:
  for (;;) {
    op = src[0] | (src[1] << 8);
    src += 2;
    for (i = 0; i < 16; i++) {
      if no data left { return; }
      if (op & 1) {
        offset = ((src[0] & 0xF0) << 4) | src[1];
        length = (src[0] & 0xF) + 3;
        src += 2;
        for (j = 0; j < length; j++)
          dst[j] = dst[j - offset];
        dst += length;
      } else {
        *dst++ = *src++;
      }
      op >>= 1;
    }
  }
== MidiVid Lossless ==
== MidiVid 3 ==


== Games Using Midivid ==
== Games Using Midivid ==

Revision as of 03:41, 1 October 2019

Midivid is a video codec developed by Jason Dorie of BlackBox Games (later acquired by Electronic Arts). It reportedly has a lot in common with MPEG-2, while claiming better compression ratios than MPEG-2.

MidiVid

First version of MidiVid codec uses LZSS compression, vector quantisation and simple hold-and-modify approach.

Frame header (all data is little-endian):

  • 32-bit frame size (can be not set)
  • 32-bit always zero?
  • 32-bit uncompressed flag (1 means the rest of frame is compressed with LZSS)

Frame data:

  • 16-bit number of vectors
  • 16-bit intra frame flag (i.e. no update mask present)
  • (inter only) 32-bit number of blocks to update
  • (inter only) update mask - one bit per each 4x4 block
  • vector data (each vector is 2x2 YUV block without any subsampling, so 12 bytes per each vector)
  • (for frames with more than 256 vector) top index bits
  • index bits (one byte per each 2x2 block)

Decoding process:

 num_vecs = get16le(src); src += 2;
 is_intra = get16le(src); src += 2;
 if (is_intra) {
   num_blocks = (w / 2) * (h / 2);
 } else {
   num_blocks = get32le(src); src += 2;
   update_mask = src;
   src += (w >> 5) * (h >> 2);
 }
 vec_data = src;
 src += num_vecs * 12;
 if (num_vecs <= 256)
   indices = src;
 else {
   idx9data = src;
   indices = idx9data + (num_blocks + 7) / 8;
 }
 
 idx9bits = 0;
 idx9val = 0;
 for (y = 0; y < h; y += 2) {
   for (x = 0; x < w; x += 2) {
     if (!is_intra && update mask bit set for x/4,y/4 block)
       continue;
     if (num_vecs <= 256) {
       idx = *indices++;
     } else {
       if (idx9bits == 0) {
         idx9val = *idx9data++;
         idx9bits = 8;
       }
       idx9bits--;
       idx = *indices++ | (((idx9val >> (7 - idx9bits)) & 1) << 8);
     }
     output vec[idx] as 2x2 block;
   }
 }

LZSS Algorithm

It's the straightforward implementation. First you have 16-bit flags and then literals or matches:

 for (;;) {
   op = src[0] | (src[1] << 8);
   src += 2;
   for (i = 0; i < 16; i++) {
     if no data left { return; }
     if (op & 1) {
       offset = ((src[0] & 0xF0) << 4) | src[1];
       length = (src[0] & 0xF) + 3;
       src += 2;
       for (j = 0; j < length; j++)
         dst[j] = dst[j - offset];
       dst += length;
     } else {
       *dst++ = *src++;
     }
     op >>= 1;
   }
 }

MidiVid Lossless

MidiVid 3

Games Using Midivid