[jni] 06_Lame编码器2-Lame编码器逻辑功能

Android 4.0

Lame编码器2-Lame编码器逻辑功能
音频编码,视频编码,lame编码,音频转码,lame转码

1、移植LAME代码
a、将不需要的文件删除,留下*.c和*.h文件
b、需要在Android.mk,将所有的*.c文件引入
LOCAL_SRC_FILES := ... 
c、然后有一个类型是linux下的,不支持,换成float

d、然后cygwin中ndk-build,需要一定的时间
换成float:  extern float fast_log2(float x);  
e、一般来说,测试是否移植别人成功,调用一下获取version的方法
2、获取lame的版本,测试是否移植成功。lame.h中有该方法的声明
//获取lame版本
JNIEXPORT jstring JNICALL Java_cn_zengfansheng_lame_MainActivity_getLameVersionFromC(
        JNIEnv *env, jobject obj) {
    //4、获取版本
    //    int CDECL lame_init_params(lame_global_flags *);
    //    const char*  CDECL get_lame_version       ( void );
    return (*env)->NewStringUTF(env, get_lame_version());
}
结果:


3、调用lame进行音频转码
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <jni.h>
#include <android/log.h>
#include <lame.h>
#include "cn_zengfansheng_lame_MainActivity.h"
#define LOG_TAG "System.out.c"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

//Jstring2CStr 把java中的jstring的类型转化成一个c语言中的char 字符串
charJstring2CStr(JNIEnv* env, jstring jstr) {
    char* rtn = NULL;
    jclass clsstring = (*env)->FindClass(env, "java/lang/String"); //String
    jstring strencode = (*env)->NewStringUTF(env, "GB2312"); // 得到一个java字符串 "GB2312"
    jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes",
            "(Ljava/lang/String;)[B"); //[ String.getBytes("gb2312");
    jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid,
            strencode); // String .getByte("GB2312");
    jsize alen = (*env)->GetArrayLength(env, barr); // byte数组的长度
    jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE);
    if (alen > 0) {
        rtn = (char*) malloc(alen + 1);         //"\0"
        memcpy(rtn, ba, alen);
        rtn[alen] = 0;
    }
    (*env)->ReleaseByteArrayElements(env, barr, ba, 0);
    return rtn;
}

//获取lame版本
JNIEXPORT jstring JNICALL Java_cn_zengfansheng_lame_MainActivity_getLameVersionFromC(
        JNIEnv *env, jobject obj) {
    //4、获取版本
    //    int CDECL lame_init_params(lame_global_flags *);
    //    const char*  CDECL get_lame_version       ( void );
    return (*env)->NewStringUTF(env, get_lame_version());
}

//转码操作
JNIEXPORT void JNICALL Java_cn_zengfansheng_lame_MainActivity_convertToMp3
(JNIEnv *env, jobject obj, jstring jstr_src , jstring jstr_dst) {

    //0-1、获取java代码传递过来的要转码的源文件,和转码后存放的路径,转换成c语言的char字符
    char* cstr_src = Jstring2CStr(env,jstr_src);
    char* cstr_dst = Jstring2CStr(env,jstr_dst);

    //0-2、LOGD测试下
    LOGD("src=%s",cstr_src);
    LOGD("dst=%s",cstr_dst);

    //0-3、打开wav、mp3文件
    FILE* fsrc = fopen(cstr_src,"rb");
    FILE* fdst = fopen(cstr_dst,"wb");

    short int wav_buffer[8192*2];
    unsigned char mp3_buffer[8192];

    //1、初始化lame的编码器
    //    struct lame_global_struct;
    //    typedef struct lame_global_struct lame_global_flags;
    //    typedef lame_global_flags *lame_t;
    //    lame_global_flags * CDECL lame_init(void);
    lame_t lame = lame_init();

    //2、设置lame  mp3的采样率
    /* input sample rate in Hz.  default = 44100hz */
    //int CDECL lame_set_in_samplerate(lame_global_flags *, int);
    //int CDECL lame_get_in_samplerate(const lame_global_flags *);
    lame_set_in_samplerate(lame,44100);

    //3、设置输入频道
    /* number of channels in input stream. default=2  */
    //int CDECL lame_set_num_channels(lame_global_flags *, int);
    //int CDECL lame_get_num_channels(const lame_global_flags *);
    lame_set_num_channels(lame,2);

    //4、设置mp3的编码方法
    /* Types of VBR.  default = vbr_off = CBR */
    //int CDECL lame_set_VBR(lame_global_flags *, vbr_mode);
    //vbr_mode CDECL lame_get_VBR(const lame_global_flags *);
    //查看typedef enum vbr_mode_e 可知:vbr_default=vbr_mtrh
    lame_set_VBR(lame,vbr_default);

    //5、设置lame配置
    /*
     * REQUIRED:
     * sets more internal configuration based on data provided above.
     * returns -1 if something failed.
     */
    //int CDECL lame_init_params(lame_global_flags *);
    lame_init_params(lame);
    LOGD("statrt--lame init finish");

    //6、开始转换
    int read = 0 ;//代表读了多少个次 和写了多少次
    int write = 0;
    LOGD("read=%d",read);
    LOGD("write=%d",write);
    do{
        //读,返回读取到的字节
        read = fread(wav_buffer,sizeof(short int)*2,8192,fsrc);
        LOGD("read=%d,lame reading",read);
        if(read!=0){
            LOGD("read=%d,--lame converting...",read);
            //转换,返回转换的字节
            write = lame_encode_buffer_interleaved(lame,wav_buffer,read,mp3_buffer,8192);
            //把转化后的mp3数据写到文件里
            fwrite(mp3_buffer,sizeof(unsigned char),write,fdst);
        }
        if(read==0){//读到末尾
            LOGD("read=%d,--lame converting...",read);
            lame_encode_flush(lame,mp3_buffer,8192);
        }
    }while(read!=0);
    LOGI("end--convert  finish");

    //7、关闭资源
    lame_close(lame);
    fclose(fsrc);
    fclose(fdst);
}
结果:


4、进度条的转化百分比实现

a)  在java代码中,设置进度条最大值,并提供修改进度条值的方法
b) 要在C代码中,在转换的过程中,获取进度值,并通过调用java中修改进度条的方法,来修改对话框进度值
问题1:在转换过程中,用户点击后退键,对话框消失了,但后台还在进行数据转换
解决:将ProgressDialog在转换时设置为不可取消
pd.setCancelable(false);
问题2:如何在用户点击后退键时,将转换停止掉?
解决:在c代码中,定义一个flag,但flag= 404 ,跳出循环
然后在java代码中,提供一个可以操作该flag的native方法,stop(),
当用户按后退键时,调用该stop,将c中的flag置为404.
int flag = 0 ;//跳出循环的条件:flag=404
public native void stop();
11-30 07:48:06.193: I/Choreographer(25721): Skipped 42 frames!  The application may be doing too much work on its main thread.