美文网首页
Android Studio接入lame

Android Studio接入lame

作者: hahafei | 来源:发表于2017-03-06 20:51 被阅读0次

在项目中要实装lame的开源库实现录音转码mp3的功能。
期间遇到诸多问题,度娘了N多博客,最终总结了接入了lame

首先在gradle.properties里面添加 android.useDeprecatedNDK = true

1、Android Studio中配置NDK路径,步骤为:

1)先下载NDK并安装(这句基本是废话)

2)点菜单栏的File->ProjectStructure…->在打开的窗口中左侧选中SDKLocation->在右侧Android NDK Location中填入NDK目录所在路径,如下图所示:

第一步 第二步

2、项目中配置JNI

1)项目切换到Project开发模式

2)在app工程下面的main/src/main/目录下面新建jni目录

默认在src/main/jni目录下面找c/c++文件编译,也可以在android{}下添加sourceSet{}

sourceSet{  
    main{  
        jni.srcDirs=['src/main/cpp']  
    }  
}

就能将指定目录下的c/c++文件编译成指定的模块名.so。
注意:上面这种方式通过gradle无法编译成多个模块,编译多个模块还是要自己写Android.mk文件实现,通过手动执行ndk-build编译成的*.so文件默认在src/main/libs下面(下面会详细讲到配置Android.mk文件)。

打包APK时,默认是寻找so的目录是/build/intermediates/ndk和/build/intermediates/jniLibs,前者是使用源码由Gradle编译成的so所处的位置,后者一般是一些第三方的so或者自己手动使用ndk编译生成的so文件所生成的,这个位置在src/main/jniLibs。

因此手动编译好so文件后,将其复制到jniLibs下面,或者在此放置第三方so,或者在build.gradle文件里面的android下面添加jniLib.srcDir定义了Gradle在哪里寻找生成的so库文件

3)在app工程下的build.gradle文件android下添加配置sourceSets
默认情况下,你需要把C/C++源代码放在 [module]/src/main/jni/ 路径下。
当然,也可以自定义源代码路径:

sourceSets {
        main {
            // jni.srcDirs禁用通过Gradle来编译本地c/c++代码
            jni.srcDirs = []
            // jniLib.srcDirs定义了Gradle在哪里寻找生成的so库文件 
            jniLibs.srcDir 'src/main/libs'  
        }
}
配置jni

NDK和JNI配置完成后,接下来就是配置lame相关

3、首先下载lame的源码,可能需要自备梯子。

http://lame.sourceforge.net/download.php
http://sourceforge.net/projects/lame/files/lame/3.99/lame-3.99.5.tar.gz

1)下载好之后解压
2)在jni下面创建文件目录(命名自己随意):lame-3.99.5_libmp3lame;
3)将解压文件夹下lame-x.xx.x/libmp3lame/ 目录下面的.c和.h文件拷贝到项目下的jni/lame-3.99.5_libmp3lame目录下,同时将将 lame-x.xx.x/include/ 目录下的 lame.h 也复制到 jni/lame-3.99.5_libmp3lame/中

下载的lame包 配置.c和.h文件

4、修改部分.c和.h文件的代码

修改源代码

1)删除fft.c文件的47行的"include "vector/lame_intrin.h""

2)删除set_get.h文件的24行的"#include <lame.h>"

3)将util.h文件的574行的"extern ieee754_float32_t fast_log2(ieee754_float32_t x);" 替换为 "extern float fast_log2(float x);"

5、在jni文件夹下创建Application.mk和Android.mk文件

mk文件

Application.mk里面的代码为:

APP_ABI := armeabi armeabi-v7a arm64-v8a x86 x86_64
APP_MODULES := mp3lame
APP_CFLAGS += -DSTDC_HEADERS
#APP_ABI:=x86_64
#APP_PLATFORM := android-21

注意:
如果是x86_64的话需要在Application.mk中加上
APP_CFLAGS += -DSTDC_HEADERS

 /*--以下为Native部分--*/
 static {
        System.loadLibrary("mp3lame");
 }

Android.mk里面的代码为:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LAME_LIBMP3_DIR := lame-3.99.5_libmp3lame   // 此处对于jni下面的lame目录

// 此处表示的是java代码引入.so的名称与Application文件的APP_MODULES := mp3lame 保持一致
LOCAL_MODULE    := mp3lame  

LOCAL_SRC_FILES :=\
$(LAME_LIBMP3_DIR)/bitstream.c \
$(LAME_LIBMP3_DIR)/fft.c \
$(LAME_LIBMP3_DIR)/id3tag.c \
$(LAME_LIBMP3_DIR)/mpglib_interface.c \
$(LAME_LIBMP3_DIR)/presets.c \
$(LAME_LIBMP3_DIR)/quantize.c \
$(LAME_LIBMP3_DIR)/reservoir.c \
$(LAME_LIBMP3_DIR)/tables.c  \
$(LAME_LIBMP3_DIR)/util.c \
$(LAME_LIBMP3_DIR)/VbrTag.c \
$(LAME_LIBMP3_DIR)/encoder.c \
$(LAME_LIBMP3_DIR)/gain_analysis.c \
$(LAME_LIBMP3_DIR)/lame.c \
$(LAME_LIBMP3_DIR)/newmdct.c \
$(LAME_LIBMP3_DIR)/psymodel.c \
$(LAME_LIBMP3_DIR)/quantize_pvt.c \
$(LAME_LIBMP3_DIR)/set_get.c \
$(LAME_LIBMP3_DIR)/takehiro.c \
$(LAME_LIBMP3_DIR)/vbrquantize.c \
$(LAME_LIBMP3_DIR)/version.c \
MP3Recorder.c

