Midivid
Jump to navigation
Jump to search
- FourCCs: MV43, MVDV, MVLZ
- Company: BlackBox Games
- Website: http://midivid.com/
- Samples:
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; } }