Archive for the ‘QuickTime’ Category

nihav-movrender: alpha release

Wednesday, September 30th, 2026

I’ve decided to make a code drop release of nihav-movrender just for the completeness sake. If you look at nihav.org you should be able to find its git bundle among the rest.

One of the hardest parts was to create some documentation for it, so I’ve put something into README.md, hopefully that will be enough for all zero people who want to try it. Essentially if you provide it with the name of input MOV file and output directory it will try to decode the former and create some files in the latter (and if you omit output directory, it will put them into the current directory and you’ll have yourself me to blame for that). For tweaking that behaviour you need to refer either to nihav-movrender --help or to the aforementioned documentation.

Even in the current imperfect form it solves the tasks I wanted it to solve: extract (and convert to more convenient format) more exotic QuickTime tracks, and merge otherwise less accessible tracks (panoramas or multiple description tracks). The only thing it can’t do is to merge video from King’s Quest VI intro but it is a special situation (multiple independent tracks with edit lists to boot) so it will require a special handling. Beside that I have no further development plans for nihav-movrender and I’ll probably return to REing obscure formats.

Announcing nihav-movrender

Friday, September 25th, 2026

I’m not yet ready to release it but it’s a good time to tell what I’ve been working on (and intend to keep working for a while).

There are many valid QT MOV files on discmaster that are not decoded (or recognised for that matter, probably exactly for the reason they cannot be decoded). Looking manually into them often shows some exotic content not understood by any program (not even by QuickTime itself these days): Flash, MIDI, PDF, PPT, QT version of Flash aka sprites and so on. And in order to get some useful content out of such files I’m developing nihav-movrender. In theory it should be able to do at least this:

  • extract various kinds of binary data;
  • decode some exotic formats;
  • assemble QTVR or navigable MOV panoramas from individual frames;
  • merge tracks with multiple descriptors into one.

Currently I have first two items done and the other two should be easier to deal with (unless I hit some unforeseen complication of course). Below I want to talk more about different content that MOV files in the wild were discovered to have and how my tool deals (or hopefully will deal) with them.

Binary files

MOV files can embed various binary files, in different forms too. So far I’ve encountered three formats—namely Flash, PDF and PPT—and they all been stored in different ways. Flash files have their own stream type handler and it’s single file in single frame (but there may be two or more tracks with Flash files). The only sample with PDF came as many video streams, each of type “pdf” and containing a single-page PDF file. PPT, on the other hand, came in a generic data stream of sub-type “@ppt” with document split into several frames. In either case extracting them is trivial.

Media files

Occasionally a whole multimedia file of other format gets wrapped into MOV, the main examples being DV (I’ve never seen such a file and I’m fine this way), MPEG-1 (rather common) and ASF/WMF (generated by Flip4Mac). I’m mentioning those mostly for the completeness sake as I’m not sure if I want to do anything with them.

Auxiliary streams

There are several of those, for instance there’s timecode stream (considering that usually it contains just one frame I doubt it’s of any real value). There’s Tween stream (short for “between”) which is used to provide smoother transitions for other tracks (usually sprites).

I also encountered skin streams (which seem to contain single PICT file) and Quartz Composer media, where data is represented as binary .plist (with embedded PNG images if that helps).

Sprite system

Initially I assumed it’s a simple object-based animation system (like Flash Animation) but in reality it’s an interactive system involving multiple tracks i.e. usually one stream contains sprite data for content animation and another one handles controls. And the text streams (which are also complex constructions of QT atoms) seem to contain action handlers and relate to the sprites. So I ended up simply dumping decoded or extracted sprite images plus text-based description of what goes on there.

The process of decoding the samples I collected was rather fun. Sprite images may come in various formats, including GIF, JPEG, PNG, TIFF, Macintosh PICT as well as QT-compressed (usually RLE) frames. What’s more, those PICT files may contain RLE data of various kinds (sometimes even with larger dimensions than the image itself) as well as QT-compressed data. So apparently some presentation frames are coded as a command set like “set foreground colour to blue; paint a rectangle with it; and now call QT RLE decoder to paint the text”. Currently I don’t handle this situation well, so either the rectangle or overlay text is returned but it’s still better than nothing. And there are funny situations like 1100×800 JPEG image embedded inside 640×480 PICT.

MIDI

This data is stored in QT Music Architecture format (with each event data aligned to 32-bit word for convenience), sample descriptor having instrument descriptions and packets simply containing 1KB of data, whatever actual time period it may cover. I wrote a simple converter to SMF format and the result sounds OK to me.

QTVR

This format is actually stored in two or three tracks: image data split into strips and coded as individual frames, QTVR data and (optionally) panorama data. Since looking at a sequence of scenery pieces is rather boring, I want to make my tool assemble one large panorama from them.

Oh, and before QTVR there were Navigable movies (the same thing but simpler and with panorama data stored in track user data). I’m aware of four such files, one of them being the only known file employing CD-Graphics codec.

Other