include $(BUILD_SHARED_LIBRARY)

6、书写jni下面的MP3Recorder.c和MP3Recorder.h文件的代码

MP3Recorder.c文件代码:

#include "lame-3.99.5_libmp3lame/lame.h"
#include "MP3Recorder.h"

static lame_global_flags *glf = NULL;

JNIEXPORT void JNICALL Java_com_babi_story_audio_MP3Recorder_init(
        JNIEnv *env, jclass cls, jint inSamplerate, jint outChannel,
        jint outSamplerate, jint outBitrate, jint quality) {
    if (glf != NULL) {
        lame_close(glf);
        glf = NULL;
    }
    glf = lame_init();
    lame_set_in_samplerate(glf, inSamplerate);
    lame_set_num_channels(glf, outChannel);
    lame_set_out_samplerate(glf, outSamplerate);
    lame_set_brate(glf, outBitrate);
    lame_set_quality(glf, quality);
    lame_init_params(glf);
}

JNIEXPORT jint JNICALL Java_com_babi_story_audio_MP3Recorder_encode(
        JNIEnv *env, jclass cls, jshortArray buffer_l, jshortArray buffer_r,
        jint samples, jbyteArray mp3buf) {
    jshort* j_buffer_l = (*env)->GetShortArrayElements(env, buffer_l, NULL);

    jshort* j_buffer_r = (*env)->GetShortArrayElements(env, buffer_r, NULL);

    const jsize mp3buf_size = (*env)->GetArrayLength(env, mp3buf);
    jbyte* j_mp3buf = (*env)->GetByteArrayElements(env, mp3buf, NULL);

    int result = lame_encode_buffer(glf, j_buffer_l, j_buffer_r,
            samples, j_mp3buf, mp3buf_size);

    (*env)->ReleaseShortArrayElements(env, buffer_l, j_buffer_l, 0);
    (*env)->ReleaseShortArrayElements(env, buffer_r, j_buffer_r, 0);
    (*env)->ReleaseByteArrayElements(env, mp3buf, j_mp3buf, 0);

    return result;
}

JNIEXPORT jint JNICALL Java_com_babi_story_audio_MP3Recorder_flush(
        JNIEnv *env, jclass cls, jbyteArray mp3buf) {
    const jsize mp3buf_size = (*env)->GetArrayLength(env, mp3buf);
    jbyte* j_mp3buf = (*env)->GetByteArrayElements(env, mp3buf, NULL);

    int result = lame_encode_flush(glf, j_mp3buf, mp3buf_size);

    (*env)->ReleaseByteArrayElements(env, mp3buf, j_mp3buf, 0);

    return result;
}

JNIEXPORT void JNICALL Java_com_babi_story_audio_MP3Recorder_close(
        JNIEnv *env, jclass cls) {
    lame_close(glf);
    glf = NULL;
}

MP3Recorder.h文件代码:


/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_kubility_demo_MP3Recorder */

#ifndef _Included_MP3Recorder
#define _Included_MP3Recorder
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_kubility_demo_MP3Recorder
 * Method:    init
 * Signature: (IIIII)V
 */
JNIEXPORT void JNICALL Java_com_babi_story_audio_MP3Recorder_init
  (JNIEnv *, jclass, jint, jint, jint, jint, jint);

/*
 * Class:     com_kubility_demo_MP3Recorder
 * Method:    encode
 * Signature: ([S[SI[B)I
 */
JNIEXPORT jint JNICALL Java_com_babi_story_audio_MP3Recorder_encode
  (JNIEnv *, jclass, jshortArray, jshortArray, jint, jbyteArray);

/*
 * Class:     com_kubility_demo_MP3Recorder
 * Method:    flush
 * Signature: ([B)I
 */
JNIEXPORT jint JNICALL Java_com_babi_story_audio_MP3Recorder_flush
  (JNIEnv *, jclass, jbyteArray);

/*
 * Class:     com_kubility_demo_MP3Recorder
 * Method:    close
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_babi_story_audio_MP3Recorder_close
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

7、在终端进入jni目录,然后执行ndk-build命令
执行命令后将会在libs文件夹目录生成项目配置相关的.so文件

生成.so文件

参考:http://blog.csdn.net/superdhq/article/details/53366483

相关文章

网友评论

      本文标题:Android Studio接入lame

      本文链接:https://www.haomeiwen.com/subject/hciugttx.html