CNM: Difference between revisions
mNo edit summary |
(→Video compression: typo) |
||
(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
- Company: Arxel Tribe
- Extension: cnm
- Samples: http://samples.mplayerhq.hu/game-formats/ring-cnm/
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.