Archive for the ‘NihAV’ Category

Archive extraction support in na_game_tool

Saturday, November 8th, 2025

Back in the day I said that I want 0.5.0 release of na_game_tool to be more than a mere decoder and also support game data archive extraction. And what do you know, less than half a year later I’ve finally started to work on it.

The idea is rather simple: use the same mechanics to detect archive type, create a plugin that will go through archive contents entry by entry, use information provided by it to create an output file and provide a writer for plugin to dump contents to.

Of course such functionality is present in many other tools, but this one will make na_game_tool more than just a decoder for some game multimedia formats, it will support the formats I somewhat care about, and it can perform some format conversion while at it. And it will allow me to offload the throwaway code I wrote for extracting such formats so that knowledge won’t be lost (as well as allowing me to use an existing framework when I need to create another extractor). With this the tool becomes more useful to me.

Here’s a simple example: the first archive format I implemented is for Access Software .ap files. The archive contains merely offsets where next file starts and nothing more. But for convenience I added a bit of code to look at the first bytes of the extracted file and give it a reasonable extension if possible (e.g. for ACC, DBE, H2O, PTF and WAV files).

Here’s another example: third (and currently last) supported archive format is Tsunami Media RLB. Beside mere extraction of all files (which is a necessary step for supporting their animation formats), it also outputs a proper image instead of raw image data for Mehan Enough (that involves remembering last decoded palette and scaling image twice horizontally). In the future I’d like to support images from other games like Ringworld but that would involve a bit more work.

Ultimately I hope to keep such hybrid approach to data extraction: convert simple formats (image and audio) in the extractor plugin if it makes sense and leave more complex formats to the other decoder (which may be na_game_tool, na_encoder or some third-party software). And I have a good candidate for that: Monty Python & the Quest for Holy Grail. You can see a page describing formats from that game linked in the top corner of this blog and even find a couple of posts about it. I guess that means that I care.

Of course it will take more months to make the next release (I’d still like to keep the rule about decoding at least twelve new formats based on my own research) but I’m not in a hurry anyway.

Slow NihAV week

Saturday, October 25th, 2025

I don’t have much energy to work on stuff, so I spent most of my time doing nothing—and occasionally working on fractal formats decoder.

But first of all I’d like to tell that I’ve added another format and a half to na_game_tool. I’m talking about the full-screen animations in Hopkins FBI game. The format by itself is very simple: 640×480 frames, first one is stored uncompressed, the rest use extremely simple compression (values 0x00-0xD2 are pixel values, opcodes 0xD3-0xDD are used to code runs, opcode 0xFC signals end of data, the rest are used to code skips). Why I called it a format and a half? Apparently what I described is true for .anm files that are used to code FMV cutscenes, but there are also .seq files that have the same structure but no opcodes for runs (those are normal pixel values there). Curiously, demo version of the game had ANM.EXE which can also both decode and encode .anm files and has helpful messages too (if you know French).

Anyway, back to the fractal compression. I’m still working out wrinkles in TMM-Frac decoder but it gives a recognizable picture more often than not. Fun thing is that back in the day Alyssa Milburn decompiled the same decoder in FVF (for ScummVM engine) and the video decoding is the same, only container is different. Unfortunately it is a decompile so it reconstructs the original code in the binary specification in C form with minimal improvements (see for yourself). Mind you, it’s a great accomplishment by itself, considering how the code in question is tricky even for modern decompilers (mostly because it uses segment registers to access different kinds of data and similar tricks). But since I care more about understanding how it works than having a working decoder, I’m fine with having a buggy implementation that I can fix eventually.

Here’s a sampler of quickly hacked FVC1 decoder (frame 70 from fernlogo.avi if anybody cares) made by copying my current TMM-Frac decoder core. As you can see, there’s still a lot to fix but there is some progress there too. Mostly it serves as a proof that it’s the same technology in all three cases (I’m yet to write an FVF decoder but it’s undoubtedly the same compression).

Of course when I finish it I’ll try to write a nice format description as it is a bit more complex than “apply affine transformation and contrast adjustment to that block” of pure fractal coding.