If you look into QuickTime File Format Specification (it’s like ISO-IEC 14496-12 but older and available for free), it mentions even more auxiliary stream formats like hot sport image track, hint tracks and such. And of course it mentions 3D images, which must’ve been a killer feature at the time.


That’s why I alluded to this format as both common (since its derivative called MP4 is still the major multimedia container, even MXF can’t rival it; and MOV itself was extremely widespread back in the day) and exotic—you can’t claim that most things I listed here are used in modern multimedia workflows on daily basis (beside embedding font files in Matroska of course).

And who knows, maybe this will help me discover some more formats hidden in those files. The whole trove of QuickDraw flavours alone made it worthy for me.

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.

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.

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?).

Cinepak’s long-lost brother?

Monday, April 20th, 2026

While discmaster is stagnating (you know whom to thank for the shortages of HDDs as well as RAM), I still look through stuff there in hopes to find something interesting. Occasionally I manage to stumble upon something special indeed.

This time it was navigable movies bundled with QuickTime 1.5 or so. Apparently the idea behind them is that all frames are actually tiles of a much larger picture that user can navigate without exhausting all RAM trying to decode it as one contiguous image. If you thought about ISO H.EIC (aka HEIF or AVIf depending on intraframe codec employed) you may be right, but also it got re-branded (and maybe enhanced a bit?) some time later as QT-VR (sometimes I think no matter how stupid modern multimedia idea is, it’s been implemented in QuickTime a couple decades ago).

Anyway, out of four such movies, one was recognised and converted by discmaster software, two were playable (with my player) after I hacked file type tag to be MooV instead of APPL, the last one could not be decoded at all because it was of an unknown type.

Luckily for me resource data of that movie contained the decoder in m68k binary format (sometimes I think no matter how stupid modern multimedia idea is, it’s been implemented in QuickTime a couple decades ago—or did I say that already?). And just by looking at the frame contents I knew it was worth REing as I could spot YUV codebook right at the beginning and it was definitely not Cinepak (or Compact Video as it was known back then). The name was “CDROM Video codec” with tag cdvc but that didn’t tell me much. The file was created in 1992 while Wickedpedia claims that SuperMac Compact Video was added to QT around that time as well.

Anyway, let’s move to the format details. The codec starts with 24-byte header followed by YUV or (theoretically) RGB24 codebook, the another 24-byte header (containing frame dimensions among other things) and finally data. Frame is split into 4×4 blocks and first there is an opcode sent containing block type and number of blocks (minus one) of that type. Blocks are known to have three types: 4 vectors per blocks, 1 vector per block (scaled 2x), or simply skip.

The concepts of codebook-based coding are the same as in Cinepak, even YUV conversion formula is almost the same (with simplified coefficients using multiplication/division by two only). The main difference is using just one codebook for everything and coding format—while Cinepak uses separate bit masks for block types, this codec uses opcodes (which is common for other fruity codecs). So this makes me wonder where this codec comes from and how it is related to Compact Video. Was it some kind of predecessor? Was it developed by Malus as a competition or based on the licensed technology? Why was it abandoned?

Even if I ended up with more questions, it was still a fun way to spend a Sunday weekend (the rest of Sunday was spent travelling to/from Lower Ulm and it’s a differently fun way to spend Sundays; but that’s not the point here). Who knows, with a new search approach I may be able to uncover a couple more of ancient codecs to look at.

P.S. Another fun codec for very early QuickTime was SIVQ (that’s how it was called, I’ve failed to find anything but the decoder for it). It was simply 128-entry 2×2 codebook (in RGB24 format) followed by codebook indices. Probably the name stands for “SImple Vector Quantisation”. That makes it the third proper VQ codec in QT (SMC is a slightly different beast; and RPZA is the first texture codec instead).

A word about some JPEG-based codecs

Wednesday, March 4th, 2026

As I mentioned previously, I don’t want to work on game codecs for a while, so I picked other stuff instead. For instance, I’ve fixed a bug in my Indeo 3 encoder (which nobody uses, myself included), refactored some NihAV code and added a couple of decoders.

First, there is PDQ2 decoder. It actually turned out to be slightly more interesting than I expected as there’s a version of the codec for Saturn version of the game (it’s not that different yet somewhat different nevertheless).

Then I’ve finally managed to figure out MoviePak. After locating a decompressor binary and trying to disassemble it as raw M68k code I could locate enough code and data to figure out that since it uses JPEG codebooks it’s likely to be based on JPEG. And after learning a bit more about how it works and NOPing out A-line _StripAddress calls (that was the most interesting part actually—you can’t find it without knowing terminology and even then just barely; I was lucky to try searching for information about 68881, learning terminology and finally finding a reference of Macintosh Toolbox calls) I managed to make Ghidra happy enough to produce a usable decompilation. After that it was just a question of re-using JPEG decoder with a slightly different header format, which finally made me do a refactoring of JPEG decoding.

