ROM Hack Video Codec for GBA?

Foxi4

Endless Trash
Global Moderator
Joined
Sep 13, 2009
Messages
30,824
Trophies
3
Location
Gaming Grotto
XP
29,818
Country
Poland
You're literally the first person I've ever met that's more well-versed in Assembly than in C, your kind is almost like the dinosaurs these days. :rofl2: Perhaps you have a bright future in hardware engineering, 9 out of 10 times it's the other way around - people tend to be more accustomed with higher-level languages (not that C is very high level - it's pretty much as low as you can go before you hit Assembly).
 

Normmatt

Former AKAIO Programmer
Member
Joined
Dec 14, 2004
Messages
2,161
Trophies
1
Age
33
Website
normmatt.com
XP
2,181
Country
New Zealand
I've seen that library before. I managed to build a test project with Burton Radon's C-based library (not something I do very well), and gasp. . .it decodes the same JPEG just a tiny bit slower than my pure ASM one! (To be fair, I ran both from CARTROM, as there were some devKitPro errors that disabled IWRAM.) However, my only real problem is that I don't understand C very well, which is why I prefer to program in ASM. Translating the C code with all those structs and typedefs, pointer-to-member. . .let's say that the end result better be worth it! Which is why I based my library on Frohwein's library: I could follow that C code. Perhaps the less understandable C code is, the more efficient it is. (Because CPUs don't speak English.)

Probably the routine costing the most in CPU cycles in my version is the "Decode" routine, where the CPU is searching through the Huffman tables for a match. Expanding the table for a straight-match would require 16KB of memory (if I recall correctly).

Thanks for the tips. I do get what you're saying about the Caimans' encoder, although I can add 2MB of DRAM to the Propeller externally...


Haha. Just let the compiler do the C->ASM then you can just disassemble the elf file to get all the function/struct names.
 

DSLSC

