DFA: Difference between revisions

From MultimediaWiki
Jump to navigation Jump to search
No edit summary
(name chunk #6, fix algo, add game)
Line 2: Line 2:
* Samples: [http://samples.mplayerhq.hu/game-formats/chronomaster-dfa/ http://samples.mplayerhq.hu/game-formats/chronomaster-dfa/]
* Samples: [http://samples.mplayerhq.hu/game-formats/chronomaster-dfa/ http://samples.mplayerhq.hu/game-formats/chronomaster-dfa/]


A DOS-based game called [http://www.mobygames.com/game/dos/chronomaster 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:
DFA is a FMV format used in PC games develped by DreamForge.
 
== File format ==
 
All multi-byte numbers are little endian. These files are comprised of chunks with the following format:


   bytes 0-3    chunk fourcc
   bytes 0-3    chunk fourcc
Line 12: Line 16:


   bytes 0-3    file signature: 'DFIA'
   bytes 0-3    file signature: 'DFIA'
  byte  4      version (= 0)
  byte  5      ? (output)
   bytes 6-7    number of frames
   bytes 6-7    number of frames
   bytes 8-9    frame width
   bytes 8-9    frame width
   bytes 10-11  frame height
   bytes 10-11  frame height
   bytes 12-15  frame rate
   bytes 12-15  frame rate
   bytes 16-19  ?
   bytes 16-19 first frame offset (= 0x80)
   bytes 20-127 unused
  bytes 20-23 ? (odirectory)
   bytes 24-127 unused


Chunk types include:
Chunk types include:
Line 27: Line 34:
   BDLT (type 4)    video frame, inter RLE-coded bytes
   BDLT (type 4)    video frame, inter RLE-coded bytes
   WDLT (type 5)    video frame, inter RLE-coded words
   WDLT (type 5)    video frame, inter RLE-coded words
        type 6     not occured in known samples
  TDLT (type 6)    not occured in known samples
   DSW1 (type 7)    video frame, inter LZ-coded
   DSW1 (type 7)    video frame, inter LZ-coded
   BLCK (type 8)    solid frame, fill whole frame with the first byte of payload
   BLCK (type 8)    solid frame, fill whole frame with the first byte of payload
Line 106: Line 113:
   }
   }


=== chunk type 6 ===
=== TDLT chunk ===
 
First four bytes code number of segments, each segment contains number of words to skip before decoding, number of words to copy and bytes to copy.


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.
  segments = getdword()
  while(segments--)
  {
    numcopy = getbyte()
    numskip = getbyte()
    output += numskip * 2
    output <- getbytes(numcopy * 2)
  }


=== DSW1 chunk ===
=== DSW1 chunk ===
Line 150: Line 166:
   }
   }


== Games using DFI ==
* [http://www.mobygames.com/game/anvil-of-dawn Anvil of Dawn]
* [http://www.mobygames.com/game/dos/chronomaster Chronomaster]
[[Category:Game Formats]]
[[Category:Game Formats]]

Revision as of 16:01, 5 April 2013

DFA is a FMV format used in PC games develped by DreamForge.

File format

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'
 byte  4      version (= 0)
 byte  5      ? (output)
 bytes 6-7    number of frames
 bytes 8-9    frame width
 bytes 10-11  frame height
 bytes 12-15  frame rate
 bytes 16-19  first frame offset (= 0x80)
 bytes 20-23  ? (odirectory)
 bytes 24-127 unused

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
 TDLT (type 6)    not occured in known samples
 DSW1 (type 7)    video frame, inter LZ-coded
 BLCK (type 8)    solid frame, fill whole frame with the first byte of payload
 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)
        get_buffer(cur_line_ptr, count);
    else
        memset(cur_line_ptr, get_byte(), -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;
 }

TDLT chunk

First four bytes code number of segments, each segment contains number of words to skip before decoding, number of words to copy and bytes to copy.

 segments = getdword()
 while(segments--)
 {
   numcopy = getbyte()
   numskip = getbyte()
   output += numskip * 2
   output <- getbytes(numcopy * 2)
 }

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. And report two bits read in any case.

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 <<= 2;
 }

Games using DFI