CNM: Difference between revisions

From MultimediaWiki
Jump to navigation Jump to search
mNo edit summary
(fill information)
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  - audio present flag
  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:
    1 byte  - number of channels
    1 bytes - bits per sample
    4 bytes - audio rate
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 4x4 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 size?
  4 bytes - width
  4 bytes - height
  4 bytes - unknown
  4 bytes - unknown
  3 bytes - unused?
Colour data begins with 16 bytes containing string "ARXEL".
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
After decoding twice as many data it is somehow combined and converted into 32- or 24-bit image.


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

Revision as of 07:34, 11 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  - audio present flag
 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:
   1 byte  - number of channels
   1 bytes - bits per sample
   4 bytes - audio rate

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 4x4 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 size?
 4 bytes - width
 4 bytes - height
 4 bytes - unknown
 4 bytes - unknown
 3 bytes - unused?

Colour data begins with 16 bytes containing string "ARXEL".

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

After decoding twice as many data it is somehow combined and converted into 32- or 24-bit image.