The freedom* of choice

June 4th, 2024

Since the topic is no longer hot, I can rant on it as well.

Sometimes I get asked why I name the search company with the name starting with G (and part of Alphabet) Baidu consistently throughout my blog. There are several reasons for that, mostly it’s because since they use my work without acknowledging it I don’t see a reason to promote their name either, but more importantly, I feel the company would fit well into a totalitarian regime (on the top of course, they do not want to be mere servants). And recently they’ve proved that once again.

You should be aware of the theory of enshittification by now: at first company caters to the users, then it shifts its focus to the suppliers and finally it starts to serve its own interests. I believe it is just a natural manifestation of shifting power balance but not the intents: companies want to have all money (control, whatever) without doing much work, users prefer to have everything as cheap as possible instead; so in order to get a hold on the market a company needs needs to build a user-base first, then it still has to submit to the suppliers’ wishes (since it still depends on them) until it finally gets an effective monopoly so neither the users nor the suppliers have any other option. Of course in reality there are many factors that still limit companies (sometimes EU regulations can be useful!) so it’s not as bad as it could be otherwise. But who knows, maybe we’ll see the cyberpunk future with large corporations becoming de facto states.

Anyway, back to the Internet search. Previously there was such thing as Internet—a gathering of different web sites and personal pages—and there was a need to find a piece of information of a web site of certain interest. Thus search services came into existence. Some were merely a catalogue of links for certain topics submitted by people, other crawled the Web in order to find new information (IMO AltaVista was the best one).

And then Internet matured and companies discovered that money can be made there. And that’s when we started to get annoying ads—large Flash banners, pop-ups, pop-unders and so on (I vaguely remember time before ads became that annoying but I hardly can believe in that myself). But the process has not stopped there, ad revenue meant that now the sites have a reason to attract users not merely to increase the visitors counter (yes, many sites had such widgets back in the day). That’s how we got another pillar of modern Web—SEO spam. Also with the technological progress we got large sites dedicated to organising user content (previously there were such things as GeoCities or Tripod but they were rather disorganised hosting services for random user homepages), including the worst of them—social networks. Eventually those sites tried to replace the whole Web—and it worked fine for most users who get their daily dose of news, recreation and social interaction from one or two of those sites.

So we have these megasites full with ads and generated nonsense or plagiarised content and Baidu had a reasonable idea of cutting the middle man—if you stay on one site to browse mostly generated nonsense why can’t we provide it all instead of referring you to an ad revenue for a different site? And if you think this idea is bad, there’s not much you can do about it—the very limited competition acts the same. Starting your own search service would require an insane amount of bandwidth and storage to do it right (even the large companies had their search quality declining for years because the content has exponential growth while storage space for even indexing it is limited, so you have to sacrifice something less popular). Mind you, if you limit the scope severely it may work just fine, it’s scaling to all Web content and for general audience that is rather impossible.

Now where does freedom* (yes, with marketing asterisk) of choice come into this picture?

I remember reading back in the day how The Party solved the problem of lacking resources to fulfil needs of people. They declared that the needs of the people are determined by the party (so if you think you should have other food beside bread, mashed eggplants and tinned sprats—well, that’s your own delusion that has nothing to do with your real needs). It feels that Web N.0 companies decided the same—for now mostly in the form of recommendations/suggestions but considering the growing limitations (like avoiding seeing ads on Baidu hosting using Baidu browser—at least they have not introduced mandatory quiz after the ads like reportedly one russian video hosting does) it may soon be about as good as in China (i.e. when you try to deviate from the prescribed path you’ll be gently returned to it and if you persist you’ll be punished—banning your Baidu account seems to be as bad as losing social credit score already). That’s the real freedom of choice—they’re free to choose an option for you and you’re free to choose to accept it (also known as Soviet choice).

Good thing is that most people don’t care and I can manage without. Bad thing is that it spreads elsewhere.

I’m talking mostly about various freedesktop.org projects, especially systemd and GNOME. In both cases the projects offered a certain merit (otherwise they would not stand out of their competition and not get support of IBM) but with the time they became too large in their domain and force their choices on Linux users. For example, systemd may be a conceptually good init system but in reality it can work only with the components designed specifically for it (or do you have a better explanation for existence of things like systemd-timesyncd?). Similarly GNOME is very hostile to attempts to change GUI appearance, so when third-party developers failed to take a hint with plugins and themes breaking every minor release, GNOME developers had to explicitly introduce libadwaitha and forbid any deviations from the light and dark themes hardcoded there. At least finding an alternative there is still possible.

