Finally NihAV
got full* support for RealAudio. Marketing asterisk there is for AAC support since only AAC LC is supported which means decoding only 22kHz from racp
(as I said before, no SBR support) plus some other features were cut: it supports just multichannel audio but no coupling feature, noise codebook or e.g. LTP from AAC Main. Also for similar reasons I did not care to optimise its performance. I don’t care much about it and I don’t want to spend a lot of time on AAC. Here’s some fun statistics for you: AAC decoder is about 1800 lines long (IMDCT, window generation and bitstream parsing are common modules but the rest of AAC stuff is there), about 100 lines are spent on subband tables, 350 lines are spent on codebook tables and 250 lines are wasted on “proper” parsing of general MPEG-4 Audio descriptor with type-specific stuff like HILN or ALS configuration being simply left as unimplemented!()
(a useful Rust macro that will report it and abort program if it reaches that point so you know when to start caring).
And now for the fun Rust part.
My codebook generator takes something that implements CodebookDescReader
trait which is essentially a common interface that specifies how to get information for each codebook element (codeword, its length and associated symbol). While I had some standard implementations, they were not very useful since the most common case is when you have two tables of different types (8 bits are enough for codeword lengths and actual codewords may take 8-32 bits) and you want to use some generic implementation instead of writing the same code again and again.
In theory it should be easy: you create generic structure that stores pointers to those tables and converts them into needed types. It would work after some fiddling with type constraints but the problem is to make the return type what you want i.e. the function takes entry index number (as usize
) and returns some more sensible type (so that when I read code later more appropriate type will be used).
And that is rather hard problem because generic return type can’t be converted from usize
easily. I asked Luca of rust-av
fame (he famously does not work on it) and he provided me with two and a half solutions that won’t work in NihAV
:
- Use unstable
TryInto
trait that can try to convert input type into something smaller—rejected since it’s unstable; - Use
num_traits
crate for conversion traits that work with stable—rejected since it’s an external crate; - Implement such trait yourself. Hmm…
So I NIHed it by taking a function that would map input index value to output type. This way is both simpler and more flexible. For example, AAC scalefactor codebook has values in the range -60..+60 so instead of writing new structure like I did before I can simply do
fn scale_map(idx: usize) -> i8 { (idx as i8) - 60 } ... let mut coderead = TableCodebookDescReader::new(AAC_SCF_CODEBOOK_CODES, AC_SCF_CODEBOOK_BITS, scale_map);
And this works as expected.
There’s a small fun thing related to it. By old C habit I wrote initially &fn
as argument type and got cryptic Rust compiler error about mismatched types:
= note: expected type `&fn(usize) -> i8` found type `&fn(usize) -> i8 {codecs::aac::scale_map}`
Again, my fault but rustc
output is a bit WTFy.
Anyway, the next is supposedly RealVideo HD or RealVideo 6 decoder and then I can forget about this codec family and move to something different like DuckMotion or Smacker/Bink.
And in the very unlikely case you were wondering why I’m so slow I can tell you why: I am lazy (big reveal, I know), I prefer to spend my time differently (on workdays I work, on Sunday I travel around, that leaves only couple of hours during workdays, some part of Saturday and a bit of Sunday if I’m lucky) and I work better when the stuff is interesting which is not always the case. Especially if you consider that there is no multimedia framework in Rust (yet?) so I have to NIH every small bit and some of those bits I don’t like much. So don’t expect any news from me soon.
I’d argue that you’d NiH even if I some of those small bits are available in rust-av ^^;
(and yes I should publish more stuff)