Friday, December 27, 2019

Compile libyuv 32bit and 64bit native libraries for android

Compile libyuv codebase for android to generate 32 bit and 64 bit native libraries.

libyuv is used to rotate NV21 raw data obtained from device camera when the device is held in portrait mode. Sadly android does not provide any API that alters the raw data it provides through the onPreviewFrame callback, so was looking for a way to rotate the NV21 by 90 degrees and libyuv came to the rescue.

I was facing an issue compiling the latest codebase so I checkout an older commit from 2015 as it has the functions that serves my purpose.

Prerequisites:-
  1. NDK setup must be done, and you must be able to compile sample ndk-apps provided in the android-ndk.
  2. Download the libyuv codebase.
The directory that gets created once you do SVN checkout is the libyuv root directory, am going to refer it as LRD (LIBYUV_ROOT_DIR).
LRD contains an Android.mk file which we are going to use to build our shared library (of-course some modifications would be needed).

Once the above prerequisites have been met, then proceed with the following steps to build the shared library:-
  • Create a jni folder in LRD.
  • Copy the Android.mk file to it.
  • Create an Application.mk file and add the following lines to it. 
APP_PLATFORM := android-21
APP_ABI := all
  •  Modify the Android.mk file as below to point to the source code correctly
# This is the Android makefile for libyuv for both platform and NDK.
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := \
$(LOCAL_PATH)/../source/compare.cc \
$(LOCAL_PATH)/../source/compare_common.cc \
$(LOCAL_PATH)/../source/compare_posix.cc \
$(LOCAL_PATH)/../source/convert.cc \
$(LOCAL_PATH)/../source/convert_argb.cc \
$(LOCAL_PATH)/../source/convert_from.cc \
$(LOCAL_PATH)/../source/convert_from_argb.cc \
$(LOCAL_PATH)/../source/convert_to_argb.cc \
$(LOCAL_PATH)/../source/convert_to_i420.cc \
$(LOCAL_PATH)/../source/cpu_id.cc \
$(LOCAL_PATH)/../source/format_conversion.cc \
$(LOCAL_PATH)/../source/planar_functions.cc \
$(LOCAL_PATH)/../source/rotate.cc \
$(LOCAL_PATH)/../source/rotate_argb.cc \
$(LOCAL_PATH)/../source/rotate_mips.cc \
$(LOCAL_PATH)/../source/row_any.cc \
$(LOCAL_PATH)/../source/row_common.cc \
$(LOCAL_PATH)/../source/row_mips.cc \
$(LOCAL_PATH)/../source/row_posix.cc \
$(LOCAL_PATH)/../source/scale.cc \
$(LOCAL_PATH)/../source/scale_argb.cc \
$(LOCAL_PATH)/../source/scale_common.cc \
$(LOCAL_PATH)/../source/scale_mips.cc \
$(LOCAL_PATH)/../source/scale_posix.cc \
$(LOCAL_PATH)/../source/video_common.cc
# TODO(fbarchard): Enable mjpeg encoder.
# source/mjpeg_decoder.cc
# source/convert_jpeg.cc
# source/mjpeg_validate.cc
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_CFLAGS += -DLIBYUV_NEON
LOCAL_SRC_FILES += \
$(LOCAL_PATH)/../source/compare_neon.cc.neon \
$(LOCAL_PATH)/../source/rotate_neon.cc.neon \
$(LOCAL_PATH)/../source/row_neon.cc.neon \
$(LOCAL_PATH)/../source/scale_neon.cc.neon
endif
ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
LOCAL_CFLAGS += -DLIBYUV_NEON
LOCAL_CFLAGS := -DHAVE_NEON=1
LOCAL_ARM_MODE := arm
LOCAL_ARM_NEON := true
LOCAL_SRC_FILES += \
$(LOCAL_PATH)/../source/compare_neon64.cc.neon \
$(LOCAL_PATH)/../source/rotate_neon64.cc.neon \
$(LOCAL_PATH)/../source/row_neon64.cc.neon \
$(LOCAL_PATH)/../source/scale_neon64.cc.neon
endif

LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../include
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../include
LOCAL_MODULE := libyuv_shared
include $(BUILD_SHARED_LIBRARY)
  • Again trigger ndk-build to generate the .so at LRD/libs/
Now the shared library obtained above has all the functions exposed like ConvertToI420,I420Rotate etc......

To check the functions available use the following command on Linux or MSYS(for windows)
 nm -C -D libyuv_shared.so

Thursday, November 21, 2019

Compile WebRTC VoiceEngine for SM android(Revisited)

Back in 2015 I had compiled WebRTC codebase for android as I needed WebRTC's VoiceEngine library for android. Link given below.


The library compiled then was 32 bit only and starting August 2019 Google has mandated to include support for 64 bit native libraries.
Thus, there was need to recompile the codebase and generate the said library again.
For this, I have used the same VM as explained in link above.

This time, I used VirtualBox 6 and MacOS Mojave 10.14.6.
Initially I faced an issue importing the the VM file(Ubuntu-14.04.2.ova) but installing VirtualBox extension pack did the trick and the VM came back to life.
Another issue I faced was that Chrome browser being used on the VM Ubuntu was quite old and wasn't responding, I wanted to upgrade but I don't the remember the password for the VM :P
I followed this tutorial to reset the password and succeeded.

Next steps remain invariably the same except for 1 modification for 64 bit and 1 correction.

cd Documents/work/android/webrtc/webrtcFresh/
export PATH=`pwd`/depot_tools:"$PATH"
export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64/
#for 32 bit devices below command
export GYP_DEFINES="OS=android"
#for 64 bit devices below command
#export GYP_DEFINES="OS=android target_arch=arm64 target_subarch=arm64"
cd /home/azhar/Documents/work/android/webrtc/webrtcFresh/WebCRT/src

. build/android/envsetup.sh
export GYP_DEFINES="build_with_chromium=0  $GYP_DEFINES"
export GYP_DEFINES="build_with_libjingle=1 $GYP_DEFINES"
export GYP_DEFINES="libjingle_java=1 $GYP_DEFINES"
export GYP_DEFINES="enable_tracing=1 $GYP_DEFINES"

gclient runhooks

  • The above command generates all the ninja files required to build the webrtc libs. Path of ninja files is as mentioned below:-
for debug mode - WebCRT/src/webrtc/obj/Debug/webrtc/
for release mode - WebCRT/src/webrtc/obj/Release/webrtc/
above path is incorrect,
corrrect path-WebCRT/src/out/Release/obj

Before building the libs edit the libwebrtc-jni.ninja to remove the -fno-rtti flag from cflags_cc parameter, it is required because some additional code is added in the JNI wrapper to make it work with SabaMeeting.

ninja -C out/Debug #builds in debug mode
ninja -C out/Release  #builds in Release mode

  • Post successful builds the final libwebrtc-jni.so will get generated at
/Documents/work/android/webrtc/webrtcFresh/WebCRT/src/webrtc/examples/android/media_demo/libs/armeabi-v7a

  • Incase the jni wrapper needs to be modified, media_demo/jni contains the JNI wrapper.

Note: Important point to note here before beginning is that the WebRTC codebase should not updated, as the WebRTC implementation has changed significantly and I could not find the VoiceEngine library in the latest codebase.