Looking for a job (again)

August 10th, 2026

Pre script: I’ll try to keep this post above the rest for obvious reasons and you should find newer posts about the usual stuff below.

For circumstances out of our control I don’t have a job any more (after sixteen years of it) and I’m completely free starting from February next year. And while I can live more or less comfortably for a couple of years on my savings I consider proper to have a job, preferably an interesting one. Since it is hard to find an interesting job for my qualification, I post this in faint hope that somebody will offer me one.

First of all, let’s start with what I can do. I have a good knowledge of C (but not C++ — nobody knows C++ in its fullness, I just don’t lie about it), Rust and various assembly languages (not just x86/AMD64 and ARM, I have some experience with a couple of more exotic ones; most of the assembly code I wrote is SIMD optimisations). I also have a knack for reverse engineering things and documenting them afterwards, which involves nor merely looking at the decompiled output (or disassembly when a decompiler can’t handle it or lies) and copying it verbatim but rather understanding it and comparing various parts to the known methods. And of course I have vast knowledge of multimedia and adjacent technologies (up to OS and CPU architecture). What I don’t know I can learn.

Then, why you should consider hiring me. If you need somebody who can write safe, portable code or fast platform-dependent assembly code that will not need much maintenance afterwards. If you need somebody to work on low-level multimedia stuff (not just integrating an existing framework but messing with protocols and decoders directly) or related image/audio processing. Or if you need somebody to work on low-level stuff e.g. for embedded systems or microcontrollers. If you need somebody to debug complex cases or reverse engineer third-party stuff for interoperability (digital sovereignty is supposedly a thing now in the EU, maybe you need somebody to implement a part of it).

Last, working conditions. I’m a naturalised German citizen, so I’d prefer my work to be inside EU, preferably remote or close to Karlsruhe where I live; or at least not requiring a relocation to another country (which is still possible for EU but the offer must be very appealing). Additionally I prefer to work in a small company instead of being a cog in a large corporation. Finally, the unpleasant question of money: I’m not going to work for exposure, peanuts or partnering up for the future profits (I had enough of that in my student times, thanks); it should be enough for a decent living here i.e. what any other middle-class worker can afford and anything above that is nice but not mandatory.

If nothing works maybe I’ll just get some useful menial job instead.

Here’s my email (repeated for convenience as it’s hidden in the links way below):
Who knows, I might be more lucky this time.

SBV, an unusual game codec

August 24th, 2026

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

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

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

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

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

Again on Knowledge Adventure MOV

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.

A bit about Pälzisch Dialekt

August 4th, 2026

I semi-jokingly say that that Alsace deserves to be called Südpfalz since the cultural border there is not clear unlike the country borders. And I mentioned back in the day that a lot of places in central Rheinland-Pfalz (or Rheinland-Palatinate if you don’t recognise its proper name) sound even more French than those close to the border (no matter from which side—e.g. both have river Lauter and a town named after it, be it Lauterbourg or Lauterecken; and Hœrdt is on comparable distance from the border as Hördt). But recently I’ve seen something that made me even more suspicious about the influences.

There’s a small town not far from Mainz called Gau-Algesheim and it has rather peculiar variation of the local dialect. Here are two examples of it:

This is a bench installed in the town centre in the memory of one of its distinguished citizens. The words on that bench are “Weck, Worscht & Woi” which I believe map to the common German “WerkBrötchen, Wurst & Wein” (or “workbun, sausage and wine” auf Englisch). Side note: thanks for the commenter for the correction, I should’ve looked in the dictionary first.

And this is one of the billboards you can encounter there. There are others, featuring other picturesque sights of the town like Graulturm, but the motto remains the same on all of them. I really have no idea what the words “so charmant” may mean in the local dialect but you cannot convince me that they don’t sound suspiciously French.

Hopefully I was able to demonstrate my point that there’s something fishy going there. I’ll keep investigating the mysteries of the land (here’s another example: the centre of local shoe industry was in Pirmasens and yet the museum dedicated to it is located in Hauenstein instead—with a shoe stolen from Montabaur, which is a very long way from either of them), at least for my own amusement.

Micro Wavelet: done

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

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.

OMGperformance

July 10th, 2026

I use my own player for playing videos. It’s not very optimised (video frame decoded with VA-API gets downloaded to my own frame structure in main RAM, which gets uploaded to SDL texture and only then displayed—the proper way is to allocate EGL texture once and use it both for VA-API decoding and displaying; or maybe the same but Vulkan and semaphores all the way) but apparently playing back 25fps video even in that way takes less CPU than updating one line with play time in gnome-console at about 10fps.

I have a feeling something went wrong with the modern software…

A bit about next micro codec

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

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

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.

Read the rest of this entry »