Archive for the ‘Game Video’ Category

One game, two rare-letter formats

Thursday, April 24th, 2025

As I’m still in a search for formats to implement in na_game_tool for 0.4.0 release, one game brought two formats at one—and both start with a letter I had only one or two formats before.

I’m talking about ID4 or Independence Day. Its Sega Saturn port uses EGG format which has not been REd before. But first I was able to locate PC version of the game with its animations in YQS format, so I started with it.

It turned out to be a very curious format, with YUV frame coded per plane using quadtree and two separate streams for pixel values and for control bits, eight streams in total (there’s IMA ADPCM audio as well and fixed-size vector codebook for luma). Essentially plane is split into 8×8 (luma) or 4×4 (chroma) blocks which may be skipped entirely (if the control bit is not set), filled with single value obtained from the stream (again, if the next control bit is not set) or split into four sub-blocks with the similar approach. 2×2 chroma blocks may be skipped, filled or coded raw; 2×2 luma blocks additionally may use input pixel value as a codebook index and use that 2×2 vector (flipped or not, depending on control bits).

After that I actually looked at EGG. It had similar structure but with some changes: frames are always 20kB and do not contain audio, values are big-endian and bitstream format for 2×2 luma blocks differs. I still had to resort to the binary specification for it though—loaded CPE file in Ghidra as raw SH-2 binary, located animation names and started attempts to disassemble data around them. Eventually I got the function that looked very similar to the one in PC version (except that it decoded just luma instead of doing all three components and converting macroblock to RGB). Thus I got a working decoder for this format as well.

That’s how I got two more formats supported, which makes it almost 42% of my goal. The problem is still mostly to locate the formats that can be supported (most of the ones I haven’t implemented need a lot of work to unpack the binary specification). In either case I’m in no hurry and it was nice to learn more about old formats.

A tale of three formats

Saturday, April 19th, 2025

Since I have nothing better to do, I keep looking at the odd formats here and there and occasionally do something about them. Here are three formats I took a look at recently and that have nothing in common beside being video codecs.

CGDI

This is a “capture” codec (aka Camcorder Video) if not for the fact that it records rather events than actual image data. I had a suspicion right from the start that it’s organised in the same way as WMF/EMF—opcodes with parameters that invoke GDI subsystem to draw actual image—and finally I’ve decided to check that.

Of course it turned out to be true. There are about 64 opcodes in total, some are for drawing things, some are for window management stuff, and some are for GDI state management (e.g. create or delete brush, pen, font and such).

Since implementing a decoder for it would mean replicating a good deal of Windows graphics subsystem (even if you can borrow code from Wine), I consider it completely impractical and merely improved codec documentation in The Wiki.

TCA

This is an animation format used on Acorn platform. Actually it has three layers of encapsulation: there’s raw TCA format that contains only the header and video frames, then there’s TCA wrapped in ACEF chunk with an optional SOUN chunk following it (no points for guessing what it contains), and finally there’s that format put inside ARMovie (as a single block).

I added its support to NihAV just for completeness sake. Of course not all of different flavours are supported (video is mostly just plain LZW but it has some alternative coding mode and an uncompressed alternative, audio is IMA ADPCM but sometimes it’s not without any reliable way to distinguish which is which). And looks like some animations may have variable frame rate (with DIR1 subchunk likely telling frame durations). All the details are there, in raw ARM binaries and semi-compiled BBC BASIC code, but I’m satisfied that it works at least for a couple of random plane samples I tried and have no desire to try supporting every known sample in existence.

Savage Warriors ANM

This one is a curious format. I’ve managed to locate decoding functions in one of the overlay files, it looked reasonable (LZ77 compression for intra frames and something a lot like FLI delta frame compression for the rest) but the decoder did not work properly. Curiously, demo version contains some of the same animations as the full game but in slightly different format (the initial magic is missing); after comparing them I found out that the release version uses a weird format with a 32-bit value inserted after each kilobyte of data. I ended up implementing my own buffered reader that loads those kilobyte blocks and skips those additional words for the release version.

Another thing is that LZ-compressed format had 17-byte header which the decoder skipped. Of course it made me suspect of being a third-party compression scheme, and after searching around it turned out to be Diet (you may remember it being used as an executable compressor but apparently it had other uses). It somewhat reminded me of MidiVid Lossless as it is yet another codec reusing third-party general compressor (with special preprocessing for executables, which was a dead giveaway).

