Archive for the ‘Game Video’ Category

Yet another FLI flavour

Wednesday, September 2nd, 2026

There’s an Argentinian game called La Mágica Aventura del Cine or (The Magical Movie Adventure in English language release) which has animations in ordinary and custom FLI format. The files are hidden inside large resource files along with .voc and other types with no obvious index (probably it is stored in accompanying .lod file which was not useful even after I uncompressed it). Anyway, custom FLIs have marker 0xAF66 with chunk types 110 (contiguous VGA palette) and 100 (LZ77-compressed frame). I’ve added support for it to na_game_tool but, like with Cross Racing Championship RoQ files, I won’t count it towards the total number of formats supported.

What’s curious is the compression scheme employed here. It is slightly more complex than classic LZSS since it has more modes of coding offset and length (8/13-bit offsets, 2/3/8/16-bit lengths). Nothing special but it looks almost the same as the compression employed in HNM except for one bit meaning inverted, LSB bitstream reading and large lengths handling. And like HNM there are two slightly different variants of the compression method used here as well: ordinary compressed files seem to use the version with 16-bit flags while frames (and some other, probably also image, formats) employ the version with 32-bit flags. I somewhat wonder if there was a widespread version of this particular compression format that got adapted by two different companies in the same way as LZSS.c from Haruhiko Okumura (which is so common that I often recognise the format even without looking at the binary specification).

In either case it’s time to move on, there are still two or three formats left to RE and implement for the na_game_tool release.

Knowledge Adventure movie v2/v3 done

Monday, August 31st, 2026

I’ve finally finished adding Knowledge Adventure movie v2/v3 support to na_game_tool—just a couple of formats more and I can make a release.

Meanwhile I want to talk about what I discovered.

First of all, the original format still looks too hard to implement, mostly because of its incomprehensible binary specification. With all known samples employing arithmetic coding if you get one thing wrong you won’t get any thing right.

Let’s jump to version 3. As it turned out, it is not a movie file per se but rather an archive containing interleaved chunks of version 2 movie format and optionally an audio track. It even stores the original file names in the header. What’s curious is that version 2 supports embedded audio track just fine.

So now the most interesting part left. Version 2 movies as I described in the previous post use static Huffman coding for multiple streams (like mode bytes, motion vector indices, colours and such). The main thing I didn’t understand back then was its pattern mode: apparently the decoder keeps track of two significant colours used by all blocks in the line (e.g. last column of the raw block, or last pixel of each motion-compensated sub-block, or two colours used in a pattern block) and may re-use them from a neighbouring block for a pattern fill.

There are also some other fun things, like older games using transposed images (i.e. it’s coded as columns in left-to-right mode) while newer games use bottom-to-top coding. And single images are often coded as a sequence of strips (e.g. first you have strip 132 pixels wide, next to it a strip 128 pixels wide and so on until the whole image is decoded).

Actually there are many feature flags in the play there, I’ve ended up implementing just the most common modes and giving up on more complex ones. At least it works on the majority of the files I tried (including the ones extracted from older and newer Knowledge Adventure archive formats—of course na_game_tool supports extracting from them now). The format will be documented shortly after the release (because it’s a thing I usually do when I have nothing better to do) so those willing to do it better will have both the code and the description to work from.

Meanwhile I’ll just chase another pair of some game codecs for completeness sake, make the release, and move to implementing a different multimedia tool…

SBV, an unusual game codec

Monday, August 24th, 2026

While I’m still preparing next na_game_tool release (still a couple of codecs to RE and implement!), I’ve finally encountered a very rare beast—wavelet game video codec!

Gunmetal features SBV format with the minimum header (frame table contains just timestamps and start offsets) but each of those frames is coded using fast wavelet coding algorithm. First level is transmitted as byte values, the other levels are coded in 4×4 or 8×8 blocks, one level after another, using fixed-bits non-zero coefficient coding (the number of bits depends on the block coding mode) plus some bit flags to code zero runs. (De)quantisation is done by simple shift operation. Wavelet looks like the traditional LGT 5/3.