Meanwhile Paul has shared a byteVC2 decoder with me and I have to look at that codec eventually (big spoiler: it looks like H.266 rip-off considering how the binary specification mentions ALF, SAO, WPP and such). So many things to procrastinate looking at!

New obscure formats

Saturday, September 27th, 2025

Despite how it looks, I still monitor Discmaster for new additions in hope there’s something interesting there. Sometimes there is, which I can either postpone for later or actually take a look and try to figure out how it works. Here’s a list of stuff I looked at and found at least somewhat interesting:

  • beta version of VfW SDK contained a special AVI file that had a different structure and apparently can contain only single stream. I added a support for it to NihAV just for completeness sake;
  • ReVoice Studio discs contain some AVD files that are AVI files in reality. The problem there is that those files seem to employ Indeo feature for content protection and require an access key to decrypt data. For rather obvious reasons it’s not something I’m willing to pursue further;
  • some Licensed Cartoon Property Activity Center discs contain videos that use ARBC codec. I looked at it long time ago at Paul’s request so I remember he wrote a decoder for it. But it turned out that there’s a version of the codec used in MOV—with the 16-bit values being big-endian now. So I also implemented a decoder for both codec flavours just for completeness sake;
  • Video Toaster 1.0 (now for Windows, who cares about Amiga system-seller?) had some samples in RTV format. It turned out to be uncompressed interlaced video in packed format. I’ve implemented a decoder for it in na_eofdec;
  • speaking of Amiga, there’s a game called Golem with animations in XFL format (that are raw frames in per-bitplane format). Those are not too interesting to support but there’s also a stand-alone video player featuring some game footage and its XFL has a proper format, with audio and palettes. So I supported it in na_eofdec (since it’s not strictly game format).

There is at least a dozen of other formats that I found by searching for large unknown files, so currently there’s enough work waiting for me (maybe I’ll actually do something eventually too).

na_eofdec finally started

Sunday, September 14th, 2025

While librempeg does its awesome stuff, I’ve finally started working on na_eofdec, a new tool for decoding exotic/obscure formats (hence the name). It is intended to decode fringe formats I find interesting enough to write a decoder but not useful enough to be included into main NihAV (maybe I’ll move some formats from there to this tool as I did previously with some game formats and na_game_tool).

And while it is based on na_game_tool and will keep its interface, there’s one major technical difference under the hood: while game formats are expected to produce constant rate content (always the same number of frames per second and audio blocks of equal size), these formats are allowed to have variable framerate and audio block length. Currently it affects only AVI writer (which I modified to have synchronisation, frame duplication and splitting audio input into blocks of equal length) but in the future I hope to write a MOV muxer to handle such inputs natively.

Of course such tool is useless without decoders, so I’ve added a pair of them for Lantern MOV formats. These are a pair of RLE-based animation formats using IFF or RIFF structure (little-endian in either case). There are more candidates out there, like all those IFF-based formats. As usual, the first release will happen when I implement at least a dozen of original decoders, so it will take a while.

MVI2: done

Thursday, August 14th, 2025

I’m almost done with Motion Pixels at last. Of course I skipped implementing some exotic modes but at least the files I could find play fine and don’t complain about missing modes. I just need to put finishing touches and commit it all, probably on Saturday.

The next post should be dedicated to intricate details of the codec(s) and comparison to its better-known competitors with similar design (Truemotion 1/RT/2/2X and Indeo 2/3) but for now all I need to say that frames may be coded in several modes (RGB or YUV with one chroma sample per 2×1, 2×2, 4×2 or 4×4 block), some parts of it may be use low-resolution delta coding (with its own peculiarities depending on line number and sampling mode); and since that was not enough, they’ve added smooth delta coding mode (which also has its own peculiarities in low-resolution coding mode). And of course there’s single-field coding mode. And some features seem to be duplicated using different flags. Since I’ve not found any samples for most of them, I simply implemented basic modes, 4×4 YUV mode with lowres and all YUV modes with optional lowres and smooth delta coding (since movieCD samples seem to exercise them all).