Well, there you have it. I’m not the first to highlight the problems and I’m not proposing a universal solution to them either. But if you ever wondered why I restrict myself on many modern technologies and NIH my own multimedia framework, here’s your answer.

All of legendary animation formats

May 31st, 2024

Since I’m still not in the mood to do something serious, I decided to play some adventure games from Legend Entertainment (you know, parser-based, mostly with EGA graphics). And some of their VGA games like Companions of Xanth or Eric the Unready contain full-screen cutscenes in unknown format. The earlier released Gateway II used the standard FLIC for many of those, SVGA games switched to .Q format—but nothing obvious for these ones. Blackstone Chronicles used QuickTime and thus is not interesting.

So I decided to look what ScummVM source code has to say about it (unrelated fun fact: it’s the only open-source project I donated some money to). Of course there’s a fork with some halfway done support of later Legend Entertainment adventure games, including its picture format support (no such luck for EGA-only games, it seems).

Apparently .PIC files are more a collection of sprites and even full backgrounds. Depending on the game one file may contain all room backgrounds, or just single area backgrounds plus related animations (e.g. flowing water or burning torches), or it may be character sprites, or—as one should expect—a cutscene.

Frames in .PIC may be full frames or delta frames. In the later case they only update a part of the screen (either by replacing an area or XORing it). The more interesting thing is how frame data is compressed. The reference code is reverse-engineered and not so informative, so it took some time to understand it. First apparently there are tables and code used to generate new tables, which turned out to be exactly what I suspected them to be—Huffman codebooks. After a bit more messing with the algorithm, it turned out to be yet another LZ77-based compressor with static codebooks and rather complicated coding that reminds me of deflate… Of course I got suspicious at this stage (it looked a bit more complex than in-house developed compression schemes for game engines usually are) and indeed, it turned out to be Pkware Data Compression Library. And I could’ve found that out simply by looking into strings in one of the overlay files. Oh well…

At least it’s yet another puzzle with formats solved. Also it’s the second time I recently encounter animation format using DCL for compression (previously it was Gold Disk animation). Which makes me wonder what other common LZ77 flavours were used in the animation and video formats. deflate (along with newer contenders like LZO, FLZ and such) is very common in screen-recording codecs. LZS was used in Sierra games .RBT, I vaguely remember RNC ProPack being used by some video format. Nightlong on Amiga used PowerPacker. Did anything use LZX (it came from Amiga before being bought by M$ so maybe it had a chance there)? LZRW? Homebrew schemes are dime a dozen (like all those LZSS variations), I wonder more about the (de facto) standard compression libraries being used in video compression. Anyway, I’ll document them as I encounter them 😉

Duck Control 1

May 18th, 2024

Back in the day there was no Bob but he had toys nevertheless. And of those toys for Bob was Star Control II. It is not a game for me to play (since my reaction time is not good enough for space battles), its 3DO version mentions “TrueMotion “S” Video Compression by The Duck Corporation” in the credits. Now that’s more my thing! I looked at it once, found it to be a lot like TrueMotion 1 but split into different files and looked no further.

But recently I got a curious request: apparently some people want to reuse the player code out of the game for playing videos on the console. And since the console is too old to support even micro-transactions (despite coming from the EA founder) let alone FullHD AV1, they look for something more fitting, which is mostly TrueMotion and Cinepak. As I remember, this format offers a bit more flexibility than the usual TM1 in some aspects (since the tables are transmitted in the video data instead of being stored in the decoder), so writing an encoder for it may be more interesting than it was for plain TM1.

Anyway, here I’d like to talk about this technology and how it differs from the conventional TrueMotion 1.
Read the rest of this entry »

Looking at random PAF

May 16th, 2024

So apparently there’s RIFF-inspired PAF format used in Bi-Fi racing game for DOS (essentially a promotional game for a local brand for sausage-in-a-roll snack).

It’s nothing to write a Multimedia Wiki article about but it’s somewhat interesting. Apparently it has one single CODE chunk that contains commands for updating frame—for all frames. It is pairs of (skip,copy) bytes that tell how many quads of bytes should be skipped on output or updated from the delta frames.