Active Member
OP
Newcomer
Joined
Aug 27, 2013
Messages
29
Trophies
0
XP
87
Country
United States
You're literally the first person I've ever met that's more well-versed in Assembly than in C, your kind is almost like the dinosaurs these days. :rofl2: Perhaps you have a bright future in hardware engineering, 9 out of 10 times it's the other way around - people tend to be more accustomed with higher-level languages (not that C is very high level - it's pretty much as low as you can go before you hit Assembly).

I definitely agree that C is probably the first level above assembler. But even so, in programming both the GBC, GBA (and yes, DS), I always end up getting completely frustrated with the compiler toolchain when programming in C. Usually it's the linker that I have the most difficulty with. I've had different frustrations with the C-compiler for each Nintendo product I've tried to use:
- in the GBC, the compiler was constantly "optimizing" important routines out. So I'm wondering, "Why isn't it working?" Then I peek at the assembled source code, and guess what I didn't see. Or I'd see the compiled ASM source code and say, "They only needed 2 instructions for that, not three!"
- in the GBA, I just didn't have enough control of the system, and besides, it's that C-thing again. I finally tackled ASM and found it soooooo easy by comparison. That is, after I learned ARM7TDMI ASM. I had a lot of fun with the JPEG library, especially on the occasions where I could translate one line of C code to one ASM instruction.
- in the DS, I tried to update dsBible, but got completely stymied by an update to the filesystem library, which changed the operation of "fread." Strings are NOT one of the strengths of C-programming. When it comes down to strings in C, you're not in very good hands!
- Oh yes, also for Windows, in Visual Studio. I was trying to write an emulator for the GBC, and was making pretty good progress...until I switched the compile mode from Debug to Release (to get the final speed)...and the errors spilled out like crazy, all pointing at innocent lines of code.

Admittedly, I enjoy programming in assembler on any platform (except a PC!), and that basically includes the GBC Z80, GBA ARM7TDMI, Microchip PIC10/12/16/18/dsPIC30, and the Parallax Propeller. The main reason? My projects always need 100% complete control of the device, and I can't figure out what the C library is going to do this time with the RAM, or where it's going to put something.

Bright future in hardware engineering? Well, if I don't understand how C works very well, writing compatible ASM might be a slight challenge. I'm not really asking for a barrage of responses from well-educated C-programmers (maybe!), but I've never really understood how memory allocation works. And that's a problem if you put an absolute address to a memory location that ends up being taken by C code. Oh yes, I get it—just dump that 5K array on the system stack!

Normmatt: Very true. (Then I'll be saying, "Wow, I can't believe how much faster my ASM version will be!") Thanks for the valuable hint.
 

cualquiercosa327

Well-Known Member
Member
Joined
Mar 24, 2009
Messages
201
Trophies
1
XP
428
Country
Hello guys,
Sorry if I'm coming back to you after so long. I was cleaning up my secondary email accounts and I found recent inquiries about the GBA Caimans codec. A quick search took me here, so I thought I would spend some time to answer your questions.
But first I have to say that, as most of you probably understood, I've been away from the GBA for quite some years, so please forgive me if some memories are blurred. Caimans codec was born out of an experiment and my will to learn how to develop for the GBA. It evolved into a commercial project, but the drive behind it never ceased to be the same one that brings you guys here: to have some fun. It was probably the last time I had so much fun developing something, and I have fond, albeit distant memories of it.
I eventually sold my IP to Activision (in 2007, I think) and thus I cannot release the encoder (not that I would know where to find the source code any more). The websites are still up an running as a form of nice memory, but really the service is no more.
That said, after all these years, I think it's fine to give a very high level description of the techniques that were used. I'm really grateful that you are still talking about this codec after so many years, but it really was nothing fancy and I'm sure that you guys can now do much better than that humble Italian bedroom coder.

There really existed 3 versions of Caimans codec: The caimans codec, the caimans codec pro and the caimans codec for DS.

Caimans Codec / Caimans codec 2: http://www.caimans.net/gbavideo/demos2.shtml
This first version was extremely simple: it used fixed 4x4 pixels codebooks. On the encoder side, each frame is converted to the YUV12 colorspace, divided in static blocks of 8x8 pixels (so you get up to 30x20 blocks on a GBA screen). A first pass of the encoder finds out the "scene changes", or frames that differer for more than a certain % from the previous one. Scene changes are called I-frames. If more than a certain number of frames go by without any scene change, an I-frame is forced anyway.
For all the frames in between two I-frames -we call then P-Frames- the encoder would then identify a set of codebooks that it could use to approximate all the blocks of all those frames. I think I used 20-30 kbytes sets, depending on the target quality. The search for the optimal set of codebook was done with k-mean algorithm and each block could be encoded with a single entry or a set of 4 entries in the codebook table (more on this later), or with a special code "zero", which means "do not update this block from the previous frame". Since codebooks are 4x4 pixels and blocks are 8x8 pixels, a block can be either a single codebook entry which is X and Y doubled at playtime, or a set of 4 codebooks. This simple tweak made it possible to encode sequences where some objects zooms in or out quite effectively.
That's it for the encoder.
At play time, the player simply gets an I-frame and a set of codebooks. It displays the I-frame then proceeds to decode the p-frames using a timer driven irq (I think). Each call just updates the blocks that need to be updated reading from the codebook table. This until a new I-frame is reached and a new codebook table is fetched.
Seek was possible as each I-frame is completely independent. So the rom had a table with the offset of the I-frames and the player could simply jump to that offset.
I remember that I frames, including all the codebooks, ended up being huge, so the codebooks were not physically stored together with the I-frame, but each of them was "streamed" together with the P-frame that was first using it.
The first implementation was done in C and it was a mess but I managed to circulate a couple of proof of concepts around. I had no plans other than that. But one day Activision calls me to use it in Spiderman 2! They asked me if it was usable as a library. I said "yes!", but of course it wasn't :-). A few sleepless night followed that email (I had a proper job to do during the day) during which I rewrote a lot of the code in assembler, I made a library out of the player and I was able to send it to them. I remember that, because of the simplicity of the encoding technique, it was extremely fast. I remember I could run it at 60 fps if I wanted, and the whole player core was only few KB and would fit entirely in the on-chip memory, or whatever it was called (sorry, I forgot the GBA-terminology).
I also developed a very simple audio codec based on ADPCM, but to be honest, although some of the demos on the website use it, it was never used in commercial videogames: the bitrate required for the video was so high (I think that it was 50-70Kbytes/sec) that saving few kbytes on a 16Khz 8-bit PCM mono track was totally pointless.

Caimans Codec Pro: http://www.caimans.net/gbavideo/demos.shtml
After the codec appeared in Spiderman 2 and in a number of other games, I got calls from other developers who wanted to store more video. I developed the caimans codec pro for the purpose, which further expanded the original idea. This time I used the YUV9 color space, but the main difference is that it added variable size and non-square codebooks. Again, a block is always 8x8, but codebooks can be one of the following sizes:

8x8
8x4
4x4
4x2

A block is encoded and decoded recursively: if a good 8x8 approximation is found, then go with it. Otherwise break the block into two 8x4 and go down recursively. you could end up with a block that had the upper half encoded with a single entry, the lower half encoded with 4 entries, or 6 or whatever.

On the top of that, I added a very basic form of motion compensation. A block could also be "shifted" (only entire pixels, no fancy qpel or halfpel) in the predicted frame. It really did something for the compression rate, but it killed the efficiency at playtime (more on this later)

I kept the k-mean algorithm as the foundation of the encoder, but due to the complexity of the new algorithm, the codebook search was painfully slow. I remember that it took a good 30 minutes to encode less than 1 minute of video on my pentium 3. It would have been trivial to improved the encoder, but I never really liked to work on that part, I was so much more into optimizing the player :-).
speaking of it, I did any trick I could come up with, I optimized my code as much as I could, but I never managed to push it beyond 15fps. Which was enough though. The video quality was only ok imho, but the bitrate could go down to few kbytes per second. It was only used commercially in a couple of products. One of them, A Lizzy Mcguire title, contained a full episode of the show (I think it was 24 minutes). I remember the producers only gave me 10 megabytes to store the entire episode. It was painful to hand tweak sequences to save up to the last bit, and the result didn't look very nice, but kids liked it. Go figure.

Caimans Codec DS: www.ds-video.com
This started as an experiment after I had given my GBA IP to Activision (they never used the encoder after that though... go figure). I started toying with the DS to see if I could repeat that experience. The GBA was fading away anyway...
At first I ported the GBA caimans codec pro, which was quite easy to do and would play at much higher frame rate due to the faster CPU (there might still be some demo on the website). But I wanted to do better so I started thinking of a full featured mpeg4 decoder. I remember I started downloading the source code of the reference mpeg4 Simple Profile player and hammered it until I had it compile for the DS (which took a long time). Finally it does, and plays video. Yeah, B/W footage at 0.5 fps :-).
But that was a starting point, so I started profiling the player, rewriting everything from scratch and moving to assembler for the the critical parts. I added a lot of tables to speed up computation, I got rid completely of Floating Point math and so on. I got some 8-12 fps on regular mpeg SP streams and I felt I could not do better than that. So what I did was I started tweaking the mpeg4 encoder until it would bias the encoding towards those elements of the mpeg4 framework that I knew I could decode faster (codebooks) and using less and less of what I could decode very slowly (half pel, all kind of motion vectors etc). So, the player is technically playing mpeg4, but the encoder is encoding a stream that is meant to be a bit easier to decode. This had a minimal impact on the quality, but allowed me go past the 15 fps barrier that I considered the minimum acceptable quality.
But everyday life, the job etc were starting to be more demanding, so I never really pursued that interest any more. I remember I released a dragon's lair prototype, but that was it.

Thanks for bringing back those epic times, and good luck with your efforts!

Hello Tony . A lot of thanks for your post.
 

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
    K3Nv2 @ K3Nv2: https://youtu.be/K-Gqyv0gkHc?si=nGlIcg7Lr7OPfc4a