The best part is that nobody cares. NihAV can’t be interfaced with MPlayer easily, discmaster.textfiles.com is not likely to change anything (e.g. files here are recognised as aviAudio type despite having video track and nihav-encoder being able to decode it just fine. Or BATH06.MOV—no link since it’s the only one in the database—which can be converted with the same tool but it’s not even recognised as QT MOV. So I don’t expect that MVI1/2 files will get a video track either.) And I never was Aware caring about the codec much, not having any content coded with it for starters.

Anyway, with this waste of time is over, so what’s next? While searching for the samples I’ve found a couple other MVI formats that may be good candidates for na_game_tool. There is a lot of janitorial work for NihAV as well (for example, I want to rewrite AVI demuxer—it’s one of the first pieces of code I implemented for the project and now I see that some things could’ve been done differently and better). And I’ve finally decided on a name for a new tool: na_eofdec (NihAV exotic/obscure formats decoder). Now all is left is to RE and implement enough formats for a release of both of those tools.

Don’t expect any of this happening soon though, I am lazy and work on it only when I’m in the mood. For example, this post might’ve been about why wavelet compression for video (and images) inherently sucks—but I still haven’t got in a proper mood for writing it.

Random NihAV news

Thursday, July 24th, 2025

Since I have not tweaked any weights and have not made any releases, I’ll just write about some stuff I’ve been working on but have not released yet. Meanwhile librempeg got support for a bunch new formats too so its changelog may be a more interesting read. Anyway, this post is about what I have (and haven’t) done.

First of all, I’ve finally fixed an annoying problem with VA-API decoding on one of my laptops. Counterintuitively, it turned out to be faster to request hardware to convert native surface into some other format (NV12 into YUV420) and then use it instead. This made decoder CPU usage drop under 10% at last. Probably it can be optimised further to reduce load on graphics subsystem but I’d rather not mess with OpenGL unless it’s really really really needed.

Then I expended support for two formats in na_game_tool. VDX (used in The 7th Guest) had a different format version for the game demo. It still employs two-colour VQ but data for intra frames is split into separate parts for masks and colours, and inter frames code updates to masks and/or colours for each block instead of independent decoding. Additionally thanks to Discmaster I’ve located DPEG version 2 which employs completely different algorithm from the version 3 (painting 4×4/2×2/1×1 squares for intra and skip/update for inter).

I’ve also discovered some new interesting formats like Lantern MOV (which codes DIB changes using 16-bit RLE and there’s a probably related older version in IFF instead of RIFF). I’m considering making a sister project to na_game_tool to decode various formats like this one, formats coming from Amiga, recording formats and such—for all the formats that I’d like to try decoding but don’t want in main NihAV. I’ll write about it when I actually have something to write about (i.e. when I have a name and enough formats for 0.1.0 release). Another curious find was fractal video codec—not the ClearVideo but something with fourcc FVF1 from Images Incorporated. Who knows, it may be interesting to RE.

And finally here’s what I really wasted too much time on: Motion Pixels decoders. It has rather annoying binary specification (like using segment registers to address decoder context variables) that decompilers refuse to translate and from I heard it’s impossible to run on anything newer than Windows 95 or NT4. Nevertheless the formats pose some interest.

From what I saw long time ago, MVI2 is MVI1 with certain extensions, and MVI1 is surprisingly close in the structure to MVI in its own format files—and Gregory Montoir has reverse engineered it long time ago.

So I started by reimplementing that MVI decoder (since I can debug its behaviour against known working implementation) while trying to understand what it does. I got it more or less working (reconstruction is still not perfect but at least it’s recognizable) and my decoder supports other files (found with Discmaster of course) that trigger demuxer bugs or have different subsampling modes.

Then I moved to implementing MVI1 decoder applying the differences found in the binary specification. While it still does not handle decoding properly (both the pictures are garbled and I don’t use all deltas stored in the frame), at least it proves I’m on the right way. Hopefully it’ll decode properly soon and then I can add MVI2 features. Of course it’s a useless format nobody cares about, but apparently I do.

PMM support for na_game_tool

Friday, June 27th, 2025

While I suffer from thermal throttling, I don’t have much progress to report. Mostly I did some quality of life fixes for NihAV. For example, BaidUTube decided to switch AAC streams to HE-AACv2 in some cases, so I spent some time debugging and fixing SBR decoder in order to get rid of annoying chirps.