Delta frames are RLE-packed data in DLTA chunks, first 32 bits tell the unpacked data size, then it’s traditional RLE (top bit clear—copy data, top bit set—repeat next byte low seven bits times).

Apparently those files were intended to be used as an animated TV screen overlay on the jukebox background (maybe also for an intro but the CD-rip of the game didn’t have it). So on one hand it’s a mediocre format, on the other it’s somewhat interesting anyway.

Next I should explore the usage of a Duck codec on “iamaduck” console…

Oh No! More Amiga Formats

May 12th, 2024

I keep looking at those, no significant progress yet but here’s what I have got so far:

  • ClariSSA—I’ve managed to locate two routines in ssa.library that look like video decompression routines (one is more advanced version of the other SSA with over a hundred of opcodes, another one is a simple RLE) but I still don’t know how they relate to e.g. BEST or COST chunks inside IFF. Update: apparently it separates data like opcodes or plane values into those chunks, I’ll write in more details about it later;
  • DeluxeVideo—haven’t looked at it that closely but it resembles more of an animation system (e.g. Macromedia Flash) than compressed video frames. Update: that’s because it is, the file essentially contains references to the actual sprites and backgrounds plus the commands and effects to apply on them;
  • TheDirector Film—the player for the only known sample uses some LZ-based cruncher but I’m too lazy to spend time on reconstructing the unpacked executable (or mess with UAE let alone unpacking and powering on my expensive door-stopper with AmigaOS 4.1);
  • Magic Lantern Diff—nothing much to say, looks doable. Update: it turned out to be RLE-based and I’m not sure but it might be coding data vertically like Zoetrope did;
  • NTitler—this is essentially a binary script for the program, referring to external resources for everything and such. Not something particularly interesting or fun to look at.

And there you are. After I do what I can with these formats (though as you can see for two of them it’s “not worth looking further” resolution already) I’ll move to something non-Amiga entirely.

Looking at Adorage SSA

May 8th, 2024

So I’m still looking at the list of unsupported video formats from dexvert in hope something curious comes by.

First, out of curiosity, I looked at the unsupported Delphine Software CIN files. Apparently they merely don’t have audio streams and contain garbage in an audio part of the header (plus they have 1-2 video frames). Ignoring the audio header makes them decode. Next.

Second, EA MAD file—apparently it comes from a game rip with audio and video files being dummied out so it’s easier to share. Nothing to look here in any sense. Next.

So, one of SSA formats (no, not that one SSA animation format for Amiga, another one). It turned out to be rather complicated RLE for bit-plane coding. I.e. frames are coded as several bit-planes with the codec commands essentially being something like “skip to this offset in the current bit-plane, then update following 16-bit values with these new values, then skip a bit more and update some more values then skip…”. There are different opcodes for run/copy of certain sizes (or ranges) plus some additional operations for repeating a pair of values (and I thought LinePack was rather unique at that).

I actually ended up hacking a some decoder. It does not seem to handle 8-bit palettes well and there are still some glitches here (just look at the letter ‘D’ in the following image) but in works in principle.

From technical point of view it was not that hard. Even if Ghidra failed to decompile decoder function properly (mostly because of the opcode jumptable) it was nothing hard, even if I don’t know M68k assembly, expressions like move.l (A0)+,(A1)+ are rather intuitive so I could figure out which piece of code, say, copied 18 bytes and which one replicated the same 16-bit value to those 18 bytes.

I’ll try to find something else to look next, there’s still half a dozen of potentially interesting formats in the list.

ARMovie: trying codec wrappers

May 7th, 2024

I’ve managed to locate two ARMovie samples with video format 600 and 602 (which is M$ Video 1 and Cinepak correspondingly), so I got curious if I can decode them. The problem is that ARMovie stores video data clumped together in a large(r) chunks so you need to parse frame somehow in order to determine its length.

Luckily in this case the wrapped codec data has 16-byte header (first 32-bit word is either frame size or a special code for e.g. palette or a skipped frame, followed by some unknown value and real codec width and height) so packetising data was not that hard. The only problem was that Video 1 stream was 156×128 while the container declared it as 160×128 but after editing the header it worked fine.

