美文网首页
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