Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Makefile needed for compiling the Opus Codec for Android

I am trying to compile the opus audio codec (http://www.opus-codec.org/downloads/) for use in an Android application. I am using Android NDK (release 6) to compile my libraries. Up to now, the native C libraries that I had to compile for my application has been pretty straightforward and I have been able to base my Android.mk files in jni mostly on tutorials or other examples. However, the compilation of Opus looks to be somewhat more complex. The tar.gz archive contains a solution file for compiling the libraries for Windows and it also contains some Makefiles for a standard Unix implementation, but translating these into an Android.mk makefile for use by the Android NDK is a bit of a challenge.

I have searched, but have been unable to find an online version for the Android makefile to compile libopus. Can someone perhaps link me to such a makefile? Alternatively, I might be missing something simpler? Is it perhaps possible to use Automake or some kind of converter to maybe generate the Android.mk file for me from the unix makefile that is already included in the tar.gz?

like image 804
Stanley Avatar asked Jul 25 '13 21:07

Stanley


3 Answers

The following is the Android.mk makefile that eventually worked for me. I hope this can help someone else too in future. Do take note that in the unix makefile included in the Opus Archive, the decision of whether to use the fixed or float silk sources is defined as an "ifdef" whereas here I am using "fixed". (To use "float" would be simple - simply update the paths "silk/fixed" to point to "silk/float" and update the CFLAGS.

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

MY_MODULE_DIR       := opus

LOCAL_MODULE        := $(MY_MODULE_DIR)
LOCAL_SRC_FILES     := \
    $(subst $(ROOT_DIR)/$(MY_MODULE_DIR)/,,$(wildcard $(ROOT_DIR)/$(MY_MODULE_DIR)/src/*.c*)) \
    $(subst $(ROOT_DIR)/$(MY_MODULE_DIR)/,,$(wildcard $(ROOT_DIR)/$(MY_MODULE_DIR)/celt/*.c*)) \
    $(subst $(ROOT_DIR)/$(MY_MODULE_DIR)/,,$(wildcard $(ROOT_DIR)/$(MY_MODULE_DIR)/silk/*.c*)) \
    $(subst $(ROOT_DIR)/$(MY_MODULE_DIR)/,,$(wildcard $(ROOT_DIR)/$(MY_MODULE_DIR)/silk/fixed/*.c*))
LOCAL_LDLIBS        := -lm -llog
LOCAL_C_INCLUDES    := \
    $(ROOT_DIR)/$(MY_MODULE_DIR)/include \
    $(ROOT_DIR)/$(MY_MODULE_DIR)/silk \
    $(ROOT_DIR)/$(MY_MODULE_DIR)/silk/fixed \
    $(ROOT_DIR)/$(MY_MODULE_DIR)/celt
LOCAL_CFLAGS        := -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64
LOCAL_CFLAGS    += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -O3 -fno-math-errno
LOCAL_CPPFLAGS      := -DBSD=1 
LOCAL_CPPFLAGS          += -ffast-math -O3 -funroll-loops

include $(BUILD_STATIC_LIBRARY)
like image 188
Stanley Avatar answered Sep 17 '22 05:09

Stanley


IMPORTANT EDIT The images might not be up to date but the work has been tested on below versions:

  • opus-1.1
  • opus-1.1.2

An updated version (works for opus-1.1.2 ) of @praneetloke's solution. A kind of different approach with some extras. First of all below is my structure to use (I intended to use more libraries, so I put opus in its own sub-folder. ) folder structor for opus JNI

Secondly I have a root Android.mk file and one another inside the folder opus-1.1.2 .

Here is the root Android.mk file:

LOCAL_PATH := $(call my-dir)
OPUS_DIR            := opus-1.1.2

include $(OPUS_DIR)/Android.mk

include $(CLEAR_VARS)

LOCAL_MODULE        := codec
LOCAL_SRC_FILES     := Opus_jni.cpp
LOCAL_CFLAGS        := -DNULL=0
LOCAL_LDLIBS        := -lm -llog
LOCAL_C_INCLUDES    := $(LOCAL_PATH)/$(OPUS_DIR)/include
LOCAL_SHARED_LIBRARIES := opus
include $(BUILD_SHARED_LIBRARY)

Android.mk file inside the opus-1.1.2 folder is below:

#Backing up previous LOCAL_PATH so it does not screw with the root Android.mk file
LOCAL_PATH_OLD := $(LOCAL_PATH)
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

#include the .mk files
include $(LOCAL_PATH)/celt_sources.mk
include $(LOCAL_PATH)/silk_sources.mk
include $(LOCAL_PATH)/opus_sources.mk

LOCAL_MODULE        := opus

#fixed point sources
SILK_SOURCES += $(SILK_SOURCES_FIXED)

#ARM build
CELT_SOURCES += $(CELT_SOURCES_ARM)
SILK_SOURCES += $(SILK_SOURCES_ARM)
LOCAL_SRC_FILES     := \
$(CELT_SOURCES) $(SILK_SOURCES) $(OPUS_SOURCES)

LOCAL_LDLIBS        := -lm -llog

LOCAL_C_INCLUDES    := \
$(LOCAL_PATH)/include \
$(LOCAL_PATH)/silk \
$(LOCAL_PATH)/silk/fixed \
$(LOCAL_PATH)/celt

LOCAL_CFLAGS        := -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64

LOCAL_CFLAGS        += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT=1 -DDISABLE_FLOAT_API -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF  -DAVOID_TABLES
LOCAL_CFLAGS        +=  -w -std=gnu99 -O3 -fno-strict-aliasing -fprefetch-loop-arrays  -fno-math-errno
LOCAL_CPPFLAGS      := -DBSD=1
LOCAL_CPPFLAGS      += -ffast-math -O3 -funroll-loops

include $(BUILD_SHARED_LIBRARY)

#Putting previous LOCAL_PATH back here
LOCAL_PATH := $(LOCAL_PATH_OLD)

This is how it looks like inside opus-1.1.2 folder:

Whole Opus Folder structure

The only touch to the original sources is addition of an Android.mk file. Nothing removed.

This way I can use and update opus just like a separate library.


Here is the extras for those who wants to compile and use opus in android; Wrapper source, partially:

#include <jni.h>
#include <android/log.h>
#include <opus.h>

/* Header for class net_abcdefgh_opustrial_codec_Opus */
#ifndef _Included_net_abcdefgh_opustrial_codec_Opus
#define _Included_net_abcdefgh_opustrial_codec_Opus

#define TAG "Opus_JNI"
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG,__VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , TAG,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO  , TAG,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN  , TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , TAG,__VA_ARGS__)
#ifdef __cplusplus
extern "C" {
    #endif
    JNIEXPORT jint JNICALL Java_net_abcdefgh_opustrial_codec_Opus_open
    (JNIEnv *env, jobject thiz){
        ...
        return error;
    }
    JNIEXPORT jint JNICALL Java_net_abcdefgh_opustrial_codec_Opus_decode
    (JNIEnv * env, jobject thiz, jbyteArray jencoded, jint jencodedOffset, jint jencodedLength, jbyteArray jpcm, jint jpcmOffset, jint jframeSize) {
        ...
        return decodedSize;
    }
    JNIEXPORT jint JNICALL Java_net_abcdefgh_opustrial_codec_Opus_encode
    (JNIEnv * env, jobject thiz, jbyteArray jpcm, jint jpcmOffset, jint jpcmLength, jbyteArray jencoded, jint jencodedOffset) {
        ...
        return encodedSize;
    }
    JNIEXPORT void JNICALL Java_net_abcdefgh_opustrial_codec_Opus_close
    (JNIEnv *env, jobject thiz){
        ...
    }
    #ifdef __cplusplus
}
#endif
#endif

Application.mk file (optional)

APP_ABI := all  # mips, armeabi, armeabi-v7a, x86 etc. builds
like image 32
guness Avatar answered Sep 17 '22 05:09

guness


Thanks to @Stanley, I was able to create a shared library successfully by tweaking his solution a bit. I don't know yet if there is an advantage of having a static library vs. a shared library. All I know is I need a shared library for the JNI wrapper. This is what I have. Note the compiler flags for fixed point. Without those the compilation will fail for fixed point mode.

First copy the celt_sources.mk, silk_sources.mk and opus_sources.mk from the opus source tarball to your jni directory. Bringing these files into your Android.mk file will add different variables which you can use to include source files based on the type of the build. This is what the opus build process does as well.

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

#include the .mk files
include celt_sources.mk
include silk_sources.mk
include opus_sources.mk

MY_MODULE_DIR       := opus

LOCAL_MODULE        := $(MY_MODULE_DIR)

#fixed point sources
SILK_SOURCES += $(SILK_SOURCES_FIXED)

#ARM build
CELT_SOURCES += $(CELT_SOURCES_ARM)
SILK_SOURCES += $(SILK_SOURCES_ARM)
LOCAL_SRC_FILES     := \
$(CELT_SOURCES) $(SILK_SOURCES) $(OPUS_SOURCES)

LOCAL_LDLIBS        := -lm -llog

LOCAL_C_INCLUDES    := \
$(LOCAL_PATH)/include \
$(LOCAL_PATH)/silk \
$(LOCAL_PATH)/silk/fixed \
$(LOCAL_PATH)/celt

LOCAL_CFLAGS        := -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64
LOCAL_CFLAGS        += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT=1 -DDISABLE_FLOAT_API -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -O3 -fno-math-errno
LOCAL_CPPFLAGS      := -DBSD=1
LOCAL_CPPFLAGS      += -ffast-math -O3 -funroll-loops

#build a shared library not a static one like in Stanley's solution
include $(BUILD_SHARED_LIBRARY)

Here's my project structure for the opus library.

Project structure

like image 38
praneetloke Avatar answered Sep 17 '22 05:09

praneetloke