Android ndk 编译Opus Android编解码器所需的Makefile

Android ndk 编译Opus Android编解码器所需的Makefile,android-ndk,arm,opus,Android Ndk,Arm,Opus,我正在尝试编译opus音频编解码器(),以便在Android应用程序中使用。我正在使用Android NDK(第6版)编译我的库。到目前为止,我必须为我的应用程序编译的本机C库非常简单,我已经能够在jni中以教程或其他示例为基础构建我的Android.mk文件。然而,作品的编纂似乎更为复杂。tar.gz归档文件包含一个用于编译Windows库的解决方案文件,还包含一些用于标准Unix实现的Makefiles,但是将这些文件转换为Android NDK使用的Android.mk makefile有

我正在尝试编译opus音频编解码器(),以便在Android应用程序中使用。我正在使用Android NDK(第6版)编译我的库。到目前为止,我必须为我的应用程序编译的本机C库非常简单,我已经能够在jni中以教程或其他示例为基础构建我的Android.mk文件。然而,作品的编纂似乎更为复杂。tar.gz归档文件包含一个用于编译Windows库的解决方案文件,还包含一些用于标准Unix实现的Makefiles,但是将这些文件转换为Android NDK使用的Android.mk makefile有点困难


我已经搜索过了,但是找不到Android makefile编译libopus的在线版本。有人能把我链接到这样一个makefile吗?或者,我可能遗漏了一些更简单的东西?是否可以使用Automake或某种转换器,从tar.gz中已经包含的unix makefile为我生成Android.mk文件?

编辑:只需使用上面接受的答案的解决方案,原始链接已失效,并且它与我回答时接受的答案基本相同

这里有一个,可能有点过时(它使用了opus 0.9.14):


在编译库之后,您将编写一些JNI包装,不过…

以下是最终对我有效的Android.mk makefile。我希望这能在将来帮助别人。请注意,在Opus归档中包含的unix makefile中,是否使用固定或浮动源的决定被定义为“ifdef”,而这里我使用的是“fixed”。(使用“float”很简单-只需更新路径“silk/fixed”以指向“silk/float”,并更新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)

多亏了@Stanley,我通过稍微调整他的解决方案成功地创建了一个共享库。我还不知道拥有静态库和共享库是否有优势。我所知道的是我需要一个用于JNI包装器的共享库。这就是我所拥有的。请注意编译器的定点标志。没有这些标志,编译就没有了对于定点模式,我将失败

首先将
celt_sources.mk
silk_sources.mk
opus_sources.mk
从opus source tarball复制到jni目录。将这些文件放入
Android.mk
文件将添加不同的变量,您可以根据构建类型使用这些变量包含源文件。这就是opus build过程也可以

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)
这是我的opus库项目结构


重要编辑 图像可能不是最新的,但该作品已在以下版本上进行了测试:

  • opus-1.1
  • opus-1.1.2
@pranetloke解决方案的更新版本(适用于)。一种带有一些额外功能的不同方法。 首先是我要使用的结构(我打算使用更多的库,所以我把opus放在它自己的子文件夹中)

其次,我有一个root
Android.mk
文件,在opus-1.1.2文件夹中有一个文件

下面是root
Android.mk
文件:

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)
opus-1.1.2文件夹中的Android.mk
文件如下:

#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)
这是opus-1.1.2文件夹中的外观:

对原始源代码的唯一接触是添加了一个
Android.mk
文件。没有删除任何内容

这样我就可以像一个单独的库一样使用和更新opus


以下是那些希望在android中编译和使用opus的人的额外信息;包装器源代码,部分:

#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

谢谢,这帮助我走上了正轨。我在使用你链接到的makefile的libopus部分时出现了一些链接器错误,所以我不得不对其进行更改。我进行了升级投票,因为该链接有助于显示celt、silk和opus源代码可以在一次编译中链接,而不必先分别编译到不同的模块中。谁知道ws如何从Android调用这些JNI接口?我想录制语音,但我不知道如何使用opus函数录制语音并保存到文件。@brucenan您想使用录制的音频样本,然后将录制的样本数组传递到C域进行编码。对于这一部分,您需要自己编写包装,因为这是ob很明显,Opus目前没有任何Java支持。希望根据编写这样的包装器很简单;一定要查看它。然后,在编码完成后,可以完全用Java编写文件。希望这有帮助!链接已失效。只提供链接是非常不鼓励的。为什么不将它贡献给Opus的人?嘿,Stanley,这有没有被添加到opus的官方版本中?这个makefile是为哪个版本的opus制作的?你有更新的v1.1版本的makefile吗?它对ARM来说似乎很好,但对x86来说没有那么多。你知道x86的makefile是什么样子的吗?你有什么问题吗?哦…现在看起来很好,m有问题y代码。我已将其与opusfile一起编译,并正在使用读取文件。在x86上,它似乎可以与
\u buf\u size/2
配合使用,但当我将
\u buf\u size
传递为
jint
时,它会因segfault而崩溃(在ARM上工作正常)。我注意到这是另一个人编写的代码,但我不知道这种行为的原因。为什么我必须将缓冲区大小除以2?顺便说一句,流是mono,通过5760(如文档中建议的那样)由于缓冲区大小似乎在两种平台上都能正常工作。@Pranetlook如何为x86构建缓冲区?非常有用,谢谢!我也有一个类似于您和上面构建libopus的缓冲区。armeabi也是如此。不过,我想知道您是否也考虑过构建armeabi-v7a版本?@leenephi我不确定,但是,
APP_ABI:=all
Appli中
APP_ABI := all  # mips, armeabi, armeabi-v7a, x86 etc. builds