DFA: Difference between revisions
(DFA information from REd decoder by VAG) |
No edit summary |
||
Line 25: | Line 25: | ||
DSW1 (type 7) video frame, inter LZ-coded | DSW1 (type 7) video frame, inter LZ-coded | ||
BLCK (type 8) black frame (fill all frame with zero) | BLCK (type 8) black frame (fill all frame with zero) | ||
DDS1 (type 9) | DDS1 (type 9) video frame, inter LZ-coded, double-scaled | ||
=== TSW1 chunk === | === TSW1 chunk === |
Revision as of 02:14, 9 March 2011
- Extensions: dfa
- Samples: http://samples.mplayerhq.hu/game-formats/chronomaster-dfa/
A DOS-based game called Chronomaster includes files with the extension .dfa which appear to be animation files. All multi-byte numbers are little endian. These files are comprised of chunks with the following format:
bytes 0-3 chunk fourcc bytes 4-7 chunk size, not including 12-byte preamble bytes 8-11 chunk type, essentially numeric equivalent of fourcc bytes 12.. chunk payload
A DFA file begins with a 128- (0x80-)byte header:
bytes 0-3 file signature: 'DFIA' bytes 4-127 unknown (mostly 0s)
Chunk types include:
EOFR (type 0) end of frame, empty chunk PAL1 (type 1) 768-byte chunk containing a 6-bit VGA palette components COPY (type 2) raw frame data TSW1 (type 3) video frame, intra LZ-coded BDLT (type 4) video frame, inter RLE-coded bytes WDLT (type 5) video frame, inter RLE-coded words type 6 not occured in known samples DSW1 (type 7) video frame, inter LZ-coded BLCK (type 8) black frame (fill all frame with zero) DDS1 (type 9) video frame, inter LZ-coded, double-scaled
TSW1 chunk
First four bytes store number of stripes to change, next four bytes - offset inside frame. The rest is stripe data.
Every stripe is coded with 16-bit LSB little-endian words in LZ77-like scheme:
mask = 0x10000; while (stripes--) { if (mask == 0x10000) { mask = 1; bitbuf = get_le16(); } if (bitbuf & mask) { v = get_le16(); offset = (v & 0x1FFF) * 2; count = ((v >> 13) + 2) * 2; memmove(cur_frame_pos, cur_frame_pos - offset, count); } else { *cur_frame_pos++ = get_byte(); *cur_frame_pos++ = get_byte(); } mask <<= 1; }
BDLT chunk
First two bytes code number of lines to skip in frame before decoding, next two bytes code number of lines to decode.
Every line is coded into segments, first byte of data tells how many segments are there. Every segment is coded as RLE, first byte tells how many pixels to skip before decoding segment, second byte is treated as signed value with sign telling if it's copy or run:
while (segments--) { cur_line_ptr += get_byte(); count = (int8_t)get_byte(); if (count >= 0) memset(cur_line_ptr, get_byte(), count); else get_buffer(cur_line_ptr, -count); cur_line_ptr += abs(count); }
WDLT chunk
First two bytes code number of lines to decode. Overall decoding is similar to BDLT chunk but with words copy instead of byte copy and different segment handling scheme:
while (lines--) { stripes = (int16_t)get_le16(); while (stripes & 0xC000) { *frame_ptr += -stripes * width; stripes = (int16_t)get_le16(); } if (stripes < 0) { frame_ptr[width - 1] = stripes & 0xFF; stripes = (int16_t)get_le16(); } line_ptr = frame_ptr; while (stripes--) { line_ptr += get_byte(); count = (int8_t)get_byte(); if (count > 0) { get_buffer(line_ptr, count * 2); line_ptr += count * 2; } else { val = get_le16(); for (i = 0; i < -count * 2; i++) { put_le16(line_ptr, val); line_ptr += 2; } } } frame_ptr += width; }
chunk type 6
First four bytes code number of segments, each segment contains number of bytes to skip before decoding, number of bytes to copy and bytes to copy.
DSW1 chunk
Almost the same as TSW1 chunk with the following differences:
- first two bytes code number of stripes
- if getbit() returned zero, get and test another bit. If that bit is zero too then read literal (two bytes), else read 2-byte number and skip corresponding number of pixels.
DDS1 chunk
Almost the same as DSW1 chunk but it decodes in scaled mode - every skip is twice that large, literal is used to set 2x2 block and copying also fills 2x2 block with pixel value:
mask = 0x10000; while (stripes--) { if (mask == 0x10000) { mask = 1; bitbuf = get_le16(); } if (bitbuf & mask) { v = get_le16(); offset = (v & 0x1FFF) * 2 * 2; count = ((v >> 13) + 2) * 2; for (i = 0; i < count; i++) { cur_frame_pos[0] = cur_frame_pos[1] = cur_frame_pos[width] = cur_frame_pos[width + 1] = cur_frame_pos[-offset]; cur_frame_pos += 2; } memmove(cur_frame_pos, cur_frame_pos - offset, count); } else if (!(bitbuf & (mask << 1)) { cur_frame_pos[0] = cur_frame_pos[1] = cur_frame_pos[width] = cur_frame_pos[width + 1] = get_byte(); cur_frame_pos += 2; cur_frame_pos[0] = cur_frame_pos[1] = cur_frame_pos[width] = cur_frame_pos[width + 1] = get_byte(); cur_frame_pos += 2; } else { cur_frame_pos += get_le16() * 2; } mask <<= 1; }