Mac系统opus Android编译集成

一、源码下载

opus官网
源码下载
我这里使用的是1.3.1版本
新建Android module opus

其目录结构如下


opus源码拷贝至src目录,在src目录下新建Android.mkApplication.mk

Android.mk
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

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) $(OPUS_SOURCES_FLOAT)
LOCAL_SRC_FILES     += \
                        logger.c \
                        jni/encoder_jni.cpp \
                        jni/decoder_jni.cpp

LOCAL_LDLIBS        := -lm -llog
LOCAL_C_INCLUDES    := \
    $(LOCAL_PATH)/include \
    $(LOCAL_PATH)/silk \
    $(LOCAL_PATH)/silk/fixed \
    $(LOCAL_PATH)/celt \
    $(LOCAL_PATH)/jni
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

LOCAL_LDLIBS     += -llog
LOCAL_LDLIBS     += -landroid
LOCAL_CFLAGS += -DNPT_CONFIG_ENABLE_LOGGING

include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_ABI := armeabi armeabi-v7a
APP_PLATFORM := android-21
APP_ALLOW_MISSING_DEPS=true
添加编译脚本build.sh
#!/usr/bin/env bash
cd ../src
ndk-build APP_BUILD_SCRIPT=Android.mk NDK_APPLICATION_MK=Application.mk NDK_PROJECT_PATH=.
cd ../build