In either case, both flavours of this ANM format are now supported by na_game_tool (and will be the part of the next release).

na_game_tool: new season start

Sunday, April 6th, 2025

It’s been some time since na_game_tool release and I’ve finally started working on adding new formats for it again (for v0.4 the goal is to have a hundred of supported formats including a dozen of fresh ones, currently it has only about eighty). And since newly added formats are somewhat remarkable, I decided to talk about them.

Spidy Ani from Imperium Galactica. The name sounded vaguely familiar and indeed I’ve encountered it before. I did not bother to support old sprite format since they are just animations for which you need to know the background image and palette. Version 2 contains both palette and (optionally) audio, making its support much more reasonable. As for the compression, it actually keeps the old RLE method and introduces a new one (where low values mean copy length instead of a literal) plus it adds optional LZSS compression. The best part is that it’s not been reverse engineered by somebody else but it has been documented (in open-ig wiki) as well.

Shadowcaster cutscenes. This is a format used by a game published by Origin, it turned out to be RLE optionally further compressed by LZSS (I shan’t blame you if you see some similarities here). The main difference is that the format contains commands for e.g. playing an external XMI track (or stop playing it). And instead of one palette it can store several and switch between them arbitrarily.

Castles 2 (CD version) greyscale video. This one is very special: the game has colour cutscenes in Interplay MVE format (usually with castles) but beside that it apparently has some greyscale animations lifted from public domain films. The files have .m extension and start with “BYON PIZZA” string, definitely not hinting at Byon Garrabrant, who was the lead programmer of that game.

It was extremely hard to read the binary specification for it as the executable stored that code and data in executable overlay. That means that it was in a special part of executable that gets loaded on demand, thus lacking proper references to the data and even functions. Luckily it turned out that I didn’t need it at all.

One of the sequences turned out to be just one black (or white) frame. Seeing that the frame was exactly 1/4th of raw image and filled with 0x40, I decided to calculate a histogram of some other (larger) frame. It turned out that indeed if you output values in 0x00-0x3F range as is and repeat 0x40-0x7F values four times you get exactly full image. Then by looking at the reconstructed image I understood that it codes data in 2×2 blocks (and in inverse mode so 0x00 means white and 0x3F means black). After that figuring out that codes 0x80-0xFF in subsequent frames are used to signal skips was trivial.

That was fun. Hopefully I’ll encounter more interesting formats in the future.

P.S. I’ve also added PI-Video decoding support to NihAV. The codec was used at least in one multimedia encyclopaedia and did some non-conventional things with LZW coding. I’m still not sure that it was a good idea because codec developer may be russian but since I could not find any information about him (or the companies involved beside them being Western European), I’m giving it the benefit of the doubt.

Cinepak everywhere!

Sunday, March 2nd, 2025

First of all, I’m happy to announce that I’ve finally managed to reverse engineer a format for game called Wing Nuts which means I’ve finally collected formats for the whole alphabet. So I want to implement another format that I’ve REd and I can finally release na_game_tool 0.3.0 in a week.

But what I really want to talk about is the game format itself. There are no real game videos but rather game engine data files containing various kind of data, including video frames. I could also extract PCM audio but I don’t know how to synchronise it properly so I ended up with a video-only decoder. MIDI data was yet another option that I ignored.

What is curious is the video compression format. While REing it I had constant thoughts like “hmm, it stores chunk type in a byte followed by 24-bit big-endian number, just like Cinepak” or “hmm, it uses 2×2 vectors and either scales them or combines four of them in a single 4×4 block, just like Cinepak” or “wait a minute, this bitstream format—chunk markers, flags and vectors—are exactly like Cinepak”. There are some differences from the usual Cinepak we all know though: it is a paletted format (with palette stored in a similar form before actual image data) and it has some additional chunks with codes 0x60-0x62 which seem to contain some auxiliary information used by the engine.

So seeing this shortly after CinEApak and knowing that SEGA company used slightly modified Cinepak format on its consoles, it makes me wonder is the codecs was more widely licensed and tweaked than we are aware of. That would make it even more like Duck TrueMotion (which was also widely used in game videos, on consoles as well, and with a special flavours used at least in one game).

