Blog: 3D Fun with Android (2012-07-13)

Over the past week, I finally found (or rather took) the time to
implement my second app for Android:
AnaCam!
The idea was floating around
in my head already for some time (since I started experimenting with
anaglyphs), and now it is done! Feel free to
take a look at it, I like how you can play around with the live
preview. So far, I've only tried it out in my flat (which also means that
I won't provide example pictures yet since I want to have something
more exciting), but hopefully
will have some possibilities soon somewhere "in the wild"—I'm
definitely looking forward to it!

It was however also quite "fun" to make it work. The first
stumbling block for me (and also lots of
others)
was that the camera preview frames Android delivers, and which I use
for the live preview but have to manipulate, are encoded in the
YUV colour space while all the rest of Android
(especially drawing) needs RGB. There is some
facility available (the
android.graphics.YuvImage
class)
to convert YUV to RGB, however only via a lot of detours of compressing the
result as JPEG image, writing it to an output stream,
and then loading the bitmap again.

To optimise this and also to get a usable performance of anaglyph creation
for the live preview, I implemented finally some low-level image processing
routines in
native
code. I was surprised at how easy it
is to use the JNI
in Android to utilise the full
processing power!

And finally, Android enforces a very
weird
restriction on the heap size of each app. On my phone, which is already
relatively old and surely on the low-end of todays Android devices, my app
was only allowed to use 32 MiB of heap storage! This is
ridiculously small for any modern system, and in particular given that
even my device has 256 MiB memory available. Working with
the camera's pictures is quite memory intensive, and so I ended up
getting OutOfMemoryError's. (Note that in the mean time,
Android implemented a
largeHeap
flag. However,
this is not yet supported by my device's Android version, and thus
I obviously did not make use of it.) One way out, which finally worked for
me and which is described by the blog post linked at the beginning of this
paragraph, is to allocate memory in native code as this does not count
towards the enforced limit. Given how easy this restriction is to
circumvent, it appears even more useless and silly than before, but
anyways. Loading off the bitmaps to native memory (since I processed them
in native code this was quite easy) and carefully null'ing
every variable as soon as possible in the crucial code paths finally
made it work. Still, especially this last piece about the memory
limitation was really quite "fun"....