Bink Video

From MultimediaWiki
Jump to navigation Jump to search
  • FourCC: BINK (note that some FourCC lists assert that BINK is a FourCC for general-purpose multimedia containers; however, Bink data is always known to be encapsulated in a custom container format)
  • Company: RAD Game Tools
  • Samples: http://samples.mplayerhq.hu/game-formats/bink/, countless video games

Bink is a video codec that purports to use every video coding technique (DCT, FFT, Wavelet Coding, Vector Quantization, Motion Compensation) under the sun and used in a large number of computer and console games. The video is packaged in custom Bink files.

Each plane is coded separately. The Y plane is always coded first in each frame.

Format

Bitstream is read LSB from 32-bit little-endian words.

Frame is coded as three planes.

Each plane starts with Huffman codebooks: two 4-bit ones, one 8-bit (which really consists of seventeen (16 plus one special) 4-bit codebooks) and four 4-bit ones.

Huffman trees

There are 16 predefined Huffman trees, Bink frame only stores tree number and sophisticated coding of leaves values.

  • 4 bits - huffman tree type.

First tree is actually raw nibbles, so no additional data for it. For other trees leaves symbols should be coded.

  • 1 bits - symbols are coded explicitly (by selection)

If that flag is one, read 3 additional bits which determine number of symbols out of order, then read those symbols (4 bits per each symbol), the rest of symbols should go in normal order.

 Example:
 read  {5} [1] (3) <9> <1> <7>
 tree type: 5
 symbols order:  9  1  7  0  2  3  4  5  6  8  A  B  C  D  E  F

In other case symbols are coded by shuffling:

  • 2 bits - shuffle depth

First divide all symbols into pairs and read 1 bit for each pair to decide whether swap this pair or not.

 Example:
 original data:  (0 1)  (2 3)  (4 5)  (6 7) ...
 read bits:         0      1      1      0  ...
 output:         (0 1)  (3 2)  (5 4)  (6 7) ...

if shuffle depth is zero, end operation; otherwise perform merging.

 void merge(uint8_t *dst, uint8_t *src1, uint8_t *src2, int size)
 {
   int size1 = size, size2 = size;
   do{
      if(getbit()){
       *dst++ = *src2++;
       size2--;
     }else{
       *dst++ = *src1++;
       size1--;
     }
   }while(size1 && size2);
   while(size1--)
     *dst++ = *src1++;
   while(size2--)
     *dst++ = *src2++;
 }

If depth is one, divide symbols into pairs and merge neighbouring pairs (i.e. [0 1] and [2 3], [4 5] and [6 7], etc.) If depth is two, divide result into quartets and merge quartet 0 with quartet 1 and quartet 2 with quartet 3. For depth = 3 additionally divide result into two halves and merge them too.

Or, more clearly:

 depth = getbits(2);
 for (i = 0; i <= depth; i++) {
   int size = 1 << i;
   int skip = size * 2;
   for (j = 0; j < 16; j += skip)
     merge(tmp + j, symbols + j, symbols + j + size, size);
   memcpy(symbols, tmp, 16);
 }

Bundle reading

8-bit values are decoded with bundles. Bundle consists of 17 Huffman trees - one to decode upper 4 bits and 16 trees that are used to decode lower 4 bits. Those lower 4 bits are used as tree number to decode next low nibble.

Decoding

Block types

NOTE: This section is incomplete

0

Copy 8x8 block from previous frame to current frame

1

Divide block into subblocks and perform some operation on it:

0 - pattern fill
2 - "lossless" 4x4 IDCT
3 - fill
5 - masked fill

2

Copy 8x8 block from previous frame with some offset (previous motion vector?)

3

Fill 8x8 block with pattern 4 bits - pattern index 63 bits - pattern

4

"lossy"-coded DCT coefficients with motion vector

5

"losslessly"-coded DCT coefficients and 4 bits quantizer

6

Fill 8x8 block with one byte

7

"losslessly"-coded DCT coefficients and 4 bits quantizer and "motion"(in DCT code)

8

Fill block using masks

9

Copy 8x8 block from some other frame?