Archive for the ‘Various Video Codecs’ Category

na_eofdec 0.1.5 release

Tuesday, October 27th, 2026

Now as the PHP calamity is temporarily over and the sites are back online, it’s as good time as ever to make a release.

I’ve come to realisation that I don’t have enough non-gaming video formats in store to reverse engineer, so instead of waiting indefinitely until I discover enough of them I’m making a release now. Half a dozen new formats are enough for 0.1.5 by my standards, and maybe it will be useful as a reference for somebody.

Since the reason for this point release is the lack of formats, don’t expect new releases in the foreseeable future. From my point of view the tool served both its purposes well: testing decoding of some exotic format and being a proving ground for MOV muxer. It makes sense to port the parts that handle variable framerates and uneven audio blocks to na_game_tool but so far I was not bored enough to do that. Anyway, the new release is at the usual place and I should not bother you with this tool ever again.

A bit about really ancient format

Monday, October 5th, 2026

While researching the formats to support I’ve finally encountered an animation format for CGA, from the times when H.261 was ratified (i.e. 1988) but a bit simpler than that format.

Essentially it’s RLE-compressed CGA memory buffers either in 640×400 monochrome or 320×200 eye-gouging 2-bit colour mode. RLE has a twist as instead of the usual mode switch or symbol repeating it sends the list of symbols that have run lengths after them.

The hardest part was to actually render the resulting frame. For some reason CGA video modes organisation is not as widely documented as EGA or VGA, and it differs enough from them. The 256-colour VGA mode is simple: there are four planes responsible for interleaved parts of the frame or you can even simply pretend it’s one contiguous blocks (with VLB and 80486 you probably won’t care about hidden performance hit anyway). EGA as many video formats of the era (like Amiga but not as exquisite; and most of VGA modes as well) simply separates data into bit-planes. CGA on the other hand first splits data into even/odd lines using two different pages for that and packs bits continuously. I can guess what technical limitations made it work this way but I still don’t like the result.

Anyway, I think this obscure format from the past really stands out and deserves a mention at least somewhere (like this blog). Oh, and README.TXT mentions the program was written by an attorney—I don’t know what aspect of it all is merely mundane.

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.

Micro Wavelet: done

Friday, July 24th, 2026

So I’ve finally implemented NeXT Micro Wavelet decoder (and updated git bundles on the site while at it) and the codec turned out to be even more interesting than on the first glance.

The codec itself consists of three distinct phases: using delta prediction along with wavelet transform, packing results into 16-bit opcodes, and further packing the opcodes with Huffman or LZSS compression. There’s also a raw mode which simply transmits 8-bit deltas so it’s not particularly interesting.

First stage is probably where the codec name comes from: it works on 2×2 pixel blocks that get transformed into the difference from the previous block means (for each component) plus vertical and horizontal differences between block pixels (the same pair is used for all block components). In other words, not exactly full wavelet transform but not exactly no wavelet transform either.

Then the deltas get quantised to a small set of pre-defined values (13 values for red and blue, 15 values for green, 5 values for horizontal and vertical differences) and get packed into a single 16-bit value (that’s merely 63375 combinations out of 65536 possible, which leaves room for special opcodes). Normally one opcode represents a set of packed deltas but in theory it can hold “skip next N blocks” opcodes though I’ve not encountered a file with those.

After we got those opcodes it’s time to pack them (or write them as is). It can be done either with static Huffman coding or with LZSS that operates on 16-bit symbols. Huffman tree definitions are stored in the codec extradata after the main decoder configuration (which deserves its own mention and should get it below) and usually define about two thousand most common symbols, the rest are accessible via the special escape symbol.

Since I’ve mentioned decoder configuration, it needs to be described for being rather special too. First of all, it is not stored in the usual place (codec descriptor atom) but rather in the user data atom on the top level of track atoms. I actually had to modify a demuxer to handle it properly (and discoverd this fact by chance while looking at the end of MOV file and seeing it being suspiciously similar to the file with the default Huffman tree definition). This decoder configuration actually consists of two parts: fixed-size decoder state (essentially RAM data dumped into the file) and Huffman tree definitions. And the decoder configuration is flexible. Remember what I said above about the delta packing into 16-bit symbols? Well, it’s extensible—you can have different number of quantisation levels and delta values to be defined for each component, I simply decided not to support such rich features and stick to the hard-coded delta sets and packing scheme.

Overall, this codec reminded me about Duck TrueMotion 1 for some reason, maybe because of its custom delta tables. All things considered, that’s probably the most exotic codec I’ve ever worked on since it combines both unconventional coding methods (micro wavelets packing into mini-words) and the fact it comes from the rather obscure OS (at least it was ordinary M68K code). I probably had encountered and shall encounter more of crazy coding approaches but it’s not likely to be this combination of obscure technical approach and the obscure platform. As always, I’ll be glad to be proven wrong.