One might think the scheme is truly scalable but unfortunately you have to decode data for one plane before you move to another. Speaking of planes it’s a simplified YUV-like scheme with
Y = ( R + G + B) / 3
Cr = (2R - G - B) / 3,
Cb = (2B - R - G) / 3

with the traditional 4:2:0 sub-sampling.

This could’ve been a simple intermediate video codec for the cases where you’re really strapped for CPU power but still want some compression. And yet it’s a game format instead… I’m still delighted to encounter such format in a game (and in general).

Again on Knowledge Adventure MOV

Friday, August 14th, 2026

While I have time I’m preparing the next release of na_game_tool, which involves REing formats (of course!). And among the formats I want to add is Knowledge Adventure MOV. So I’ve revisited it and RE’d one of the flavours.

Apparently there are three versions of that MOV: the original format used in DOS games (with magic KAMv), version 2 (starting with LzH2) and version 3 (starting with LzH3) which seem to be used in both DOS games and some Internet applications (and I’ve used Mac binary for Undersea Adventure). So while I’m yet to progress on KAMv (because there’s only 16-bit DOS binary specification for it), I’ve mostly REd LzH2 and it’s rather crazy.

This codec splits image into rows of 4×2 tiles and unless I’m mistaken those rows are coded in scalable way (first just one row, then two, then four, then eight and so on until the whole frame is decoded). Each tile may be coded as motion (with a set of motion vectors selectable in the file header—it gives me flashbacks of DiVX 3 Hi/Lo-motion), raw tiles, or pattern-coded tiles. And those pattern-coded tiles actually may code colours explicitly or use another motion vector to re-use some existing ones, that’s not something I’ve seen before. Afterwards all those kinds of data (tile types, colours, patterns, motion vector indices) are grouped and compressed with their own static Huffman codes; the tree descriptions (just code lengths as the symbols are always the same) are transmitted at the beginning of each frame.

Overall, it reminds me of Smacker if not for the fact it uses per-frame Huffman trees instead of global ones (and raw PCM instead of Huffman-compressed data), smaller tiles and more ingenious use of motion vectors. Now I want to implement a decoder for it even if just to see what I understand wrong.

MOVing Puzzles

Sunday, June 14th, 2026

Mostly because of the weather I have not been in mood to work on anything serious for weeks, but here is something rather interesting.

Apparently there are some CD-ROMs represented on discmaster titled “Moving Puzzle: …” that have some .mv files (inside media.pak archive) that supposedly give motion to those puzzles. And of course somebody had to look at the format.

Obviously the format was inspired by QuickTime as it has the header with all those chunks defining per-track data including e.g. sample-to-chunk mapping. There are two main differences though: the format is flat as first you have header size and header chunks following each other without any nesting (so when you encounter the second track header chunk the following chunks will belong to this new track); and the data is little-endian there, both numbers and tags (e.g. “ssiz” which is sample sizes chunk is written as “ziss” instead, same for e.g. codec IDs). Luckily I could ignore most of it as the data seems to be stored without gaps, so reading palette, then seeking to the first video chunk and reading individual samples(frames) from there works fine.

And it has its own two codecs, RLE and LZSS. RLE has two modes, both coded the same but inter mode storing the difference from the previous frame (not even XOR, simple subtraction by modulo). LZSS is not the usual flavour either. Unlike the most widespread scheme of “read 8/16/32-bit flags, treat the following bytes until next flags as either literals or packed 16-bit LZ offset+copy length combination” here it is a continuous bitstream with offset and length bits being signalled in the bitstream header and offset zero being used to skip decoded data (since you decode to the frame buffer, it leaves some bytes of it unchanged). Nothing groundbreaking but you most implementations hardly make any changes from the original LZSS.C and right now I can only think of JAM format which implemented LZSS with copying from the reference picture.

IMO this is an over-engineered system but that’s what makes it interesting to look at.

Quickly about Factor 5 VID 1

Friday, April 24th, 2026

Yes, calculating that results in VID5 but in reality it’s MPEG-4 part 2 (minus some parts). Paul has asked me to look at it some time ago, so I did (which is much better than implementing a decoder for it).

