CNM: Difference between revisions

From MultimediaWiki
Jump to navigation Jump to search
m (→‎Container format: small fix)
(One intermediate revision by the same user not shown)
Line 42: Line 42:
== Video compression ==
== Video compression ==


Each frame is an independently compressed image (in bottoms-up format) split into 4x4 tiles.
Each frame is an independently compressed image (in bottoms-up format) split into tiles.
Frame header:
Frame header:
   4 bytes - payload size (not counting the header)
   4 bytes - payload size (not counting the header)
   4 bytes - offset to the colour data
   4 bytes - offset to the colour data
   2 bytes - number of tiles?
   2 bytes - number of tiles
   2 bytes - tile size?
   2 bytes - tile data size
   4 bytes - width
   4 bytes - width
   4 bytes - height
   4 bytes - height
Line 54: Line 54:
   3 bytes - unused?
   3 bytes - unused?


Colour data begins with 16 bytes containing string "ARXEL".
Colour data may contain either raw tile pixels (32-bit BGR0) or it may be packed. In that case tile data size is set to 4 or 2 and deltas stored right after it. Overall tile restoration algorithm is the following:
 
  copy 16 bytes (4x1 tile) from the stream
  for (tile = 1; tile < num_tiles; tile++) {
    tile_data[tile] = tile_data[tile - 1];
    bits = get_bits(3) + 1; //the same bit reading as below, bits=8 should not happen
    for (i = 0; i < 16; i++) {
      delta = get_bits(bits);
      if (delta && get_bit())
        delta = -delta;
      tile_data[tile][i] += delta;
    }
  }
 


Tile control data is compressed using variable amount of bits, bits are stored MSB first. Tile index is read depending on the number of tiles: if it can fit into 10 bits then it's ten bits, if it can fit into 11 bits then it's 11 bits, otherwise it's 12 bits.
Tile control data is compressed using variable amount of bits, bits are stored MSB first. Tile index is read depending on the number of tiles: if it can fit into 10 bits then it's ten bits, if it can fit into 11 bits then it's 11 bits, otherwise it's 12 bits.
Line 60: Line 73:
Single tile decoding flow:
Single tile decoding flow:


   if (getbit()) {
   if (!getbit()) {
     offset = get_bits(tile_index_bits);
     offset = get_bits(tile_index_bits);
     copy tile data from the colour data using offset*16
     copy tile data from the colour data using offset*16
Line 91: Line 104:
   001111 -  0,-5
   001111 -  0,-5


After decoding twice as many data it is somehow combined and converted into 32- or 24-bit image.
Actual image may be interlaced, i.e. only half of the lines are decoded.


[[Category:Game Formats]]
[[Category:Game Formats]]

Revision as of 04:16, 12 November 2022

CNM is a multimedia format used in the computer game Ring: The Legend of the Nibelungen.

Container format

Container has the following structure:

  • magic CNM UNR\0
  • header
  • frame offsets table (video and audio interleaved, audio offsets are zero when audio is not present)
  • frames

Header format (all values are little-endian):

 4 bytes - number of frames
 4 bytes - unknown
 1 byte  - unknown
 4 bytes - image width
 4 bytes - image height
 2 bytes - unknown
 1 byte  - number of audio tracks
 4 bytes - number of video frames?
 4 bytes - number of frames repeated?
 4 bytes - size of offsets table
 152 bytes - always zero?
 when audio is present for each track:
   1 byte  - number of channels
   1 bytes - bits per sample
   4 bytes - audio rate
   10 bytes - unused?

Each frame is prefixed by a byte containing its type. Known frame types:

  • 0x41 - audio data
  • 0x42 - audio data
  • 0x53 - image
  • 0x54 - some control marker
  • 0x5A - audio data

Audio data is PCM prefixed by 32-bit data size, video frames are reviewed below.

Video compression

Each frame is an independently compressed image (in bottoms-up format) split into tiles. Frame header:

 4 bytes - payload size (not counting the header)
 4 bytes - offset to the colour data
 2 bytes - number of tiles
 2 bytes - tile data size
 4 bytes - width
 4 bytes - height
 4 bytes - unknown
 4 bytes - unknown
 3 bytes - unused?

Colour data may contain either raw tile pixels (32-bit BGR0) or it may be packed. In that case tile data size is set to 4 or 2 and deltas stored right after it. Overall tile restoration algorithm is the following:

 copy 16 bytes (4x1 tile) from the stream
 for (tile = 1; tile < num_tiles; tile++) {
   tile_data[tile] = tile_data[tile - 1];
   bits = get_bits(3) + 1; //the same bit reading as below, bits=8 should not happen
   for (i = 0; i < 16; i++) {
     delta = get_bits(bits);
     if (delta && get_bit())
       delta = -delta;
     tile_data[tile][i] += delta;
   }
 }


Tile control data is compressed using variable amount of bits, bits are stored MSB first. Tile index is read depending on the number of tiles: if it can fit into 10 bits then it's ten bits, if it can fit into 11 bits then it's 11 bits, otherwise it's 12 bits.

Single tile decoding flow:

 if (!getbit()) {
   offset = get_bits(tile_index_bits);
   copy tile data from the colour data using offset*16
 } else { // copy existing tile
   decode motion vector, copy tile to which it points to
   (e.g. -1,0 means previous tile and 0,-1 means top tile)
 }

Motion vector codebook:

 1      -  0,-1
 0100   - -1, 0
 0101   - -1,-1
 0110   -  1,-1
 0111   -  0,-2
 000000 - -2,-3
 000001 -  2,-3
 000010 - -1,-4
 000011 -  1,-4
 000100 - -1,-2
 000101 -  1,-2
 000110 -  0,-3
 000111 -  0,-4
 001000 - -2, 0
 001001 - -2,-1
 001010 -  1,-1
 001011 - -2,-2
 001100 -  2,-2
 001101 - -1,-3
 001110 -  1,-3
 001111 -  0,-5

Actual image may be interlaced, i.e. only half of the lines are decoded.