Saturday, May 10, 2014

HEVC/H.265 Video Decoding on Android

HEVC Decoding on Android - Porting lib265 to Android using NDK - Part I


libde265 is an open source implementation of the h.265 video codec. It is written from scratch in plain C for simplicity and efficiency. Its simple API makes it easy to integrate it into other software.

Before jumping into the build using NDK, we will understand the build procedure for lib265. 


Install the pre-requisites (Ubuntu 12.04) -

sudo apt-get install autotools-dev
sudo apt-get install automake
sudo apt-get install libtool


Download the code from the location:

https://github.com/strukturag/libde265

As per the documentation, the script "configure" must be generated using the 
script "autogen.sh". As we are interested in the static library, we will disable the
build of other programs.

--disable-dec265        # Do not dec265 decoder program.
--disable-sherlock265   # Do not build sherlock265 visual inspection program.

Many of the existing open source libraries can be built with the shell command 
"./configure; make; make install". In our sample project, we wrote a build_android.sh 
script to execute the three steps with the Android NDK cross compiler.


Define variables:

As the installation paths may be too long, we can define variables and use those variables 
rather than the absolute paths. Here we define a variable NDK specifying the path where 
our NDK is installed.

NDK=/home/ramesh/Android/Google/NDK/android-ndk-r9


Select the appropriate toolchain:

Based on the CPU architecture (ARM, x86 or MIPS) of our targeted devices, you need to 
choose the corresponding toolchain. The toolchains are available under the toolchains 
folder of Android NDK r8d. As we want to build for ARM, we will use 
"arm-linux-androideabi-4.8" toolchain. We will specify this as-

TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64

$NDK refers to the Android NDK root folder.


Select the sysroot: 

Based on the Android native API level and CPU architecture we want to 
target, you will need to choose the appropriate sysroot. The compiler will look for 
headers and libraries under the sysroot directory at compilation.

The path to sysroot follows this format: 

$NDK/platforms/android-<level>/arch-<arch>/

$NDK refers to the Android NDK root folder, <level> refers to the Android API level, 
and <arch> indicates the CPU architecture.

Based on my environment the SYSROOT is:

SYSROOT=$NDK/platforms/android-8/arch-arm/

The sysroot option "--sysroot" would be specified along with the cross compiler.


Specify the cross compiler:

The library's existing build system usually has a way for us to specify the cross 
compiler. It is usually through a configuration option or an environment variable.

In libde265, we can enter the "./configure --help" command to see how to set the compiler. 
The compiler command is specified through the environment variable CC, while the 
environment variables CFLAGS and LDFLAGS are used to specify the compiler flags and 
linker flags. In our build_android.sh script, the CC environment variables is set 
as follows:

export CC="$TOOLCHAIN/bin/arm-linux-androideabi-gcc --sysroot=$SYSROOT"



Specify the output locations for the header files and library binary: 

The output would be generated in the folder ./android/arm
It would contain two folders, "lib" and "include" containing the library and header file
respectively. We specify this by passing the following options to configure the script:

--prefix=$PREFIX

where

CPU=arm
PREFIX=$(pwd)/android/$CPU

Specify the system types:
The following System types are available:
--build=BUILD     configure for building on BUILD [guessed]
--host=HOST       cross-compile to build programs to run on HOST [BUILD]
--target=TARGET   configure for building compilers for TARGET [HOST]
  
We specify the values as-
--build=x86_64-unknown-linux-gnu
--host=arm-linux-androideabi
--target=arm-linux-androideabi


Make and install the library: 

You can simply execute "make; make install;" to build and install the library.

The complete build_android.sh is as shown below-

#!/bin/bash
NDK=/home/ramesh/Android/Google/NDK/android-ndk-r9
SYSROOT=$NDK/platforms/android-8/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64
export CC="$TOOLCHAIN/bin/arm-linux-androideabi-gcc --sysroot=$SYSROOT"
function build_one
{
./autogen.sh
./configure \
--disable-dec265 \
--disable-sherlock265 \
--prefix=$PREFIX \
--build=x86_64-unknown-linux-gnu \
--host=arm-linux-androideabi \
--target=arm-linux-androideabi \
make clean
make
make install
}
CPU=arm
PREFIX=$(pwd)/android/$CPU
build_one


Building the library:

To build the library, do the following steps-

1. Save the build_android.sh file to the libde265 folder
2. Add the execute permission to the build_android.sh file with the following command:

   $ sudo chmod +x build_android.sh

3. At a command line shell, go to the libde265 directory, and enter the following
command to build the library:

   $ ./build_android.sh

Once the build completes successfully, check the android folder in lib265. The following
files should be present-

android/arm/lib/libde265.a
android/arm/lib/libde265.so

android/arm/include/libde265/de265.h
android/arm/include/libde265/de265-version.h

Other options can also be specified which I will cover in other post.



Ref: 

1. Android NDK Cookbook
2. https://github.com/strukturag/libde265