As I said already, this is essentially MPEG-4 part 2 with some insane parts being cut off (but not enough to turn it back into ITU H.263): there’s no support for special texture shapes, interlacing or even quarterpel motion compensation. There are still B- and S-frames to complicate things though. Bitstream format is cut down as well to remove most of the nonsense (or omgFFeatures if you have that view), so there are just frames containing basic header (or slightly less basic with GMC and S-frames) plus macroblock data. Macroblock data is almost identical to the expected format—they even still have sync pattern handling in MCBPC despite there being no need for that.

So on the one hard writing decoder for it is not that hard, as you can simply hack an existing decoder for that, and hard enough at the same time (because you either need to hack an existing decoder or implement it yourself and that ISO standard is not easy to comprehend and personally I decided not to touch S-frames at all and if the need arises I’m actually considering making a wrapper for xvidcore instead).

Meanwhile I still have MVS to document and lots of encoders to write to make use of my new palettiser (because so far I have just three codecs that can encode paletted formats—two of them are for AVI, one is GIF, and none are for MOV). So hopefully I’ll have something more interesting to write about next time.

na_game_tool: final stretch before 0.5.0

Thursday, January 15th, 2026

As I’m somewhat tired with na_game_tool development (for now), so I’m just picking bits for the release goal to do that and switch to something else (I’ve found a couple of interesting MOV files to analyse, maybe I can improve my Indeo 3 encoder and such). I’ve added support for HNM5 and HNM6 formats, reached the self-imposed limit of at least twelve original decoders and essentially I need to add 7th Level archive format and that’s it. Meanwhile I can talk about the formats I added support for, I want to add support for (but not right now) and the formats I’m hesitating to add support for.

So, supported formats first.

There’s GRN format used in Genesia game. Frames are stored raw, compressed with RLE (which looks a lot like FLI delta RLE compression but working on pixel pairs) and the data may optionally be compressed with LZSS afterwards. And if would’ve not been a format from French company without some weirdness. In this case audio stream data is interleaved with video in the simplest way: first you have 2kB header, then a certain number of 2kB sectors with initial audio data (the number is in the header), then it is 8kB of video stream followed by 2kB of audio followed by 8kB of video stream etc etc. So video frame data may suddenly have 2kB of audio inside it. Of course it was easily solved with a custom de-interleaver but you’d expect it to see in industry-standard applications and not in a game from early 1990s.

And there’s MGIF from Gates of Skeldal. Despite the name it was only inspired by GIF in the sense it uses similar LZW compression scheme but not the format (unlike HAF). Another curious detail that I haven’t seen elsewhere is using a simple pre-processing: bytes are coded as a difference to the previous ones. What made it annoying is that this prediction resets when LZW decoder resets (i.e. when the “reset dictionary” code is encountered), so you have to implement it inside LZW decompressor instead of making a pass afterwards. Still, it gets a point for the originality.

Finally there is Celestial Impact intro.dxv. This file employs RLE to compress not merely image but its palette and some additional data (it did not look like a sound to me and I have no idea what it is) as a single array.

Now for the formats I want to support in some (distant) future. Beside the usual “whatever I can find” it definitely includes AVI and SMS—two Smacker-based formats. Maybe I can implement some Cinepak-based console formats while at it.

And speaking of console formats, here’s a fun format called DDV and used in Oddworld games (or maybe just one of them). There’s a reverse-engineered implementation of the decoder and by the look of it this format encapsulates MDEC—which makes it a perfect candidate for librempeg. It has support for some MDEC-based formats already after all.

That’s it, hopefully the next post will be about the release already.

na_game_tool: more FLICy formats

Saturday, December 27th, 2025

I’ve added another bunch of formats to na_game_tool, including both old video formats and game archive support to extract some of those (and other) formats from.