cp -f ../src/libs/armeabi-v7a/* ../../libs/armeabi-v7a/

编译可得libopus.so

二、jni调用

java部分添加编解码类

public class Encoder {

    public Encoder() {
        Opus.getInstance();
    }

    public int initEncoder(Parameter parameter) {
        return _initEncoder(parameter);
    }

    public int encode(byte[] opus, short[] pcm) {
        return _encode(opus, pcm);
    }

    public int destroyEncoder() {
        return _destroyEncoder();
    }

    private native int _initEncoder(Parameter parameter);

    private native int _encode(byte[] opus, short[] pcm);

    private native int _destroyEncoder();
}
public class Decoder {

    public Decoder() {
        Opus.getInstance();
    }

    public int initDecoder(Parameter parameter) {
        return _initDecoder(parameter);
    }

    public int decode(short[] pcm, byte[] opus) {
        return _decode(pcm, opus);
    }

    public int destroyDecoder() {
        return _destroyDecoder();
    }

    private native int _initDecoder(Parameter parameter);

    private native int _decode(short[] pcm, byte[] opus);

    private native int _destroyDecoder();
}

添加jni脚本jni.sh,用于生成头文件

#!/usr/bin/env bash
# Mirror
javah -o ../core/src/jni/decoder_jni.h -classpath ../build/intermediates/classes/release/ com.cast.opus.decoder.Decoder
javah -o ../core/src/jni/encoder_jni.h -classpath ../build/intermediates/classes/release/ com.cast.opus.encoder.Encoder

image.png

新建encoder_jni.cppdecoder_jni.cpp分别实现编解码部分的jni调用

encoder_jni.cpp
#include "encoder_jni.h"
#include "logger.h"
#include "opus.h"

#define TAG "encoder-jni"

OpusEncoder *gOpusEnc;

JNIEXPORT jint JNICALL Java_com_cast_opus_encoder_Encoder__1initEncoder
(JNIEnv *env, jobject obj, jobject paraObj) {
    int error;
    gOpusEnc = opus_encoder_create(48000, 2,
                                        OPUS_APPLICATION_RESTRICTED_LOWDELAY,
                                        &error);
    if (gOpusEnc) {
        opus_encoder_ctl(gOpusEnc, OPUS_SET_VBR(0));//0:CBR, 1:VBR
        opus_encoder_ctl(gOpusEnc, OPUS_SET_VBR_CONSTRAINT(true));
        opus_encoder_ctl(gOpusEnc, OPUS_SET_BITRATE(32000));
        opus_encoder_ctl(gOpusEnc, OPUS_SET_COMPLEXITY(8));//8    0~10
        opus_encoder_ctl(gOpusEnc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
        opus_encoder_ctl(gOpusEnc, OPUS_SET_LSB_DEPTH(16));
        opus_encoder_ctl(gOpusEnc, OPUS_SET_DTX(0));
        opus_encoder_ctl(gOpusEnc, OPUS_SET_INBAND_FEC(0));
        opus_encoder_ctl(gOpusEnc, OPUS_SET_PACKET_LOSS_PERC(0));
    }
    OpusLogI(TAG,"initEncoder %d ", error);
    return error;
}

JNIEXPORT jint JNICALL Java_com_cast_opus_encoder_Encoder__1encode
(JNIEnv *env, jobject obj,  jbyteArray opus,jshortArray pcm) {
    if (!gOpusEnc || !pcm || !opus) {
        OpusLogW(TAG,"encode ignore 1");
        return -1;
    }
    jshort *pcmArray = env->GetShortArrayElements(pcm, 0);
    jsize pcmSize = env->GetArrayLength(pcm);

    jbyte *opusArray = env->GetByteArrayElements(opus, 0);
    jsize opusSize = env->GetArrayLength(opus);
    
    //if (opusSize < 320 || pcmSize <= 0) {
    if (opusSize <= 0 || pcmSize <= 0) {
        OpusLogW(TAG,"encode ignore 2");
        return -1;
    }
    OpusLogI(TAG,"encode %d %d",pcmSize,opusSize);
    //
    // int nRet = opus_encode(gOpusEnc, pcmArray, pcmSize, (unsigned char *) opusArray,
    //                         opusSize);
    int nRet = opus_encode(gOpusEnc, pcmArray, pcmSize, (unsigned char *) opusArray,
                            opusSize);
    env->ReleaseShortArrayElements(pcm, pcmArray, 0);
    env->ReleaseByteArrayElements(opus, opusArray, 0);
    OpusLogI(TAG,"encode %d ",nRet);
    return nRet;
}

JNIEXPORT jint JNICALL Java_com_cast_opus_encoder_Encoder__1destroyEncoder
(JNIEnv *env, jobject obj) {
    OpusLogI(TAG,"destroyEncoder");
    if (!gOpusEnc)
       return 0;
    opus_encoder_destroy(gOpusEnc);
    return 0;
}
decoder_jni.cpp
//
// Created by don on 2020/5/20.
//
#include "decoder_jni.h"
#include "logger.h"
#include "opus.h"

#define TAG "decoder-jni"

OpusDecoder *gOpusDec;

JNIEXPORT jint JNICALL Java_com_cast_opus_decoder_Decoder__1initDecoder
(JNIEnv *env, jobject obj, jobject paraObj){
    int error;
    gOpusDec = opus_decoder_create(48000, 2, &error);
    OpusLogI(TAG,"initDecoder %d",error);
    return error;
}

JNIEXPORT jint JNICALL Java_com_cast_opus_decoder_Decoder__1decode
(JNIEnv *env, jobject obj,  jshortArray pcm,jbyteArray opus){
    OpusLogI(TAG,"decode");
    if (!gOpusDec || !opus || !pcm)
        return -1;
    jbyte *opusArray = env->GetByteArrayElements(opus, 0);
    jsize opusSize = env->GetArrayLength(opus);

    jshort *pcmArray = env->GetShortArrayElements(pcm, 0);
    jsize pcmSize = env->GetArrayLength(pcm);
    if (opusSize <= 0 || pcmSize <= 0) {
        return -1;
    }
    int nRet = opus_decode(gOpusDec, (unsigned char *) opusArray, opusSize, pcmArray, pcmSize, 0);
    env->ReleaseShortArrayElements(pcm, pcmArray, 0);
    env->ReleaseByteArrayElements(opus, opusArray, 0);
    return nRet;
}

JNIEXPORT jint JNICALL Java_com_cast_opus_decoder_Decoder__1destroyDecoder
(JNIEnv *env, jobject obj){
    OpusLogI(TAG,"destroyDecoder");
    if (!gOpusDec)
       return 0;
    opus_decoder_destroy(gOpusDec);
    gOpusDec = NULL;
    return 0;
}

三、编解码调用

pcm编码为opus
    private byte[] encode(short[] buf) {
        short[] newShortBuf = new short[1920];
        System.arraycopy(buf, 0, newShortBuf, 0, newShortBuf.length);
        Logger.i(TAG, "opus---- origin: " + Arrays.toString(newShortBuf));
        byte[] opus = new byte[newShortBuf.length / 8];
        if (mOpusEncoder == null) {
            mOpusEncoder = new Encoder();
            mOpusEncoder.initEncoder(null);
        }
        int result = mOpusEncoder.encode(opus, newShortBuf);
        //Logger.i(TAG, "opus---- encode opus: " + Arrays.toString(opus));
        byte[] newOpus = new byte[result];
        System.arraycopy(opus, 0, newOpus, 0, newOpus.length);
        return newOpus;
    }
opus解码为pcm
    private short[] decode(byte[] buf) {
        short[] pcm = new short[1920];
        if (mOpusDecoder == null) {
            mOpusDecoder = new Decoder();
            mOpusDecoder.initDecoder(null);
        }
        int result = mOpusDecoder.decode(pcm, buf);
        Logger.i(TAG, "decode " + result);
        short[] newPcm = new short[result];
        System.arraycopy(pcm,0,newPcm,0,newPcm.length);
        return newPcm;
    }

你可能感兴趣的:(Mac系统opus Android编译集成)