But finally I decided to be more systematic and tried to compile a list of known FMV (and FMV-ish) games and what formats they use. In the end I got a list of about four hundred known games, though of course I did not look at all of them: some games are not easy to find, others are console games which I’d rather not touch. SEGA formats are more conventional (often it’s just Cinepak or TrueMotion in AVI), while 3DO or CD-i is something too exotic and for Playstation you have better luck with librempeg.

Anyway, while compiling this list I discovered that PMM format is used in three games, so I decided to implement it at last. It is supposed to contain rather simple quadtree-based video coding with 15-bit pixels that may be updated per-component, and audio may be coded with one of several simple compression ways. Unfortunately format description in The Wiki was somewhat lacking and did not describe audio type 3, so I had to look at the binary specification.

Audio compression type 3 turned out to be real DPCM (while type 2 is not DPCM but rather 16-to-8 bit mapping scheme a la A-/μ-law). It codes packets of 16 bytes where the first byte is delta shift and the rest are 4-bit signed delta values.

The format itself turned out to be more curious than expected as it may be in either endianness (which affects not merely chunk sizes but header fields and code bits of the video data as well). And to push it further, it apparently also code frames as raw palettised data (using SEGA Saturn palette format).

But that’s not all, Area 51 game actually uses YUV colourspace for some of its videos so sometimes you get BGR555 and sometimes it’s YUV555—with YUV to RGB conversion coefficients sometimes transmitted in a special chunk. I suppose it improves compression ratio a bit.

In conclusion I say the usual thing: looking at those old formats is usually more interesting than looking at the new ones. Back in the day developers had fewer opportunities to borrow ideas from the standard formats (except for FLI of course) and threw different crazy ideas in order to see what sticks. For instance, some French codecs liked to perform motion compensation tied to affine transform (i.e. rotating and/or mirroring that block); some codecs used RLE operating on pairs of bytes or copying backwards; some codecs stopped at coding block with two colours, while others used several or even put those colour combinations into a frame-level codebook. Even those two codecs (Reaper and Xilam DERF) that would look like ordinary JPEG clones used an interesting mix of bytes and nibbles to code coefficients without wasting too much space or resorting to Huffman coding. And nowadays people are lazily waiting for H.267 (and if anybody would use H.266 for real) and AV2 (which should’ve been released about four years ago). No wonder people have little interest in multimedia.

P.S. It’s not likely that I’ll work on supporting another game format soon. Even disregarding the heat wave, I have other things I’d rather work on (and maybe there will be something to report eventually).

NihAV: now with TealMovie support

Wednesday, June 11th, 2025

Back in the day I looked at the format and recently, to distract myself from game formats, I decided that it might be a good not the worst idea to implement decoding it.

And in the course of doing that I discovered some things that make it even more peculiar. For starters, it flips every second sample in its ADPCM coding. I don’t know if it improves compression in this particular case or it was done just to be different. Similarly split sub- or sub-sub-blocks are coded in コ-order instead of more traditional zigzag order.

But there are more interesting things about it. For starters, the file is organised into blocks instead of frames. First block always contains metadata (streams parameters, title, creator and such), next blocks contain one or more video frames (which you have to decode one after another; I implemented frame parsing for finding out frame boundaries but that’s inelegant solution), and last blocks are used to store audio. This means demuxer either has to demux audio frames after all video frames are sent or jump places in order to maintain synchronisation. Since this is not na_game_tool, I picked the former. The samples are short, so it’s easier to decode them to AVI+WAV and remux properly (or decode both streams to AVI and make AVI demuxer handle unsynchronised streams better—but that’s a task for another day).

Another surprising thing is that there is 16-bit RGB support, done in a very peculiar way. Frame decoding remains the same, except that now frame data is actually a pseudo-YUV frame with two chroma planes following the luma plane. And of course the conversion is done using one of two tables (depending on file version) using the formula yuv2rgbtab[(u + v) * 128 + y]. I guess it’s coding luma, colour difference and colour difference difference here.

And finally, intra frames in TealMovie are stored raw. But when frame width exceeds 160, it is stored half-size.