For example, I’ve finally added an extractor for Conquest Earth WAD with its 16-bit FLH (a variant of FLI with RNC compression; it has been supported since version 0.2.0) but there are other variants that justify this post title:

  • Alien Virus animation—almost standard FLI with changed tag and some jitter in subchunk sizes (i.e. they may be a byte too short or a byte too long compared to the chunk size);
  • Bureau 13—here it is a super-format with chunks comprising FLI headers, FLI chunks or PCM audio—and it may be several FLIs with different resolution too. And it is put into its own archive format (which I also added an extractor for);
  • C13 for Hammer of the Gods—at first I thought it’s just yet another hack of the format but after looking closer at the data I realised it’s merely LZSS-compressed. Essentially I just hacked my FLI decoder to decompress data first and operate on decoded data instead of file in this case;
  • Stargunner FLC—like other files in the game archive it was compressed using byte-pair encoding (and it may be the only case of such method being used for compression in the wild). In this case file is split into small chunks and unused byte values are used to code pairs (of used byte values or other pairs). Adding support for it was as trivial as in the previous case, but the fun thing here is that after I figured out the decompression algorithm I found out that it’s been known and supported by various extraction tools, it’s just discmaster picked up the laziest one.

Beside that I’ve REd HUF format from Johnny Bazookatone which employs RLE compression and then further compresses video frame data with global Huffman codes. And I’ve also added support for Goosebumps: Escape from Horrorland archive among other things. The curious thing about it is that such archives contain .gvd files which are essentially remuxed AVIs, so my plug-in reconstructs AVI from them by default (but this can be disabled if you prefer the original files instead). Almost all of the files use Indeo 3 but a couple of them seem to use their own codec with no decoder available so here’s that.

In general I still have at least four original formats to add (plus HNM6 and some extractors) but there seems to be enough candidate games to RE for it to be feasible.

P.S. I also looked at SMV format from AGON: The Lost Sword of Toledo but after looking at the binary specification and discovering MPEG-4 ASP decoder there (also if you remove the SMV header it can be played as an elementary MPEG-4 ASP stream) I lost any interest. Maybe Paul will have some interest supporting it in librempeg, maybe not—and I definitely don’t want to mess with such format (the same applies to KSV as well).

These weeks in na_game_tool

Sunday, December 14th, 2025

Last time I talked about MVI formats, mentioning that I had one more equally German MVI format. Well, the official specification uses CauseWay DOS extender which compresses executables (and I still haven’t found a way to make DosBox debugger dump loaded 32-bit segments, otherwise I would’ve REd a bunch of Psygnosis formats too). Luckily the demo version did not use it and I was able to find how it is coded. Apparently they employed some non-standard LZW which for some reason shuffled low codes, so 0/1/2 are used as special signals—dictionary bump (followed by byte aligning for some reason; other implementations bump dictionary size implicitly and do not insert bits), dictionary reset and EOF correspondingly—while codes 3..257 are used to code bytes. Beside that it’s nothing special: intra frames are (optionally) LZW-compressed, inter frames consist of pixels and mask telling where on frame to update those pixels (both parts with optional LZW compression).

Speaking of LZW, there was this FLK format (apparently Italian) that also employed LZW to compress pixel data along with the command stream with rather simple commands like “repeat pixel N times, skip next M pixels, copy following P pixels” and additionally “restore Q pixels of the background”. As you can guess, the format is used for animations overlaid on something else in addition to video clips. In case of the latter command stream may be absent and you simply put decompressed pixels into a new frame.

Other codecs are Ascon SKS (which is essentially a collection of JPEGs with swapped chroma planes; I did it mostly as a test of JPEG decoder module that I plan to use in other decoders) and Interactive Pictures VID (which I encountered in .evd, .fvd and .gvd files—for files with English version of the video, French version, and general version without speech). This one is curious not only because its binary specification for some reason contains compression for it (which I encountered first) but for the format features itself. Images are split into 8×8 blocks that may be coded raw, with 2-16 colours and a pattern, and a custom-scan RLE I remember seeing in Bink (and XCF but like Bink there are 16 patterns here as well and not just four). Probably nobody cares about it but it was fun to discover.

