F2 40 01 2A (some notes on SIMD, instruction sets and everything)

September 15th, 2009

I’ve been following the steps of Måns and got myself Gdium too. Since it’s no fun just owning less-spread computer architecture and not writing anything on it, I’ve tried SIMDifying the easiest operations one can do on it — vector sum, vector subtraction and vector scalar product. And I have a decoder that uses those operations extensively, so why not try to benchmark it a bit?

Test sample was first 26 seconds of Monkey Audio file with insane compression since this mode uses longest filters and benefits from SIMD most (and is slow enough even for short samples ;). In all cases I’m the one who has written SIMD code, so it’s fair 🙂

PowerPC (Freescale 7447A 1.42 GHz): 25 seconds and 6 seconds
MIPS (Loongson 2F 900 MHz): 37 seconds and 7 seconds
ARM (Cortex A8 600 MHz): 138 seconds and 22 seconds
x86 (Intel Atom N270 800 MHz): 50 seconds and 9 seconds

Mind you, SIMD instructions in Loongson are custom for that CPU and modelled after MMX (64-bit registers, actually reusing FPU regs, similar names) but at least they are done in RISC fashion, i.e. you can store result in some other register.


I’ve also looked out of interest at binary representation of SIMD. On x86 the principle is to prefix SIMD instruction (usually with 0x66 “opcode for CPU with half of current bits” byte) so SSE7 instructions will look like instructions for 1-bit FPU on Intel 4004 predecessor and will take 8-16 bytes to represent.

Other architectures use simple 32-bit word for any instruction. NEON (on ARM) and AltiVec (PowerPC) use some opcodes in general instruction space, Loongson 2 SIMD are custom calls to the second co-processor.

Talking about instruction sets I cannot omit the fact that IDA 5.2 sucks at disassembling PowerPC code (not only AltiVec but some of the core instructions too) and objdump sucks at disassembling MacOSX format (it ignores internal structure and disassembles it as raw file), that looks like the reason why we don’t have Apple Intermediate Codec RE’d yet.


P.S. Jag vill gärna få AVR32, BlackFin, ColdFire och andra exotisk CPU:ar. Alpha eller Sparc är bra ochså men det är bara orealistisk, tror jag.

Tell me how you pronounce ‘g’ and I’ll tell who you are

September 7th, 2009

As some of you may already know, I have a bit of interest in linguistics. Here I’ll try to describe an interesting (for me) fact. While some of the letters are read virtually the same in any language, some differ greatly. It looks to me that ‘g’ is the telltale letter because its pronunciation differs most in different languages.

Let’s see:

  • English: djee
  • French: may sound more like ‘z’ in “azure” (Je ne parle pas français, though)
  • German: IIRC, in words ending with “-ig” it’s read as soft ‘h’ or something (Ich spreche Deutsch nicht)
  • Hungarian: sometimes it’s read as ‘d’ (for example, in the name of country — Magyar)

And now for more exotic languages:

  • Ukrainian: it’s more like voiced ‘h’ or French ‘r’. For ‘g’ sound in loanwords another letter is used.
  • Belarusian: resembles Ukrainian but less voiced.
  • Japanese: it’s easy — you’ll never see it alone since they use syllable-based system, not letter-based.

And finally, in my homeland (och jag vet lita svenska) it may also sound in two different ways: more like in other languages (till exempel: “gamla”) and more like ‘j’ — listen at example from Wikipedia how to pronounce Göteborg correctly (you can hear ‘g’ at the beginning and at the end of the word).

FFmpeg: providing better alternative since 2000

September 4th, 2009

Few days ago FFmpeg finally got WMA3 decoder. This event gives me an opportunity to look at our achievements.

  1. Popular and/or standard codecs — supported except for the newest stuff (AAC-HE[2], H.264 interlaced modes, VC-1 interlaced modes).
  2. Windows Media — WMV1-WMV3 are supported (except for beta version of WMV3 and other WMV3 spinoffs). WMA1-WMA3 is supported too. We still have WMA Lossless and WMA Voice to RE and our top men are working on it (did you remember “Raiders of the Ark” ending? Neither did I).
  3. Real Media — RV1-RV4 are supported, from the variety of audio codecs only Sipro and Real Lossless support are missing. Sipro is in the works and nobody (including RealNetworks itself) cares about RALF.
  4. Intel codecs — Indeo 1-3 is supported, patch for Indeo 4-5 is available, IMC is supported, IAC is not REd (and not in queue).
  5. RAD codecs — REd, there are still some issues with Bink to sort out before inclusion.
  6. AVI codecs — that’s a mess. There are simply too many very codecs and new ones still continue to appear. Some are supported, most are not.
  7. Lossless audio codecs — some are supported, some are not. Again, looks like everybody writes own lossless audio or video codec. I’d like to get support for TAK though.
  8. Game video codecs — we still have a lot of them to RE. Personally I want Discworld III video (BMV, but it differs from the format used in Discworld II) support. *sigh*