Another weird format

Friday, July 17th, 2026

Just couple of years ago I had a small rant about German RLE-based codecs named *PEG. Recently I’ve discovered yet another pointless format called NPEG.

Unlike the rest it’s Polish, targets Amiga instead of DOS and it’s essentially MPEG-1 frames stored in IFF. Considering that it appeared around 1998, NP1 is the original MP4 format (if you ignore MPEG-1 in MOV of course).

Currently I have no desire to implement support of it but maybe one day I’ll really have nothing better to do and add MPEG-1 support (with various exotic containers) to NihAV. Though I hope such day will never come.

A bit about next micro codec

Tuesday, July 7th, 2026

Some time ago I mentioned that I’d stumbled upon a QuickTime sample encoded on NeXT using MicroWavelet codec which was used only there. I also expressed a regret of it being completely lost to time. And what do you know, it’s yet another situation where I’d be glad to be proven wrong—and I was (and I am).

Apparently had I looked around for a bit longer, I would’ve discovered more samples and a decoder to boot. Apparently that decoder was a part of NeXTTime and not QuickTime, which is a completely different thing. And NeXTTime including that decoder could be found on OpenStep 4.x in particular.

While I have not written a decoder for it yet, I’ve figured out enough details to talk about it.

First of all, it’s a sort of several loosely-tied codecs (and I’m yet to figure out what makes it choose which decoding path to take). One of them is a simple wavelet codec with 8-bit coefficients and no additional compression, others are delta coding plus zero-run compression plus optional compression of that data. Optional compression may be either static Huffman coding (with trees stored in a separate file bundled with the decoder—a bit like ClearVideo did it) and an individual tree selected per frame, or it may be LZSS.

It’s nothing outstanding but still it’s a rather curious codec from a rather curious obscure platform (Display PostScript anyone?). And as a final fun fact, it’s internally called “harsh” with the functions being named e.g. harsh_decode_skip. Hopefully implementing a decoder for it would be mild and agreeable despite the naming.

TWV: unsupported formats

Thursday, June 25th, 2026

While the weather is stewing here and there’s no desire to do anything, I suppose this is a good occasion to talk about two formats with the same extension that I’m not going to support.

The first TWV format comes from Reality Pump games like Knightshift and World War III: Black Gold. It is not a particularly complex codec but the fact that it’s simplified version of interlaced MPEG-2 or MPEG-4 with an additional layer of headerless deflate compression makes me not want to work on it at all.

The other TWV format comes from Québec and I’ve encountered it in Le Logiciel de Finances Personnel and (mostly with TMV extension) in the game Music Chase. I’ve written about it some time ago, essentially it is QuickTime MOV format with the annoying quirks like all values being little-endian, some additional fields inserted (I suspect that 1-byte version field and 3-byte flags field combination got expanded into two 4-byte fields), and it also uses custom handlers for both audio and video tracks (yes, even pure audio files contain a video track with dummy 17-byte frames). I tried to read the binary specification for the video decompressor but quickly got lost in code for Windows 3.x that Ghidra refused to decompile. The same applies to their special BMP compression (in TBP files).

Hopefully somebody else can fare better but I don’t expect to see these formats supported even in librempeg.

A new/old video coding scheme

Friday, June 19th, 2026

Now that AV2 has officially been released it’s time to remind that these codec advances are not for free. Here it is claimed that AV2 offers about 25% improvements in compression efficiency compared to AV1 with decoding being five times slower (and that’s for an extremely optimised decoder; no idea how much slower encoding is).

Back in the day I proposed to go full AI with the codec design but it was not a fully serious idea, here I’d like to propose something more realistic that would use “AI” hardware that we should have plenty of by now—and with no AVn codecs in mind.

(more…)

We have FLI at home

Friday, May 29th, 2026

Recently I’ve released na_eofdec, a tool for decoding exotic and/or obscure formats. That release included F16 format support, but recently I’ve REd another one (PC Animate Plus / 3D WorkShop animation) and there’s yet another one waiting in the queue (Reflections animation). What unites them all is that they all employ simple compression schemes (mostly RLE-based) and (beside F16) they all have a 3D modelling program associated with them. And I’ve REd these formats by investigating the file format, they’re that simple.

F16 posed itself as “FLI but 16-bit” and it looks like its creators have failed to build an ecosystem out of it. I have encountered merely two demo samples at discmaster and nothing else. From technical point of view it’s either uncompressed intra frames or the rather familiar FLI delta compression scheme with its number of skip/run opcodes per line, just with small variations.