That’s why I’m looking at those old formats: there’s significantly more variety there in employed coding methods and storage format nuances. Not all of them make much sense but sometimes they’re entertaining or so original that it makes you wonder why such approaches got no further development.

P.S. Maybe I should take another look at the handheld console video formats.

P.P.S. But I think I’ll have to do some boring things instead. With BaidUTube changing its available formats it seems I finally need my own MP4 muxer. In either case that’s easier than to fix libav.

na_game_tool 0.4.0 release

Tuesday, June 3rd, 2025

At last a new version, now with over a hundred various formats being supported!

About a third of them are console formats of mostly raw variety (you need just to figure out how tile data is represented) but some of them required some reverse engineering as well (e.g. Road Avenger employs LZ77-based compression). Another third comes from known sources (either The Wiki or ScummVM source code. Last third is from my reverse-engineering efforts on DOS games.

What’s next? I don’t make plans, but I like the idea (suggested by Paul of librempeg fame) to make the tool more versatile. So version 0.5.0 should at least support extracting data from game archives: some of the currently supported video formats can be found only inside large game archives, so why not provide a way to obtain the files as well?

Beside that, I’ll probably focus on more complex codecs, namely the ones that are based on other codecs like Cinepak, JPEG or Smacker. I’m not sure I’ll be able to find another dozen formats to RE but at least there should be something new beside merely archive extraction.

Meanwhile grab the current version here (or don’t, it shan’t make a difference).

na_game_tool: yet another bunch of formats

Sunday, May 11th, 2025

So, what’s been added since previous report?

  • Road Avenger BIN—as mentioned in an update to the previous post, done;
  • Reaper FMV (from Rollcage game)—decoding works fine but the reconstruction does not because of imperfect IDCT implementation on my side (and the fact they don’t use any kind of clipping to make sure the result will stay in range all while employing different tricks like converting double to int by adding a large constant, storing the result as double and read the second half of it as an integer). Overall, I decided not to count it and threw in a couple of easily REd formats described in the next entry;
  • a pair of other BIN formats from Data East—they’re the same as Road Avenger BIN but not even compressed;
  • Ecco the Dolphin LMS—another raw-tile Sega CD console format except that tile data is arranged more curiously there (128×128 frame is split into 128×32 strips consisting of 8×8 tiles that are arranged in columns). Also it seems to use implicit grey-scale palette (unless there are some external palettes hidden elsewhere), at least watching those documentaries in this way is fine;
  • Interplay M95—it’s been described on The Wiki since 2006 (not by me of course) but nobody bothered to implement a decoder for it until now;
  • Psygnosis SMV (from WipEout game)—I looked at it back in the day but of course it’s been on The Wiki since 2012. Codec 2 was not described completely right there (partition codebooks are stored in the end, after block indices and not before; and it was not immediately clear that block palettes are stored in global frame order and not in partition coding order) but nothing that a bit of debugging can’t fix.

In either case I’ve filled self-imposed quota of a dozen of originally REd formats and started to pick other formats to support (three done, about nine to go). I have noted about three formats worth supporting and if I can’t find more good candidates—well, maybe there are some more low-hanging Sega CD formats…

And as usual, for more supported console formats, both simpler and much more complex, there’s always librempeg (and that’s not talking about other things it offers like the countless audio and video filters).

P.S. Since I don’t want to do a separate rant, I’ll mention some tangentially related things here.

First, a search for more SMV samples on discmaster returned no unknown real SMV samples but some PMV samples with .smv extension including one that could not be decoded (because of zero root chunk length—I’ve fixed that) and a couple that had nothing wrong with them but were not detected as Zork PMV at all for some reason.

Second, I actually used discmaster to check if there are some interesting ARMovie files. Sadly it still lack an option for omitting supported files so I searched for acornReplayAudio files and filtered out the sources containing actual ARMovie files without video track (somehow I don’t want to check all of ~6000 files so if one or two files coming from same CD are audio-only I excluded it from the further search). After all this winnowing I’ve found two samples with Eidos Escape 102 codec. It’s simple and I’ve REd it some time ago so finally I’ve managed to write a decoder for it. At least I don’t have to search for the samples by the magic string like I did back in the day… Sadly there’s no good way to detect old TCA format so I’m not even going to attempt looking for it.