Compiling cwebp for Android with PNG/JPEG support
This post was originally published on Engineering@TelenorDigital.
TL;DR: Pre-configured git repo. Clone it and run
ndk-build
.
In an earlier post I described that power consumption is our main issue with Gonzo. We need the camera to run for a month or so on a single charge, and everything you do with the camera eats power away. A major cost in terms of battery life is uploading the photos that the camera takes. The photos that we take are 640x480, encoded as JPEG at 70% quality. That gives an average file size of a bit over 50 KB, and that takes 13 seconds to upload over a 2G connection. If we can get that down, that means less transmission time, and thus less power consumption.
There has been quite some fuss over new image formats that should compress better, of which BPG looked very promising. Unfortunately it’s built on top of x265, and licensing issues are withholding me from using it in any production system. Next thing: WebP, Googles image format based on VP8.
Mozilla thought about better compression too, and created a separate project named MozJPEG that gets better results at encoding images than Firefox’s default library libjpeg-turbo. Note that this won’t replace the default JPEG library in Firefox, but is something especially for encoding images. However, when I was working on the issue MozJPEG 3 was not out yet, and I didn’t look at how much improvement could be made over libjpeg-turbo.
As Gonzo is binary compatible with Android, and libwebp ships with an Android.mk file, it was quite easy to compile the project through the Android NDK.
$ ln -s $PWD $PWD/jni
$ ndk-build
As you can see I have no clue how to compile on Android without a /jni folder, so I just symlink to the current dir and all seems to be fine. Don’t try this at home.
This generates two ARM compatible binaries of cwebp and dwebp (encoder and decoder). Now when pushing the cwebp binary to Gonzo (through normal adb push
) I could not encode any images:
PNG support not compiled. Please install the libpng development package before building.
I asked a question about this on the webp mailing list but no ready answer was present. First thing I was wondering about was why the compiler did not complain about the lack of libpng and libjpeg, until I realized that in Android.mk the flags -DWEBP_HAVE_PNG
and -DWEBP_HAVE_JPEG
were missing. Adding the following line helps (delete obj/ directory first):
WEBP_CFLAGS += -DWEBP_HAVE_PNG -DWEBP_HAVE_JPEG
And gives me a useful error message:
jni/examples/jpegdec.c:21:21: fatal error: jpeglib.h: No such file or directory
#include <jpeglib.h>
While I was doing this I didn’t realize I could change Android.mk to compile libpng & libjpeg as static libraries and then use them later on from one file, as is done for the example_util library in libwebp/examples/Android.mk, so instead I:
- Added libjpeg, libpng and zlib to my source directory
- Added their .c files to the LOCAL_FILES in Android.mk (don’t add everything, quite some files don’t compile on Android)
- Made relative links to the header files instead of libraries (f.e. jpegdec.c)
Now running ndk-build
generates binaries that can also encode PNG and JPEG on Android. Victory!
It’s also a victory for Gonzo. We now encode images in WebP @ 60% and have acceptable image quality at 20-30 KB per photo. That shaves off half our transmission time (and adds 1 second for encoding) and saves us around 1,000 mAh in battery capacity!