na_game_tool: penultimate letter

Friday, February 28th, 2025

So now there’s just one letter left, hopefully it won’t take that long to find a suitable format.

Meanwhile two formats for letter ‘o’ have been added, both formats are formally from Origin.

One is FLIC-in-IFF used to store intro and ending for Ultima VII (both parts). Actually there are also fonts and speech stored there but since you need external data (plus game engine) to combine them properly I ended up simply decoding animations from those archives.

Another one is equally flimsy—System Shock movies (which are predominantly just audio tracks used probably for audio logs; also the game reminds me of Paul for some reason). What’s remarkable is that it essentially combines two different coding methods for two sizes: VGA movies are RLE-coded, SVGA movies use 4×4 tile coding with additional Huffman coding of tokens. Essentially tiles are coded using tokens representing opcodes, which may refer to 4-16 colours from the global colour table or some other operation (e.g. “skip N blocks” or “repeat previous operation” or even “fill block with these two colours”); tokens are Huffman-coded, both colours and Huffman table may be transmitted at any time. Luckily I did not have to RE it from scratch as the engine code has been open-sourced some time ago.

Just a couple more formats and I’ll be able to make 0.3.0 release at last.

And I’ve thought for another fun goal for 0.4.0: get a number of supported formats to a hundred (it would be better to hit some round number like 128 but that’s more of a milestone for the improbable 0.5.0 release). Currently I have 70-something formats listed and that will number will increase to 80 for the upcoming release for sure. Finding about eight extra formats to support is easier than finding twelve formats to RE. And to put things into perspective, librempeg lists about 270 video decoders (excluding raw formats and hardware accelerated decoding), some of them being equally incomplete, simple, or being a small variation of another decoder. So having a third of that number for game-only video formats (most of those being unique too) is a respectable feat IMO.

na_game_tool: another letter

Tuesday, February 25th, 2025

Finally I’m closer to the goal of having formats for every letter of alphabet supported in na_game_tool. Finally I’ve managed to add a format(s) starting with ‘y’.

First, I was able to locate an obscure game ported to Windows from SEGA Saturn called Yumimi Mix. The best part of is the first letter in its name and that it has some animation formats. Two and a half of them actually: there’s a companion game Dinosaur Island with its own cutscene format starting with ACUT magic, and there’s a sprite collection and animation format starting with ABLK magic that has two distinct coding modes (plus raw).

All these formats are based on the rather standard approaches used by the console: a scene is composed of (possibly several) overlaid sprites, each sprite is split into 8×8 block that belong to a global tile atlas. Both tile data and tile indices are compressed by some variants of RLE plus there are multiple palettes and commands to compose sprites and backgrounds and do some other stuff.

Since I’m not inclined to re-implement half of the game engine for that I simply ended up with a guesswork that gives acceptable results in many cases. Of course it’s far from perfect but it still better than something.

And then dexvert added MXV format to its list of unsupported formats. Since it’s used in Yo Matías game series (as well as some other games by Caimán), it was a perfect backup candidate. Of course it’s proper to call it simply mxv but I know what I’ll call it.

The format is rather simple: PCM audio and 8- or 16-bit intra frames with no/deflate/LZW compression. There’s a later iteration of the format using Vorbis audio but you should expect librempeg to support such format, not na_game_tool. So it took me just a day to RE and implement it compared to about ten day for the Yumimix formats (which are still rather incomplete).

All in all, it’s moving fine. I have some prospects on filling two other missing letters and probably by then I can finally make 0.3.0 release. Despite Paul’s suggestion I’m not going to hunt and/or invent formats with names starting with every combination of two letters of alphabet, but I’m not going to abandon the project for good either. It’s just without a clear (even if artificial) goal it’ll take more time to get enough formats for the next release.

This fortnight in na_game_tool

Saturday, February 15th, 2025

Since last time I’ve added a couple more formats:

  • finally did Dragon’s Lair (PC port) videos—it turned not as bad as I expected after Space Ace;
  • Jazz Jackrabbit 2 videos (from the decompiled decoder in Jazz² Resurrection)
  • finally implemented Xilam DERF format support (audio and video);
  • ported FutureVision FCMP and FST decoders from main NihAV;
  • freshly implemented scene format for Psychic Detective;
  • and Cyclemania video support.