Supporting such wrappers actually poses more of a question of design for NihAV—how to link those rather container-specific packetisers to a demuxer. Making demuxer parse all possible formats is rather stupid, my current solution of simply registering global packetiser and hoping there’s no need for another is a bit hacky. I should probably make it namespaced so that the code first probes e.g. “armovie/cinepak” packetiser before “cinepak” one but it’s an additional effort for no apparent gain. Speaking of which, I should probably change code to feed the stream provided by the packetiser to a decoder (instead of always using the one from demuxer) but since I’m lazy I’m not going to do that either.

Anyway, I’m not going to spend more time on ARMovie unless new samples for the formats I don’t support show up (beside newer Eidos Escape codecs which are supported elsewhere already). There are other formats left to look at. For example, I’ve made a good progress with Adorage animation format.

Looking at Ace Film

May 3rd, 2024

This is an old animation format on Acorn computers made by Ace Computing. It exists in several flavours.

There is bare Ace film that has barely any header (mostly just data size, title, some offsets) and chunks which start and end with the chunk size (so that you can seek backwards in the file). Then there’s chunked Ace film where all that data is wrapped into ACEF chunk with some other chunks following it (like RATE, FULL or PALE—the last one is for palette).

Presumably at offset 32 of raw data there is a compression method: 0, 1 or 2 (last one added in EuclidX). 0 means uncompressed data, 1 means LZW and 2 means unpacked data XORed with the previous frame.

Let’s take a closer look at method 1. It looks like a more or less conventional LZW. If the second byte of the stream is zero, the stream contains 16-bit little-endian LZW indices, otherwise it is variable-length LZW with initial index length being 9 bits (and value equal to 256) and growing up (the decoders don’t check upper limit but I suspect it should be around 16 bits). It also uses value 256 to signal the stream end and there are no other reserved values.

Apparently for convenience it decodes indices, stores them in the dictionary (it’s the property of LZW that each new index involves adding a new dictionary entry) and then decodes them backwards. After all, LZW dictionary entries are essentially stored in reverse so either you have to decode an entry, reverse and output it—or you can decode reverse string and output it at the end. This decoder chose the latter implementation (not that you can do it in any other way).

Unfortunately I’ve not managed to reconstruct data properly because of the implementation subtle details but I’m pretty sure anybody knowing how LZW works and willing to spend a bit of time fiddling with the format can come with a working decoder. As for me, it’s not interesting enough to spend more time on it. There are still several more ARMovie codecs to support and other formats to look at.

ARMovie: Moving Blocks done

April 30th, 2024

I’ve finally finished Moving Blocks HQ and REing Super Moving Blocks. The main changes from vanilla Moving Blocks is a larger MV table (vectors can now target as far as 8 pixels instead of previous 4 and the fact that now raw luma samples use delta coding and static Huffman codebook. The only difference between two newer variations is that Super Moving Blocks uses 6-bit luma samples (and larger codebook for handling twice as many possible delta values).

With this part done, all is left is adding support for various Escape codecs as well as raw audio and video formats. And ACEFilm of course, but that’s a separate format.

A quick look at Eidos Escape codecs

April 28th, 2024

As people remember, Eidos started as a company offering video editing software for Acorn RISC machines (do not confuse with Acorn RISC Machines company), but later it merged with a game publisher (more than once) and now it’s a Japanese game company. Yet the codecs they developed survived for some time in the games.

Since I was looking at ARMovie and found decompressors for Escape 100 and 102 codecs (essentially the earliest in the series) I looked at those as well and here’s a brief overview.

Both codecs are almost identical in design (only the luma code seems to differ), they operate on 160×128 frames in 5-bit YUV420 format, operating on 2×2 blocks. Chroma values are picked from the table of 256 combined U/V values. The codecs code data as a variable-length code for the number of blocks to skip (the same code seems to have survived until Escape 124) and the following block update mode (luma and/or chroma). As I said before, chroma values are taken from the table or left intact from the previous frame; luma values are coded two 5-bit values and 3-bit mask telling which value to use for the block elements (first element in the block is always the first value of course).

And that’s it. No other modes, the only frame header is 32-bit word with codec ID (later revisions decided to add frame size and even flags that affect decoding process). Nevertheless it’s rather interesting to encounter codecs that use simple two-colour vector quantisation (and fixed codebook for chroma pairs) without any additional image transformation tricks (e.g. motion compensation beside skipping, or even allowing raw blocks).