PMM

From MultimediaWiki
Jump to navigation Jump to search

The game Krazy Ivan uses multimedia files with the extension .pmm. Carries encoded 15-bit video along with PCM or DPCM (never used) audio track.

File Format

File structure follows general RIFF format, but uses custom chunk names. All numbers are little endian.

File begins with 4 * 3 bytes catalog header:

u32 fourcc     -- "PIFF"
u32 filesize   -- not including fourcc and filesize fields
u32 filetype   -- "PXMT" /PXM Type?/

followed by chunks:

u32 fourcc             -- chunk FOURCC
u32 chunksize          -- not including fourcc and chunksize fields
u8  payload[chunksize] -- chunk data

PXMH chunk

/PXM Header?/ Carries general movie information.

u16 unknown0
u16 flags
u16 width           -- frame width in blocks
u16 height          -- frame height in blocks
u16 bwidth          -- block width (always 8)
u16 bheight         -- block height (always 8)
u16 framerate
u16 numframes
u32 maxframe        -- size of the largest BODY chunk
u8  descrition[32]
u16 audiofreq
u8  audiotype       -- audio compression format
u8  audiochnl
...                 -- the rest is unknown/unused

CPAL

8-bit palette. Obsolete.

MPAL

Palette? Obsolete.

BODY

Contains encoded vide frame. See below.

AUDO

Contains audio fragment. See below.

Video Compression

Vide is encoded as a series of bwidth x bheight blocks (typically, 8x8), which may further be divided in to smaller blocks. Pixel format is 15-bit RGB.

Video payload format:

 u16  codetable_ofs   -- offset of code table bitstream (inside the chunk)
 u16  pixels_ofs      -- offsets of pixels data (inside the chunk)
 ...
 u8   codetable[]     -- bitstream data, read bits from the lowest of each byte
 u8   pixels[]        -- encoded pixel data (bytes)

Compression is based on selective pixel color components change within the block. To decode single block:

1. Initialize last_pixel to 0
2. Read the 3-bits color_mask value. This is a bit mask, indicates which pixel components will be changed (bit 0 - Red, 1 - Green, 2 - Blue). Zero value indicates the whole block is unchanged.
3. Read next bit. If bit is zero, decode pixel and use it to draw the whole (sub)block; otherwise
4. If subblock size is 2, decode each pixel of subblock and draw it; otherwise
5. Split the (sub)block on to 4 equial subblocks and process recursively from step 3 (left-right-top-bottom.)


DecodePixel operates as follows:

1. Read next 8-bits pixel_data (from pixels[])
2. If high bit of pixel_data is set, pixel value is the next entry of pixels[] (lower part) combined with 7 bits of pixel_data (upper part.); otherwise
3. Color_index = value in bits 5-6 of pixel_data (0 - Blue, 1 - Green, 2 - Red, 3 - Skip), color_value = bits 0-4 of pixel_data. If color_index is Skip, assume pixel value is last_pixel. Otherwise, for each color component selected by color_mask, set it to color_value if it's the same component as specified by color_index, or if color_mask indicates no change of color_index component (this case is used to change two components at once.) Reuse all untouched components from last_pixel.
4. Set last_pixel to newly decoded pixel value.

Audio Compression

According to audiotype field, audio can be stored in the following formats:

Type 0 - PCM16

Raw 16-bit PCM samples.

Type 1 - Packed PCM16

Only high 8 bits of 16-bits sample stored. I.e. DecodedSample = data << 8.

Type 2 - DPCM

Decode a sample using the following DPCM table:

-32767,-30191,-27818,-25631,-23617,-21760,-20050,-18474,-17021,-15683,-14451,-13315,-12268,-11304,-10415, -9596,
 -8842, -8147, -7506, -6916, -6373, -5872, -5410, -4985, -4593, -4232, -3899, -3593, -3310, -3050, -2810, -2589,
 -2386, -2198, -2025, -1866, -1719, -1584, -1460, -1345, -1239, -1142, -1052,  -969,  -893,  -823,  -758,  -698,
  -643,  -593,  -546,  -503,  -464,  -427,  -393,  -363,  -334,  -308,  -283,  -261,  -241,  -222,  -204,  -188,
  -173,  -160,  -147,  -135,  -125,  -115,  -106,   -97,   -90,   -83,   -76,   -70,   -65,   -59,   -55,   -50,
   -46,   -43,   -39,   -36,   -33,   -31,   -28,   -26,   -24,   -22,   -20,   -19,   -17,   -16,   -14,   -13,
   -12,   -11,   -10,    -9,    -9,    -8,    -7,    -7,    -6,    -6,    -5,    -5,    -4,    -4,    -4,    -3,
    -3,    -3,    -2,    -2,    -2,    -2,    -2,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,     0,
     1,     1,     1,     1,     1,     1,     1,     1,     2,     2,     2,     2,     2,     3,     3,     3,
     4,     4,     4,     5,     5,     6,     6,     7,     7,     8,     9,     9,    10,    11,    12,    13,
    14,    16,    17,    19,    20,    22,    24,    26,    28,    31,    33,    36,    39,    43,    46,    50,
    55,    59,    65,    70,    76,    83,    90,    97,   106,   115,   125,   135,   147,   160,   173,   188,
   204,   222,   241,   261,   283,   308,   334,   363,   393,   427,   464,   503,   546,   593,   643,   698,
   758,   823,   893,   969,  1052,  1142,  1239,  1345,  1460,  1584,  1719,  1866,  2025,  2198,  2386,  2589,
  2810,  3050,  3310,  3593,  3899,  4232,  4593,  4985,  5410,  5872,  6373,  6916,  7506,  8147,  8842,  9596,
 10415, 11304, 12268, 13315, 14451, 15683, 17021, 18474, 20050, 21760, 23617, 25631, 27818, 30191, 32767, 32767