If you for some unfathomable reason wonder when it will be released, I can answer: not soon.

As I mentioned before, I intend to make a release with at least a dozen of new REd formats and I’m still far from that goal. Since version 0.2.5 I’ve added support for about fifteen formats but most of them don’t count: some formats were ported from NihAV, some were based on other sources (like game engines or—for some planned additions—entries in The Wiki not based on my research), some are of poor quality and don’t really count. This means only about half of those formats is eligible—and I don’t know where to find another half (and that’s not counting other things I’d like to work on).

And there’s another small but irritating detail: so far I’ve implemented decoders for all but three letters of alphabet. Formats with names starting at ‘o’, ‘w’ and ‘y’ are still missing. Of course I can easily fill the gaps by supporting Origin Xan, Westwood VQA (or CPS) and Psygnosis YOP but I’d prefer to have something original instead of well-known formats supported elsewhere.

CinEApak

Tuesday, February 11th, 2025

First of all I’d like to blame Peter Ross for ignoring this peculiar format from his favourite company. Apparently he prefers to dig Lead instead.

Anyway, as I was scraping bottom of the barrel for FMV game formats to support in na_game_tool (and I still haven’t found good candidates for some letters, a rant about it will come later), I encountered a game called Psychic Detective.

It stores video in large .str files with some external means to signal where a segment starts and what format it has (as it may switch between 160×120 and 320×240 video and 11kHz stereo and 22kHz mono audio).

Audio is bog standard IMA ADPCM, video is while being intra-frame only is much more curious.

First of all, it employs vector quantisation with the same approach as Cinepak: there is a codebook of 2×2 blocks that get scaled to 4×4 output block, there is a codebook of 2×2 sub-blocks used to compose 4×4 output blocks, there are block mode bits telling whether it’s one- or four-vector block, and finally there are vector indices. And for larger (320×240) videos there is even a second codebook that replaces four-vector codebook after a provided line, a lot like Cinepak slices. The main difference is the structure: while Cinepak has more flexible frame structure with chunks for codebook updates, indices and such, here all data is stored in the fixed order with its sizes transmitted in the frame header.

Oh, and there’s another minor detail: frames simultaneously code 8-bit paletted and YUV video (rendered as 15- or 16-bit RGB). This is achieved by transmitting actual palette and duplicating codebook information first as palette indices and then as YUV blocks (so the decoder can decide which one to use). Also YUV to RGB conversion is simplified to look a lot like Cinepak formula as well.

I keep repeating the same thing again and again because it still holds true: those old codecs are much more interesting to look at because sometimes you find out crazy methods like this one.

This month in na_game_tool

Tuesday, January 21st, 2025

Since I’ve managed to locate a couple of FMV games I decided to make a short digest on what I’ve been working (and will keep working for a bit longer).

Ravenloft ANM

This is a predecessor of DFA, the first format implemented in libav. It is simpler but has its own peculiar decisions: interframes may be updated as a series of line segments on each column, there’s very interlaced raw picture format (for 4×4 blocks), and there’s a special picture mode which tells “decode this other delta picture N times” (though I’ve not managed to locate a sample for that).

ReadySoft scenes

This company is known for the ports of the original FMV games (you know, arcade ones using Laserdisc). I’ve managed to locate samples from three of them, namely Dragon’s Lair, Space Ace and Brain Dead 13. All three turned out to be in different formats while sharing some common traits.

I’ll start with last game and keep going in the reverse. Its videos are stored in one single BD.DAT file but are easy to extract (32-bit header size followed by the TOC with 32-bit video ID, offset and size). Videos themselves are composed of two layers—background and sprite(s). Both are updated independently and the final image is composed from them. Background data employs RLE compression, sprite employs RLE with skips. What makes it remarkable is that it not merely updates background, but also issues commands on how to scroll it around.

(Side note: this makes me think about the experimental FFV codec that used field-of-view classification to split video into layers for better compression; IIRC the technology was sold for the use in some video editor and the compression part was ditched completely. Sadly the links to it are equally dead and were not archived.)

Then there’s Space Ace which is mostly similar but uses an additional mask with sprite telling which backgrounds blocks to update and which to ignore (since they’ll be overwritten anyway). There are two additional annoying features: while the output image is 320×200, background is 328×208 for some reason (for better scrolling?); and the output is vertically interlaced. As the result it stores every fourth column in both background and sprite grouped together, so you’ll have to do some tricks to restore the proper image. Take moving into account and you’ll understand why I gave up and committed my buggy version with the words “eh, good enough”.