In addition to that I’ve implemented support for a couple of well-known formats, namely HNM5 (aka UBB2—UBB is apparently the same but lacks headers) and RoQ. The former is a typical French format (you can tell it by the fact it uses crazy motion compensation modes with mirroring and transposing), I implemented it mostly for completeness sake (so I have support for all HNM flavours in my tool, all is left is HNM6). The latter has the same rationale as when I looked at it four years ago: its support in libavformat/libavcodec sucks i.e. it’s adequate for videos intended for id Tech 4 engine but not for the original Trilobyte games (not handling JPEG-compressed frames and not descending into 0x1030 chunk are two most glaring deficiencies). Plus there is a can of worms related to the fact that audio in Trilobyte games uses unsigned predictor while id Tech games use signed predictor and to the fact that for some files you need to scale motion vector twice (and for some files it should be done on a picture scaled twice vertically). I try my best to detect such situations but they do not offer work correctly (and if you wonder, in games engine may have a hard-coded list of files that should be treated differently).

And that is actually not all! I’m still working on supporting some game archives as well (for example, the majority of RoQ files I encountered were hidden in .gjd archives, same as VDX files). One interesting example is Escal compressor. One funny aspect of it is that it is employed in Pumuckl Klabauterjagd, a game for about 8-year olds, while the rest of titles using it are definitely 18+. From technical point it’s interesting as it seems to be inspired by the dynamic variant of deflate with some simplifications: instead of blocks you have codebook definition valid only for the next specified amount of symbols (which are still combined literals and copy symbols, with their codebook coded using code lengths packed with another codebook). Overall it’s distinct enough but the source of inspiration is obvious too.

Overall it means I have only four more original decoders to create plus some of the archive formats to support (like Coktel Vision STK/STK2 as well as the previously mentioned extractor/converter for Monty Python & the Quest for Holy Grail). Probably it will be the last release too as I’m not sure I’ll have enough game formats for another release. Well, there’s also na_eofdec which should get more Amiga formats before 0.1.0 release. And in theory there are console formats if Paul has not written decoders for them all…

Ikarion MVI formats

Friday, November 21st, 2025

So I found another pair of rather peculiar game video formats. What’s curious is that while MVI1 and MVI2 are rather different internally, they both are used in Battle Race demo, and that’s not saying anything about their design (yet).

Both MVI1 and MVI2 are codecs used in some old DOS games developed by Ikarion Software. The only common thing in their structure is that is starts with magic containing “MVI” followed by 16-bit version and a table of frame sizes. And that’s where the differences begin. In MVI1 frame sizes are coded as radix-7 (or MIDI encoding, also known as LEB128 nowadays); in MVI2 they didn’t bother with it and left them as 32-bit numbers. In MVI1 frame consists of several optional parts, in MVI2 frame structure is fixed. And there’s another small difference: MVI1 has LZ77-compressed paletted images while MVI2 has vector-quantised 5-bit YUV420.

Of course formats employing LZ77 are dime a dozen but MVI1 still manages to stand out: first, it employs radix-7 encoded offsets, and it also de-interleaves palette by components before compressing (i.e. first all red components are sent, then all green components and finally all blue components). Optionally it can employ motion compensation on 10×10 tiles (which is uncommon already) with motion vectors for each tile being compressed with RLE and also in de-interleaved form (i.e. 768 16-bit offsets are split into high and low bytes and those are compressed one after another). I can’t think of many formats back then that thought about de-interleaving data in order to increase compression.

MVI2 splits frames into 64×64 tiles that are composed of 4×4 blocks selected from a circular buffer of 4096 entries. So frame decoding consists of reading new 4×4 blocks for the codebook and then decoding 12-bit block indices for 64×64 luma plane and two 32×32 chroma planes (all they use the same codebook, which is rather unusual for such codecs). Of course such approach is not particularly new (and reminds me more of 16-bit consoles) but I still can’t remember another VQ-based codec with exactly the same design.

P.S. And there’s also MVI used in Archimedean Dynasty—yet another MVI format from yet another German company. I’ve not looked at it yet (beside a cursory glance in the hex viewer) but it looks different from those two. Let’s see what surprises it has…