Xilam DERF
- Extensions: adp, vdo, vds
- Company: Xilam Animation
- Samples:
DERF is a name given to both video and audio format in at least one game by Xilam Animation since they both start with that magic word. Audio is DPCM-based and video files employ 8x8 DCT blocks for image coding and the same DPCM audio coding.
All values in the files are little-endian.
Audio format
File header:
bytes 0-3 "DERF" bytes 4-7 number of channels (1 or 2) bytes 8-11 data size
Sampling rate is always 22050 Hz.
Audio is DPCM-coded with one byte for delta, stereo audio has deltas interleaved. Top bit means delta sign, low 7 bits are index in the delta table. Delta is added to the previous 16-bit sample value with overflow.
Delta table:
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0x10, 0x11, 0x13, 0x15, 0x17, 0x19, 0x1C, 0x1F, 0x22, 0x25, 0x29, 0x2D, 0x32, 0x37, 0x3C, 0x42, 0x49, 0x50, 0x58, 0x61, 0x6B, 0x76, 0x82, 0x8F, 0x9D, 0xAD, 0xBE, 0xD1, 0xE6, 0xFD, 0x117, 0x133, 0x151, 0x173, 0x198, 0x1C1, 0x1EE, 0x220, 0x256, 0x292, 0x2D4, 0x31C, 0x36C, 0x3C3, 0x424, 0x48E, 0x502, 0x583, 0x610, 0x6AB, 0x756, 0x812, 0x8E0, 0x9C3, 0xABD, 0xBD0, 0xCFF, 0xE4C, 0xFBA, 0x114C, 0x1307, 0x14EE, 0x1706, 0x1954, 0x1BDC, 0x1EA5, 0x21B6, 0x2515, 0x28CA, 0x2CDF, 0x315B, 0x364B, 0x3BB9, 0x41B2, 0x4844, 0x4F7E, 0x5771, 0x602F, 0x69CE, 0x7462, 0x7FFF
Video format
Video files also start with DERF
magic but they can be distinguished from audio files by the fact that the next field is total data size which should be greater than maximum channel count stored for audio files there.
File structure
File header:
bytes 0-3 "DERF" bytes 4-7 data size bytes 8-9 number of chunks in the file bytes 10-11 width bytes 12-13 height bytes 14-35 unknown/unused
After the file header a specified number of chunks follows.
Chunk header:
bytes 0-1 chunk type bytes 2-3 unknown bytes 4-7 chunk size including header bytes 8-15 unknown
Known chunk types:
FK
- keyframe chunkKB
- interframe chunkCM
- mono audio data (DPCM-encoded in the same way as audio file)CS
- stereo audio data
Video frame encoding
Video frames are coded as 8x8 blocks that may be split further down to 2x2 blocks for motion compensation or use DCT for coding block contents.
Frame structure:
bytes 0-3 block flags data offset bytes 4-7 coefficients data offset bytes 8-.. motion vector and extended coefficients data [block flags data] [coefficients data]
Block flags tell how to split block for motion compensation. They are grouped into 32-bit words MSB.
Coefficients data tell how to decode DCT coefficients and code small coefficient values. They are coded as nibbles packed into 32-bit words with low nibble first.
Block decoding proces:
void decode_block(int x, int y, int w, int h) { if ((w == 2 && h == 2) || get_flag()) { decode motion data or DCT } else if ((h == w * 2) || ((w == h) && get_flag())) { decode_block(x, y, w, h / 2); decode_block(x, y + h / 2, w, h / 2); } else { decode_block(x, y, w / 2, h); decode_block(x + w / 2, y, w / 2, h); } }
Motion data
Motion data is stored as 16-bit word with the following bit fields:
bits 13-15 motion mode bits 7-12 motion vector y component plus 31 bits 1-6 motion vector x component plus 31 bit 0 reference source (0 = previous frame, 1 = current frame)
Motion modes:
- 0 - copy block data
- 1 - copy block data flipped upside-down
- 2 - copy block data flipped right-left
- 3 - copy block data flipped both upside-down and right-left
- 4 - copy block data transposed
- 5 - copy block data flipped around antidiagonal
- 6 - copy block data transposed and flipped
- 7 - 8x8 block is DCT-coded
DCT block data
DCT-coded block has three 8x8 blocks with their coefficients coded interleaved and in zig-zag ordering (i.e. y0 u0 v0 y1 u1 v1 y8 u8 v8 ...
) using the following scheme (which is essentially "group zero/non-zero coefficients together and use nibbles to signal which to read and using which data size"):
dst_end = dst + 64 * 3; flags = get_nibble(); // nibbles come from coefficients data for (i = 0; i < 4; i++) { if (flags & (1 << idx)) *dst++ = get_byte_signed(); // comes from MV and ext coeffs data else *dst++ = get_16bit_signed(); // comes from MV and ext coeffs data } while (dst < dst_end) { mode = get_nibble(); // nibbles come from coefficients data switch (mode) { case 0: *dst++ = get_byte_signed(); break; // comes from MV and ext coeffs data case 1: *dst++ = get_nibble_signed(); break; case 2: while ((run = get_byte()) != 0) { while (run--) *dst++ = 0; *dst++ = get_byte_signed(); } break; case 3: while ((run = get_byte()) != 0) { while (run--) *dst++ = 0; *dst++ = get_nibble_signed(); } break; case 4: while ((run = get_nibble()) != 0) { while (run--) *dst++ = 0; *dst++ = get_byte_signed(); } break; case 5: while ((run = get_nibble()) != 0) { while (run--) *dst++ = 0; *dst++ = get_nibble_signed(); } break; case 6: len = get_nibble(); for (i = 0; i < (len >> 2) + 1; i++) *dst++ = 0; for (i = 0; i < (len & 3) + 1; i++) *dst++ = get_nibble_signed(); break; case 7: len = get_nibble(); for (i = 0; i < (len >> 1) + 1; i++) *dst++ = 0; for (i = 0; i < (len & 1) + 1; i++) *dst++ = get_nibble_signed(); break; case 8: len = get_nibble(); for (i = 0; i < (len >> 3) + 1; i++) *dst++ = 0; for (i = 0; i < (len & 7) + 1; i++) *dst++ = get_nibble_signed(); break; case 9: len = get_nibble(); for (i = 0; i < len; i++) *dst++ = get_nibble_signed(); break; case 10: while ((len = get_nibble()) != 0) { for (i = 0; i < len; i++) *dst++ = 0; *dst++ = get_16bit_signed(); } break; case 11: while ((len = get_byte()) != 0) { for (i = 0; i < len; i++) *dst++ = 0; *dst++ = get_16bit_signed(); } break; case 12: *dst++ = get_16bit_signed(); break; case 13-15: not present } }
Block is reconstructed by applying default IJG dequantisation, IDCT and YUV to RGB conversion.