Dragon’s Lair seems to be the oldest of them all and uses the same RLE but with different file format. I haven’t even finished figuring out details. Maybe some other day, maybe never.

Ascon videos

This is a format used in some games by ASCARON Entertainment GmbH when it had a slightly shorter name. The format is very peculiar and I’m not talking about German chunk names like BILD or ENDE.

The earlier version codes planar YUV frames (5-bit luma and 8-bit chroma components) either in raw form or as delta with possible run for unchanged area of each component. Additionally, while some YUV codecs (Cinepak and Indeo 3 come to mind) allowed displaying their output as paletted video, here the files start with large PALT chunk specifying both the palette and a way to map 15-bit YUV value to palette index.

Then the format was extended to support 6-bit luma as well and an additional frame format that first codes offset in the reference buffer for each 8×8 block. But that’s not all, there’s a completely new frame compression method that now works in RGB and employs LZSS directly on pixels and using whole frame instead of a limited window.

I still have to figure out some details like special cases for offset wraparound but the decoder should be complete soon.


Discovering such crazy codecs is definitely more interesting than, say, watching AV2 development. I’m yet to see how the console codec (suggested by Paul) works but I don’t expect much from it.

Looking at some more exotic animation formats

Thursday, December 19th, 2024

I keep looking for old games with interesting animation formats and I’ve found another two, from Israeli companies this time.

First is the format used in Armed & Delirious. Since all of the files are in the custom archive (except for a single file with “please change CD” animation) I’m not going to support it, though I still documented it for posterity. Apparently it has two operating modes: updating some lines where each line can have its own coding mode (all are RLE variations) and updating tiles, now with each tile having its own coding mode. The only interesting thing is that tile coding operates on a sub-set of colours so it can use 3-6 bits for index. I remember some formats resorting to 16 colours and 4-bit indices but there are more variations here.

And then there’s VID format used in Soul Hunt and, apparently, some other games by the same company. It features DPCM-compressed audio and depending on version RLE- or JPEG-compressed images (and both versions are present in the game). That’s right, they use code (probably borrowed from libjpeg but I’m not sure about that) to decode data in JPEG-like format (8×8 blocks, IDCT and such) and then use some large lookup table to convert it from YUV to paletted RGB. Of course there are video codecs with such built-in functionality like Cinepak or Indeo 3 but it’s still surprising to see such thing in a random codec.

Update from December 21st: I’ve looked at JPEG-inspired coding again and I have a better understanding what it does (so maybe I’ll even be able to support it eventually):

  • there’s intra- and inter-coding, the former operates on 256×16 megablocks (consisting of 32×2 Y blocks and 16 U and V blocks each), the latter has a macroblock update mask and codes only updated macroblocks;
  • there are two quantisation matrices sets used in intra and inter mode, the binary specifications calls them “good” and “bad” factors;
  • the colour conversion code and IDCT seem to come from libjpeg while coefficient coding is their own invention;
  • coefficient coding seems to employ a rather simple set of codes: xxx0 is used for -4..4 values (codes are LSB first), xxxxxx01 is used for larger values, xxxxxx11 is used to code zero runs and xxxxxxxx 11111111 is used to code large values;
  • DC prediction is present and works the following way: decode block, dequantise it, add last DC value (and update it afterwards), scale block DC value by 32.

Initially I was discouraged by the coefficient decoding routines being implemented as state machines with computed label, so Ghidra cannot decompile it properly. I.e. it starts with “refill bit buffer” state, then moves to “decode new coefficient having 32 bits”, then it handles one of four cases listed above and moves to “decode new coefficient having 28 bits”, or “decode new coefficient having 24 bits”, or “decode new coefficient having 16 bits” state—unless it decoded the full block and saves that state to keep working from it the next time the function is called. Oh well, at least it turned out to be not that much complicated in the end.

Update from December 27th: I dug a bit more and while decoding macroblock data looks feasible, reconstructing it properly is bonkers, as the game reads quantisation matrices and scale factor for good/bad case from quants.ini text file. So I’m not so sure it’s worth the effort…