Archive for the ‘NihAV’ Category

Random NihAV news

Sunday, February 8th, 2026

As I mentioned previously, after making 0.5.0 na_game_tool release I’d rather work on something else for a change (if at all), so here are some bits about what I’ve been doing since:

  • first of all, I’ve implemented support for AV, a Polished AVI format. By that I mean the format comes apparently from a Polish company and it’s simplified remux of AVI data: first there’s BITMAPINFOHEADER (and optionally palette) followed by video stream header (starting with the familiar vids tag), then there may be WAVEFORMAT structure with auds stream header, then you have table of contents (video and audio frame sizes plus flags) followed by video and audio chunks. The format was trivial to guess and I’ve added support for it because why not;
  • I’ve also finally implemented functions for reading arrays of integers. First I’ve introduced them to na_game_tool and tried them in some decoders, and then ported them to the main NihAV codebase. The idea behind it is that reading data directly into destination array (with optional byte-swapping) is faster than reading data, re-interpreting it as an integer and finally copying it into the destination buffer. I had a specific version of it implemented in MP4 demuxer already (because otherwise opening a 2-3 hour long video would cause a noticeable delay) but overall it’s nicer to have just one call instead of a loop;
  • in other things, I’ve re-started na_eofdec development using the current na_game_tool codebase. That does not mean I’m starting developing it (or going to do so in the nearest feature) but at least when I eventually get to it, I can add some archive extraction modules as well. Beside that it should be a sandbox for testing MOV muxer that I want to write sooner or later (kinda like OpenDML AVI muxer in NihAV is a backport of one from na_game_tool). Of course it would need to get a couple more formats to test it on but I’m not in a hurry;
  • speaking of MOV, I’ve improved support for MOV in MacBinary II. So far I’ve seen four flavours of it: essentially flat MOV with MacBin header, MOV with mdat box in data fork and moov atom in resource fork, the same but data fork containing mdat contents without size and tag, and even older format (with samples from 1990) with much flatter structure (i.e. lots of nesting chunks are not present at all). The first three are detected and handled more or less fine now, I’ll try to support it even if as a historical curiosity;
  • there was one major code refactoring in NihAV, namely I’ve put demuxing handling code into a new nihav_hlblocks crate and made all my tools use it instead of dragging local copies of it. If you wonder why this was necessary, that’s because you can have normal demuxers (that return full packets for the streams) as well as raw stream demuxers (that return pieces of data belonging to a stream and you need to form full packet using a packetiser). And of course you can have simply raw streams like MP3 that needs a packetiser but no demuxer. That’s why I’ve made a DemuxerObject (yes, very original name) that encapsulates them all and represents all of them as a normal demuxer;
  • and finally I’ve discovered that I can call SDL_UpdateYUVTexture instead of copying frame data into the texture manually. And then I discovered that it did not work with the time display (because it also wrote to the texture directly in presumption that it will update some pixels on the frame; there is a note in the documentation telling not to do so but it worked by chance before). So I’ve changed it to render a separate small RGBA texture and blit it over the frame instead—like it should’ve been done from the start. I somewhat wonder when I’ll have to adapt it all to SDL3 but apparently I can postpone it for now.

That’s all for now. There’s a lot to do, maybe some of it will actually be done.

na_game_tool 0.5.0 released

Monday, January 19th, 2026

Grab it from the usual place if you’re interested in it for some unfathomable reason. I’ll try to document the formats when I have time (and multimedia.cx server does not suffer from crawlers).

Update from January 30: I’ve uploaded a fixed version as I broke extracting old-style Cryo archives during refactoring (and before committing), so now it should work. The rest will (not) work in the same way as before.

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

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.