Archive for the ‘NihAV’ Category

na_game_tool: another bunch of formats

Wednesday, April 30th, 2025

Short summary for Paul: nothing interesting. I write it as a report of done work and to provide some clues for somebody looking for ancient formats.

After I did EGG format support, I remembered that samples.mplayerhq.hu had a directory dedicated to that and some other game formats (from Smacker to Bink 2), so I decided to look at it and see if I can support some of those. Spoiler alert: there were low-hanging fruits there.

What got supported:

  • ICOM video—this one is used in their Sherlock Holmes Consulting Detective series. Initial frame is unpacked, the rest are coded as sequences of skip and masked updates. I’ve managed to RE it from the sample files only, it’s that simple!
  • Klondike Moon VID—also raw first frame plus simple RLE for the following frames, and I’ve also managed to RE it from the samples;
  • Maelstrom ANM—this one uses RLE for both intra and inter frames;
  • Manic Karts AMF—simple RLE with a special large value skip or run modes that encode skip/run length in the way known as Xiph lacing;
  • The Amazing Spider-Man vs The Kingpin BIN (Sega Saturn game)—again, I’ve REd it from the two known sample files despite this being a console game. I had some vague ideas about how the console works and indeed it proved to be raw data for tiles/palette/scroll planes (even if it was send as a partial update in some cases) that I simply had to assemble correctly. Just reading some console specifications of its video system was enough.

What I looked at but haven’t REd (yet?):

  • Knowledge Adventure Movie—I looked at it some time ago and it’s not a format I’m eager to revisit;
  • Road Avenger BIN—this format seems to compress tile data with some custom LZ77-based compressor with a signature “sarc20“. I’ve managed to locate the bit in the binary specification responsible for the unpacking but no references to what and how it’s used. Nevertheless I hope to finish REing it with my new knowledge Update: done. It’s simply one plane with tiles coded and palette transmitted before the compressed data;
  • Rollcage Ripper FMV—I REd it long time ago, I just need to locate my notes and finish it. Update: it’s in progress, decoding works, reconstruction is far from good though;
  • Rocketz VQM—I failed to find the code responsible for the decoding (and Ghidra decompiler refuses to work on many functions there), and DosBox debugger reports that these files are read in 16kB chunks, so no luck on guessing their internal structure. Maybe one day…

In either case that makes it ten original formats added since version 0.3 and about ninety in total. Two more originally REd formats and another dozen of formats REd and documented by others (those are easier to come by) and my goal for the next release is complete.

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.

NihAV: even further encoder improvements

Wednesday, April 9th, 2025

Since the last time I wrote about it somebody actually decided to test my transcoder on a bunch of fringe formats. The main issue there was wrong audio output (since I didn’t bother to check the actual input format, it often passed e.g. floating-point audio as 16-bit PCM, resulting in complete garbage). Additionally I’ve fixed a stupid bug in Indeo IVF demuxer (so now both known samples are decoded fine) as well as improving support for some other corner cases.

And there was one fun failure only my transcoder could have: when video streams starts with skip frame(s) and ZMBV encoder was selected, it refused to encode. I’ve added a work-around so now it simply presumes that frame to be black and goes forth normally (if you encode into raw video, such initial frames would be skipped instead).

So whatever can be decoded seems to be decoded and re-encoded just fine (but there are probably more cases waiting for their turn to be discovered). And there are some more formats waiting for an open-source decoder (in case of Motion Pixels the wait is likely to be very long).

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.

NihAV: encoder improvements

Friday, March 21st, 2025

Since I feel I’ve done enough (for a moment) on na_game_tool, I decided to work on the rather (always) neglected NihAV. And specifically on the nihav-encoder tool.

As you can guess from the name, it is a tool for re-encoding input file(s) into something else (or something the same). Since I don’t have much need in transcoding anything, I use it occasionally to test encoders (especially for collecting information by running encoding with different parameters on the selected sample set) or a muxer. Essentially if video is encoded correctly that’s enough, audio de-sync or even drop-outs (because not all encoded packets were actually muxed) is another thing. Finally I’ve decided to improve the situation and make it more usable.
(more…)

NihAV: hardware-accelerated playback revisited

Monday, March 10th, 2025

Recently I’ve made a mistake of upgrading one of my laptops to systemd 24.04. I can talk about various quality of life improvements there (like brightness control not working any longer so I have to evoke xrandr instead) but it’s so useless rant that it does not deserve to be written. What is worth talking about is hardware acceleration. Previously my player on that laptop had rather unreliable playback with VA-API decoding (i.e. it worked but some videos made it too laggy); now the situation has improved—it’s reliably unusable. Additionally it seems to consume only slightly less CPU than with software decoding. So I finally looked at the way to speed it up (spoiler alert: and failed).