If you think there’s some codec we definitely should support, please tell us (preferably with specification or decoder sources 😉 If you just want to have some codec support in FFmpeg — make us interested in it, some codecs support appeared in FFmpeg after somebody had said “can play that file?”.

Bink: pattern-run blocks

September 4th, 2009

And now for something completely the same.

Let’s talk about most interesting block type in Bink. I don’t know official name for it but I call it pattern-run block because of the way it’s coded. Idea is simple: there are runs of single colour and blocks of different colours like in your ordinary RLE; what can be interesting in that? But there is one thing — block is filled with runs/copies not in usual scan orders but following one of 16 predefined patterns – columns, spirals, Hilbert curve (Zelda pattern for some of us), whatever.

Here’s an example:
Scan pattern #13
(and SVG version)

I think it’s obvious how this helps block compression. The only bad thing about it is the fact it did not appear in Smacker (mostly because Smacker uses 4×4 blocks).


This concludes my series of posts about Bink.
“Works for me” patch against FFmpeg r19754 is located here.

Bink: a bunch of peculiarities

September 3rd, 2009

I’ve mentioned before that Bink differs greatly from other codecs. Now I want to walk over general structure of it and mark all peculiarities I’ve seen so far.

  1. Huffman coding. I think I’ve mentioned it enough times.
  2. Data coding. The fact that different values (block types, colours, run values) are coded in so-called bundles (i.e. groups) for at least one row of blocks at once. So when starting decoding new row bundles are checked whether there’s enough data and more is decoded if needed.
  3. 16×16 and 8×8 block mix. Sometimes encoder inserts 16×16 block into usual array of 8×8 blocks. Looks like those blocks can happen only on even positions which eases skipping decoded part of it. 16×16 block contents are actually 8×8 block contents scaled twice.
  4. Coding modes. There are 10 block types; three of them belongs to vector quantisation techniques (I’ll write another post about special run-length pattern block), two block types use DCT (more below) and another block type uses special coding for residue without any additional transform.
  5. DCT coefficients coding. I’ve written a bit about it already. Have I mentioned they also use non-standard scan order (designed for pairs of coefficients)?
  6. Coefficients quantising. There are 16 possible quantisers – 1, 1 1/3, 1 2/3, 2, 2 2/3, 3 1/2, 4, 5, 6, 8, 12, 17, 22, 28, 34 and 44.

I suspect that some of the things are legacy of Smacker and really clean design would go in slightly other direction – it’s not pure vector quantisation as it was but it’s not pure DCT-based codec either.

As for the progress: I have more or less working decoder in my own build of FFmpeg. When somebody kicks certain devs to push Bink demuxer and audio decoder into SVN codebase, I’ll give my decoder with that. Until then just wait.

Bink: ‘lossless’ block coding

September 2nd, 2009

First of all, I’d like to note that those names are taken from Bink code. In reality ‘lossy’ block is used as is and ‘lossless’ block is DCT coefficients.

And now, the differences:

  • in ‘lossless’ mode coefficients are decoded until mask becomes zero, there’s no explicit number of coefficients
  • coefficient bits are stored explicitly, not as several masks: coef[x] = mask | get_bits(log2(mask));
  • starting list somewhat differs

For those who for some unknown reason are interested in RE progress, I can say that my implementation is still far away from perfect. It crashes on 640×480 BIKi files and for those two files it plays (BIKf and BIKi) it gives barely recognisable image — I blame DCT and dequantisation (I haven’t looked at them yet).

Bink: ‘lossy’ coefficients reading.

August 29th, 2009

RTMP client seems to work fine, RTMP support in FFserver is not that close, so I work on REing some codec which seems to be rather widespread in games.

OK, now to technical details. ‘Lossless’ coefficient coding is similar but a bit more complicated.

For each 8×8 block there is 7-bit number specifying number of masks to read (mask = part of the coefficient), slightly resembling progressive JPEG coding; coefficient value may be composed from several masks, high bits are decoded first. Decoding continues until all masks are read.

Coding method is not that comprehensible though: there is list of start coefficient and modes, so decoding iterates over this list and performs some action depending on mode. Have I mentioned that aforementioned list may change during operation?

And here’s decoding algorithm (if I got it right):


mask = 1 < < get_bits(3) iterate over already decoded coefficients, if read bit = 1 then add mask to the coefficient iterate over list of modes until end is reached, if (coef,mode)==(0,0) or read bit = 0 then skip current entry:   mode = 0:    set current entry to (cur_coef+4; mode = 1)    for(i=0;i<4;i++, cur_coef++){     if(get_bit()) prepend list with (cur_coef, mode = 3)     else coeffs[cur_coef] = get_bit() ? -mask : mask;    }   mode = 1:    set current entry to (cur_coef; mode = 2)    append (cur_coef+4; mode = 2), (cur_coef+8; mode = 2), (cur_coef+12; mode = 2) to the list   mode = 2:    set current entry to (0; mode = 0)    for(i=0;i<4;i++, cur_coef++){     if(get_bit()) prepend list with (cur_coef, mode = 3)     else coeffs[cur_coef] = get_bit() ? -mask : mask;    }   mode = 3:    coeffs[cur_coef] = get_bit() ? -mask : mask;

Brief notes about Bink

July 13th, 2009

If you play a lot of games (or maybe not that much) andd are interested in watching their FMVs you should hear about Bink sooner or later.

This is rather widespread codec in games and it’s sad we still don’t have an opensource decoder for it.

Here are some facts about it:

  • Container format seems to inherit a lot from Smacker.
  • There are two different audio codecs differing by transform.
  • Bink video is mostly static Huffman coding + vector quantisation or DCT

So, why not reimplement it?
Here are some more details about video:

  1. It employs static Huffman coding – there are 16 predefined trees which are used to decode a lot of data — the only exceptions are block coefficients. Tree definitions include only tree number and how to reorder table of symbols for current data.
  2. Almost all values are coded in bundles for several blocks at once (usually for half of a frame)
  3. 8-bit values may be encoded as independent nibbles or high nibble may have context-dependent encoding when it’s encoded with a tree number equal to the last high nibble (so you need 16+1 trees for that but who cares).

The rest will be available as it goes.

A bit on Interplay MVE 16-bit

April 29th, 2009

For those, who are interested in playing 16-bit MVE files (yes, Mike, I am talking about you) here are some bits of information I’ve gathered at my leisure:

  • you have to skip 16 bytes from block map at the beginning instead of 14 for 8-bit MVE
  • colours are now stored as 15-bit (obvious, isn’t it), and high bit may be set for pattern fill order (8-bit MVE just compared colour values, which still works)
  • for some opcodes pattern fill order was changed a bit (i.e. subblocks scan order)
  • some opcodes meaning was changed completely. Opcode 3 does not requires additional bytes to be read anymore.

I didn’t have a desire to complete it, especially because it’s no fun to debug how motion is stored, so I just hacked existing decoder a bit to decode 16-bit files. Here’s a picture produced by maimed libavcodec/ipvideo.c:

interplay16

In the memory of my ThinkPad

April 29th, 2009

I bought my brand newrefurbished IBM ThinkPad 390 six years ago. While its hardware may be laughable by the current standards – PII-266, 192MB RAM, 4GB HDD – it was my computer where I started developing for FFmpeg. GCC compiling libavcodec/motion_est.c was the reason for adding 128MB to original 64MB of RAM. IIRC, all of codecs development till 2006 GSoC (VC-1 decoder) was done on it.

When I moved to MacMini, it still served me – as a router (it’s hard to see COM port on modern hardware, so modem was connected to TP390, later it was ADSL modem and second PCMCIA network card), as an x86 platform (mostly for running IDA and binary codecs) and for Internet-related stuff (cvs and git server, mail fetching, small web server, downloader and such).

Here’s how it looked for the last years:

i390

Rest in peace.

Now I have Asus EEE 701 working instead of it. Since it’s more compact, I can also fit BeagleBoard on the table next to it.