And since I’ve factored out common JPEG decoding support for MoviePak, Radius Studio and actual motion JPEG decoder, I decided to add a video codec for effects used in proDAD Adorage video editor (its FOURCC is pDAD, quite surprisingly). This one could be reverse engineered just by looking at the frame data. Each frame consists of 20-byte header, JPEG image plus alpha channel coded as PNG or JPEG. Since I have not bothered to write a motion PNG decoder (it’s very uncommon after all and I’m not NIHing image library—at least not yet), I decode just the first part. Maybe I’ll add a PNG decoder support and re-visit this decoder for proper alpha support, but for now this seems unlikely.

I’ll keep working on some boring stuff nobody cares about but maybe I’ll have a codec or two to write about as well.

Some words about the oldest QuickTime

Thursday, February 19th, 2026

Since apparently discmaster.textfiles.com ran out of space (because storage is not cheap now thanks to “AI” companies), I have no new formats to be distracted with and have to resort to looking at the old ones.

As we all know, A**le single-handedly invented multimedia and the existence of IFF ANIM (that pre-dates it by a couple of years) should not confuse you. From what I could find, the earliest QuickTime samples can be found on Apple Reference & Presentation Library 8 CD-ROM that was intended for demonstration but not for the consumers. That disc actually contains three flavours of QT MOV: ordinary MOVs that can be decoded without problems, slightly older MOV that looks almost the same but has slightly different format (and features version -1 both in the header and in the metadata strings) and some extremely old files that do not correspond to the usual MOV structure. Those apparently come from the alpha version of QuickTime around year 1990 when it was still known by its code-name after USian artist of Ukrainian origin.

The first glaring difference is that atoms are not strictly nested but may contain some data beforehand. Essentially all atoms that normally have special header atoms have it before the rest. So instead of (pardon my S-expressions)

(moov (mvhd (trak tkhd (mdia mdhd (minf …))))

there is

(moov [moov header data] (trak [trak header data] (mdia [mdia header data] [all codec description data])))

Data structure is flatter too. In release QT version data for the individual tracks is grouped into chunks, so the header describes both the chunks and what tracks use what chunks (and what are frame sizes in the chunk). Here frames are stored as (offset, size) pairs.

From the accompanying decoder I can see it supported raw video, RLE and motion JPEG at the time—fancy vector quantisation codecs came later.

I hope to support it one day but there’s no hurry. Currently I’m more or less done improving NihAV tools and want to add some practical demuxers, muxers (and maybe even impractical encoders like for Indeo 4 or RedHat Ultimotion). And there’s na_eofdec still waiting to collect enough supported formats for its first release (tangential fun fact: recently I’ve added support for Electric Image format there which is mostly a simple RLE but its frames apparently have timestamps in floating-point format like 0.266 or 0.5).

P.S. I’ve also discovered MoviePak QT codec which looks like JPEG variant. Maybe one day when I’ll have nothing better to do I’ll look closer at it, but for now I have no desire to reverse engineer M68k code in unknown format.

Quicker look at QuickTime

Sunday, February 1st, 2026

Since I’ve done looking at game formats for a while (I’ve updated na_game_tool 0.5.0 release with the fixed extraction of old-style Cryo Interactive archives BTW), I decided to look at my backlog of unsupported (either mis-detected as audio-only or not detected at all) MOV files from discmaster instead. Of course the majority of them are files missing their resource fork (and majority of the rest are poorly-recognised data+resource forks in MacBinary II format; that reminds me I should improve support for it), and majority of the rest are files that I support already (like Duck Truemotion 1 or Eidos Escape codecs). And a good deal of the rest are Flash in MOV (not going to touch it). And yet there are a couple of files worth talking about.

  • 911602.MOV—remarkable for having JPEG frame embedded in QuickDraw stream. It made me finally write a decoder for it (but without JPEG support, maybe one day…);
  • a couple of .flm files turned out to have obfuscated moov atom (with something almost, but not quite, entirely unlike TEA if you care). Not something I’d like to support;
  • La88110mN1Hz2_20-07.mov—it turned out to be raw YUV420 codec;
  • Omni_324.mov—compressed apparently by MicroWavelet on NeXT. Intriguing but I doubt anything else can be found about that codec;
  • Music Chase .tmv—a very weird little-endian MOV format with custom video codec (I think I mentioned it before but I haven’t progressed since);
  • there was one Flip4Mac-produced sample (which name eludes me), but considering that it stores ASF packets inside MOV it’s not something anybody is eager to support;
  • some undecodeable SVQ3 files—apparently they are encrypted;
  • and finally there are some QT Sprite files, which seem to be (often deflate-compressed) frames containing several atoms with commands and occasionally image data as well. Sounds too hairy to support but again, maybe one day…

With AVI situation is somewhat better, there are some poorly formatted and encrypted/obfuscated files as well (plus damaged files from AOL archives that start at random position, so contents may be AVI file with some additional garbage in the beginning or missing few dozens kilobytes of initial data). Beside that I’ll probably implement PDQ2 decoder just for completeness sake. Eventually.