CNM: Difference between revisions

From MultimediaWiki
Jump to navigation Jump to search
mNo edit summary
(3 intermediate revisions by the same user not shown)
Line 4: Line 4:


CNM is a multimedia format used in the computer game [http://www.mobygames.com/game/windows/ring-the-legend-of-the-nibelungen Ring: The Legend of the Nibelungen].
CNM is a multimedia format used in the computer game [http://www.mobygames.com/game/windows/ring-the-legend-of-the-nibelungen Ring: The Legend of the Nibelungen].
== Container format ==
Container has the following structure:
* magic <code>CNM UNR\0</code>
* 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.


[[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.