Conceptually it’s simple: after you decode VA-API picture you need to obtain its internal parameters with vaExportSurfaceHandle(), create an EGL picture using eglCreateImage() (or eglCreateImageKHR()), blit it onto OpenGL texture with glEGLImageTargetTexture2DOES() and you’re done. It was not so simple in practice though.

Exporting descriptors is easy, I just modified my fork of VA-API wrapper to do that and it even seemed to produce correct output. The problems started with OpenGL integration. My player uses SDL2 so I spent a lot of time trying to make it work. First of all, it’s not clear how to obtain a proper OpenGL context for the calls, then there’s this problem of it being finicky and not liking multi-threaded execution. And of course you have to load all those functions mentioned above manually (because SDL2 offers only a small subset of all possible OpenGL functions—not surprising, considering how many of those are optionally supported extensions or missing in certain profiles).

Anyway, I threw away most of my player functionality, leaving just loading an input file, decoding it and trying to display only the first frame. It ended with a segfault.

It is probably because of (poorly documented) SDL2 wrapper doing, but it can’t provide a sane OpenGL context probably. So a call to eglGetCurrentDisplay() returns either NULL or a pointer that looks like a small negative value; the same happens with eglCreateImage() (fun thing that eglGetError() returns the same value, -424 if somebody is curious); at glEGLImageTargetTexture2DOES() call it finally segfaults.

At that point I actually tried searching for some alternative crates that would allow me to create an OpenGL window and call those functions—and found none fitting the purpose. They all are either provide rather limited OpenGL subset which is enough for drawing a triangle with shaders (and probably expect you to locate and load the library with the additional functions by yourself) or even simply provide OpenGL bindings, leaving even window creation to you.

In other words, not my kind of fun. I’ll simply disable hardware acceleration for all cases there until I find a better alternative.

P.S. Vulkan is not really an option either. My hardware is too old for ANV driver (and for HASVK driver too).

Random NihAV news

Saturday, March 8th, 2025

Since I can’t do anything about the world largest countries run by over 70-year old dictators, I try to find a distraction elsewhere. It usually works only until the next time I read next. Anyway, here’s something different for a change.

With all the work on na_game_tool I’ve been mostly neglecting the original NihAV (not that it makes much difference). So I’ve tried to improve it a bit and I have something to report.

First of all, I decided to make ARMovie support more complete (after discovering that e.g. the only thing that can play Eidos Escape 122 codec is their own DOS player). So I’ve added all three video codecs with known samples (Escape 122, 124 and 130) as well as their ADPCM codec. Sadly Escape 122 description in The Wiki is somewhat unclear, so I referred to the original DOS player for it. Similarly I looked at ADPCM decoding because what libavcodec produces is not quite right (but I guess Paul can tell you more stories about all those IMA ADPCM flavours). So I guess now my project has the most complete ARMovie formats support out there. There’s only one other third-party format I’m aware of (The Complete Animation film, it may be stand-alone or encapsulated in RPL) and I might get to it eventually.

The other thing is TrueMotion S. When you think there’s nothing unknown left about it, it manages to surprise you anyway. So I was looking at Discmaster search results for potential candidates (“aviAudio” is a good format for that—sometimes it is really AVI with audio track only, sometimes it is AVI with unknown video codec) and found three .duk files that were TM1 in AVI and which could not be decoded. It turned out to use codebook 0—which is not present in the open-sourced version of the decoder. Another thing is that it does not use so-called fat deltas (i.e. larger difference values), so code zero means eight zeroes instead of an escape value. Remarkably, this is demo of The Horde game by Toys For Bob, known to employ yet another exotic version of the codec in their 3DO version of Star Control II. It makes me wonder if they had the same relationship with Duck as JVC NWC with RAD (you know, the company which released a game with Bink-b videos not found anywhere else and bundling Bink-d decoder with one of their other games—all while others started with Bink-f or later).

Hopefully I’ll be able to do more in the future, but I wanted to share these stories while they’re still fresh.

na_game_tool 0.3.0 released

Tuesday, March 4th, 2025

This is finally a release I’ve been wanting to make—with a format for each letter of the alphabet! It features about twenty new formats supported, a dozen of them being newly reverse engineered by me and the rest coming from NihAV, various open-source game engines and my older RE work. The games are diverse too, as some of them come from Argentina, Finland, France, Germany, Israel, Japan, Spain—beside the usual English-speaking countries (I’ve not tried to achieve it but that’s a nice thing too).

As usual, it’s available here (but who really cares?).

Considering that I’ve mostly exhausted the games to look at and the goals for the next release are at least twelve new formats and to support over hundred formats in total (i.e. about twelve in total), I’m not sure the next release will happen this year. I’ll find other stuff to do meanwhile.

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.