.VQA files by Aaron Glover (arn@ibm.net) Each VQA has a 62-byte header, as follows: VQAHeader: record TextFORM: array[0..3] of Char; {Always 'FORM'} FileBTF: LongInt; {Reverse - Bytes to follow} TextWVQAVQHD: array[0..7] of Char; {Always 'WVQAVQHD'} RStartPos: LongInt; {Reverse - Relative start position} Unknown1: Word; Unknown2: Word; NumFrames: Word; Width: Word; Height: Word; Unknown3: Word; Unknown4: Word; Unknown5: Word; Unknown6: Word; Unknown7: LongInt; Unknown8: Word; {This changes} Unknown9: Word; Unknown10: Word; Unknown11: array[0..13] of Char; end; Following the header, there are a number of `sub-files' that each have a header of 8 bytes. The first four are the name (or type) of the sub-file, the next four are a reverse LongInt that equals the number of sub-file data bytes to follow (sub-file size minus sub-file header size). By `reverse LongInt', I mean a 4-byte Integer value stored backwards. For example, take the the decimal value 77236. In hexadecimal it's 12DB4h, and would be stored in a binary file as the bytes B4 2D 01 00. As a reverse LongInt, it would be stored as 00 01 2D B4. More human readable, but not how computers work. Some sub-file names seem to start with a null byte (00h). There is a reason for this, which will become apparent later. Just ignore the null byte and assume the next one is the start of the sub-file header. So, after the header, you should find the something like the following sub-files: FINF SND2 SND2 VQFR SND2 VQFR SND2 VQFR SND2 VQFR ... Each VQFR sub-file itself has sub-files. If you treat each VQFR sub- file as if the `data bytes to follow' value was zero, you should get something like: FINF SND2 SND2 VQFR CBF0 CBP0 CPL0 VPTZ SND2 VQFR CBP0 VPTZ SND2 VQFR CBP0 VPTZ SND2 VQFR CBP0 VPTZ ... FINF sub-file type: First is a Word value that, if you multiply by two, gives the position of the first data sub-file (relative to the start of the VQA), then another Word value that seems to be always 4000h. Following that is an array of LongInt values that, when multiplied by two, give the position of each of the frame data sub-files (relative to the start of the VQA). Each frame comprises of a SND2 sub-file and a VQFR sub-file that follows immediately after. This is why some of the sub-file names start with a null byte. Since you have to multiply by two, each offset value must be even. So if it would normally be odd, a null is inserted as the first byte to make the sub-file's name offset even. Whew! Try saying that five times fast! The number of elements in the array is FrameNum (from the VQA header) minus one. I've noticed some of the LongInt values in this array are 40000000h too large. I don't know why this is, at the moment I subtract 40000000h from values over 40000000h, it seems to work OK. SND2 sub-file type: I bet you've guessed this one. Well, so did I. Audio, right? I've had a go at decoding them, and they seem to be in the same format as the .AUD files, but I can't work them out (yet). CBF0 sub-file type: An array of eight-byte (4x2 pixel) uncompressed screen graphics. I'll explain what they're used for when we get to the VPTZ sub-file type. Just remember that it's an array of graphics that measure 4x2 screen pixels. CBP0 sub-file type: Eight of these (in frame order) appended together make up a complete CBF0 sub-file that replaces the previous CBF0 sub-file information. After you've displayed each eighth frame, you need to replace the current CBF0 information with the new one you've made up from eight CBP0 sub-files. Just do it, OK? This will make more sense when we get to the VPTZ sub-file type. CPL0 sub-file type: The palette for the VQA file. An array of Red, Green and Blue byte values (in that order). Note that there are sometimes less than 256 colours in the palette. VPTZ sub-file type: Well, here it is. This is the heart of the VQA file, the graphics. Each VPTZ sub-file is compressed with the Format 80 method as described later in this document. When you decompress a VPTZ sub-file, you get an 80x156 graphic. The top half (the first 78 lines) is the basis of the finished frame, while the bottom half is a modifier for the pixels in the top half. The final size of each VQA frame is 320x156. With the top half (basis of the finished frame, remember) being 80x78, you can see that we need to multiply by four in the X (horizontal) direction, and by two in the Y (vertical) direction. Imagine that each pixel in the top half in fact represents eight screen pixels, arranged in a 4x2 format. I must distinguish between pixels and screen pixels. By pixel, I mean one byte read from the decompressed VPTZ graphic, which, when displayed on screen, measures 4x2 screen pixels. Now, if you view a VQA, you can see that there is a higher resolution used than each pixel being 4x2 screen pixels. This is where the bottom half and the CBF0 sub-file type comes in. The bottom half is an overlay of modifiers for the top half. That is, the top-left pixel in the bottom half is a modifier for the top- left pixel in the top half. The bottom half pixel values range from 00h to 0Fh. 0Fh means `no modifcation'. The corresponding pixel value in the top half is copied eight times to produce the 4x2 screen pixel format. 00-0Eh are modifiers. If you treat these pixel values as the high byte in a Word value, and treat the corresponding pixel value in the top half as the low byte, you get the CBF0 array element number of the 4x2 screen graphic you should display for that pixel. Make sense? That is how the higher resolution is achieved. Perhaps I should clarify. If TopByte is the top half pixel byte value, and BottomByte is the bottom half pixel byte value, then the 4x2 screen pixel graphic is element number (BottomByte * 256 + TopByte) in the CBF0 array. Just display the frames in order, and presto! You have a VQA movie.