PC Animate Plus is more interesting as it has 4-, 8- and 16-bit content compressed, at least two format versions and several compression schemes. Plus it has some additional chunks for complex operations and even metadata telling e.g. which Voc file to play along. Intra frames are RLE-compressed, inter frames usually employ FLI delta compression (with small changes of course) but there’s another mode consisting of offsets and chunks of data to update. Another interesting thing is that it does not replace old pixels but XORs them with new data instead (maybe it comes from an alternative universe where 80×86 had REP XORMOVSB instruction).

And there’s Reflections animation. While I haven’t written a decoder for it yet, I can describe it already. I’m aware of three samples with rather uncommon 320×256 resolution and big-endian format. First frame is uncompressed, the rest seems to be simply “skip N 32-bit words, update M 32-bit words”. Writing a decoder for it should not be that hard… An update from the next day: it’s simple RLE with opcodes being skip/repeat/copy but the actual data is stored in 4-pixel columns format, so e.g. copying 8 pixel quads will result in 4×8 rectangle.

Individually the formats are nothing to write about but together they form a group of FLI clones that poses some interest. Now that I’m done with MVS it’s either extending QuickTime support in NihAV or REing obscure formats, hopefully it will give me more material for my writing.

NihAV: QT support enhancements

Friday, May 8th, 2026

When I have enough inspiration, I improve NihAV. When I don’t (which is more common state to me), I RE codecs or write blog posts—so here’s one.

First of all, I’ve started adding non-raw encoders for some common QT formats. It’s not that there are no open-source encoders for them, but I do them mostly to find out how it is done and maybe learn something new in the process. For instance, RLE encoding combines skips, runs and pixel copies; this rises the question of optimal encoding as sometimes it may be cheaper to encode a whole area as new pixels instead of a mix of copy+skip+copy. So I’ve implemented a greedy approach (i.e. code longest skip or run and fall back to encoding raw if those two fail) as well as slow but optimal one. It’s a variation of trellis coding: just calculate encoding cost with each mode (skip/run/raw) to all next possible positions and if it’s lower than the existing one, use that mode; at the end simply trace back the decisions that gave least cost at the end and encode them in right order.

Then I also added RPZA encoder. This is essentially the first texture codec before GPUs with the need for texture compression, its main compression mode is encoding 4×4 block with four colours where two colours are linearly interpolated from two explicitly transmitted colours. There is no apparent way on how to do it fast, so I ended up with an extremely simplified scheme: first I calculate the maximum difference between components and pick the one with the largest difference (or code block as single-colour if it’s small enough) to decide what values to pick, then I calculate explicit colours from an average of input pixels close to minimum and maximum ends of that range. I also have a refinement step by running vector quantisation loop to adjust the ends but it’s rarely needed in practice.

There are still more encoders to implement (SMC, SVQ1, IMA ADPCM and MACE) but none of them is interesting beside SVQ1, so probably I’ll write about it when/if I ever get to implementing an encoder for it (it does not matter if The Multimedia Mike has done that over fifteen years ago—NIH is there in the project name for a reason).

Now, surprisingly enough I’ve improved decoding support as well. The original QuickTime had SIVQ codec which is a straightforward 256-entry codebook for 2×2 RGB24 tiles followed by codebook indices. I had read its binary specification some time ago and recently I was able to locate (probably the only existing) sample for it, which is a good reason to write a decoder for it. It was well-spent five minutes of my time. Maybe in the future I’ll also do something about Pixar codecs (Ghidra works better with raw m68k version of the decoder than with 16-bit Windows 3.x version of the same).

And finally I’ve improved the support for multi-descriptor MOV files. I mentioned it some time ago and I got bitten by it again recently. For example, alice_lo_m.mov from samples.mplayerhq.hu got just first frame decoded for me and many QuickTime 1.5 sample videos (with its developers) gave an error on the last frame. For the former it’s because first frame is JPEG and the rest of them are SVQ1, while the latter samples are coded with Cinepak but the last frame may be a special one encoded with RPZA. And there was another file fully encoded with RPZA—but with the majority of it being 160×120 while last dozen of frames or so were 320×240. So I finally got annoyed enough to implement multiple streams per track so at least the frames get marshalled to the correct decoder, even if it leads to the partial streams being rather unusable. Maybe one day I’ll write a tool which will walk through MOV and render all tracks in correct sequence (taking edit lists into account), scaling and adjusting playback rate as needed, producing a raw MOV file that can be played without special hacks; or maybe I don’t hate myself that much.

That’s it for now, don’t expect anything soon (MVS description may appear but who’s waiting for that?).