Lameライブラリを使用してAndroidプラットフォームJNIのMP 3とpcmの相互回転を実現


Android Studio 4.0に基づいて、CmakeListを使用して、案内人East_に感謝します.Wu、漏れがあれば指摘を歓迎します.
1.lameライブラリのインポート
コンパイル後、対応するSOファイルを直接インポートできますが、なぜ私がコンパイルした後、x86_64の何かが欠けていることをヒントにして、半日探しても結果が出ないので、すべてのパッケージを直接インポートします.親切な人がコンパイルしてSOリンクを振って共有してほしいです.感謝します(直接導入するとbuildには警告がたくさんあって、見ていて不快です).
MP 3はPCMを回転して著作権の問題に関連するようで、lameはデフォルトで関連するコードを遮蔽して、mpglib_interface.cの中の下のコードを注釈を取り消して、著作権に注意します.
1.1 lame 3をダウンロードする.100
1.2ファイルをインポートします.libmp3lameフォルダの下にあるすべての.cおよび.hファイル(サブフォルダは管理せず)をcppフォルダの下にあるincludeフォルダ(sなし)にコピーし、mpglibフォルダの下にあるすべての.cおよび.hファイルをincludeフォルダにコピーします.
1.3cMakeListはこのファイルを参照します.

add_library( 
        # Sets the name of the library.
        native-lib
        # Sets the library as a shared library.
        SHARED
        # Provides a relative path to your source file(s).
        native-lib.cpp

        # MP3 PCM     
        include/libmp3lame/common.c
        include/libmp3lame/common.h
        include/libmp3lame/huffman.h
        include/libmp3lame/interface.c
        include/libmp3lame/interface.h
        include/libmp3lame/l2tables.h
        include/libmp3lame/layer1.c
        include/libmp3lame/layer1.h
        include/libmp3lame/layer2.c
        include/libmp3lame/layer2.h
        include/libmp3lame/layer3.c
        include/libmp3lame/layer3.h
        include/libmp3lame/mpg123.h
        include/libmp3lame/mpglib.h
        include/libmp3lame/tabinit.c
        include/libmp3lame/tabinit.h
        include/libmp3lame/dct64_i386.c
        include/libmp3lame/dct64_i386.h
        include/libmp3lame/decode_i386.c
        include/libmp3lame/decode_i386.h


        # PCM MP3     
        include/libmp3lame/bitstream.c
        include/libmp3lame/encoder.c
        include/libmp3lame/fft.c
        include/libmp3lame/gain_analysis.c
        include/libmp3lame/id3tag.c
        include/libmp3lame/lame.c
        include/libmp3lame/mpglib_interface.c
        include/libmp3lame/newmdct.c
        include/libmp3lame/presets.c
        include/libmp3lame/psymodel.c
        include/libmp3lame/quantize.c
        include/libmp3lame/quantize_pvt.c
        include/libmp3lame/reservoir.c
        include/libmp3lame/set_get.c
        include/libmp3lame/tables.c
        include/libmp3lame/takehiro.c
        include/libmp3lame/util.c
        include/libmp3lame/vbrquantize.c
        include/libmp3lame/VbrTag.c
        include/libmp3lame/version.c
        )

2.基本使用
2.1 PCM -> MP3
私の標準的な流れは、init->encoder->flush->writeTag->closeです.
これが使い捨てであれば、1つの関数に書くことができます.プログラムでは何度も録音をオンにしたりオフにしたりすることができるので、それを分けます.encoder shortArrayを使ったのはENCODING_PCM_16BITのformatを使ったからですflushの意味は、例えば、機械の処理が遅いか、データが処理されていないか、バッファに残りのデータがあるか、残りのデータをファイルに書き込む必要があるということです.writeTagメソッドは、ファイルヘッダにmp 3のtagを書き込み、プレーヤー識別用にlameが開始時にファイル先頭部分を空けるのがデフォルトです.
2.2 MP3 -> PCM
菜鶏アルゴリズムはこれを書くことはできません.私たちにフロントエンドで処理しなければなりません.インタフェースに入るたびに呼び出されるので、ここは関数の中に書いてあります.
私の標準的な流れは、init->encoder->flush->writeTag->closeです.
3具体コード
いくつかはプロジェクトの要求に応じていくつかの処理をして、各位は自動的に無視します.

static lame_global_flags *lame = nullptr;

extern "C" {

/************************************************************************
 *                              PCM   MP3                              *
 ***********************************************************************/

void JNICALL xxx_RecordService_init(JNIEnv *env,jobject,jint sampleRate,
jint channelCount, jint audioFormatBit,jint quality){
    lame = lame_init();
    //     
    lame_set_in_samplerate(lame, sampleRate);
    //   
    lame_set_num_channels(lame, channelCount);
    //     
    lame_set_out_samplerate(lame, sampleRate);
    //  
    lame_set_brate(lame, audioFormatBit);
    //    
    lame_set_quality(lame, quality);
    //       
    lame_init_params(lame);
}

//  PCM,  MP3
jint JNICALL xxx_RecordService_encoder(JNIEnv *env, jobject, jshortArray pcmBuffer, jbyteArray mp3Buffer, jint sample_num) {
    //lame    short    
    jshort *pcmBuf = env->GetShortArrayElements(pcmBuffer, JNI_FALSE);
    //  MP3    
    const jsize mp3_buff_len = env->GetArrayLength(mp3Buffer);
    //  buffer  
    jbyte *mp3Buf =env->GetByteArrayElements(mp3Buffer, JNI_FALSE);

    //    bytes
    int encode_result;
    //           
    if (lame_get_num_channels(lame) == 2) {
        encode_result = lame_encode_buffer_interleaved(lame, pcmBuf, sample_num / 2,(unsigned char *) mp3Buf,mp3_buff_len);
    } else {
        encode_result = lame_encode_buffer(lame, pcmBuf, pcmBuf, sample_num,(unsigned char *) mp3Buf, mp3_buff_len);
    }
    //    
    env->ReleaseShortArrayElements(pcmBuffer, pcmBuf, 0);
    env->ReleaseByteArrayElements(mp3Buffer, mp3Buf, 0);
    return encode_result;
}
//      
jint JNICALL xxx_RecordService_flush(JNIEnv *env,jobject, jbyteArray mp3Buffer) {
    //  MP3    
    const jsize mp3_buff_len = env->GetArrayLength(mp3Buffer);
    //  buffer  
    jbyte *mp3Buf = env->GetByteArrayElements(mp3Buffer, JNI_FALSE);
    //       ,              
    int flush_result = lame_encode_flush(lame, (unsigned char *)mp3Buf, mp3_buff_len);
    env->ReleaseByteArrayElements(mp3Buffer, mp3Buf, 0);
    return flush_result;
}
//   MP3 Tag
void JNICALL xxx_RecordService_writeTag(JNIEnv *env,jobject,jstring mp3FilePath){
    FILE *mp3File = fopen(jstring2string(env,mp3FilePath).c_str(),"ab+");
    lame_mp3_tags_fid(lame, mp3File);
    fclose(mp3File);
}

//     
void JNICALL xxx_RecordService_close(JNIEnv *env,jobject) {
    lame_close(lame);
}

/************************************************************************
 *                              PCM   MP3                              *
 ***********************************************************************/
 
//     pcmPath,    pcm  
jboolean JNICALL xxx_RecordService_Mp3ToPcm(
        JNIEnv *env,
        jobject, jstring mp3Path,jstring pcmPath) {
    vector forHH;
    int read, i, samples;

    long cumulative_read = 0;

    const int PCM_SIZE = 8192;
    const int MP3_SIZE = 8192;

    //       
    short int pcm_l[PCM_SIZE], pcm_r[PCM_SIZE];
    unsigned char mp3_buffer[MP3_SIZE];

    //input  MP3  
    FILE *mp3 = fopen(jstring2string(env,mp3Path).c_str(), "rb");
    FILE *pcm = fopen(jstring2string(env,pcmPath).c_str(), "wb");
    fseek(mp3, 0, SEEK_SET);

    lame = lame_init();
    lame_set_decode_only(lame, 1);

    hip_t hip = hip_decode_init();

    mp3data_struct mp3data;
    memset(&mp3data, 0, sizeof(mp3data));

    int nChannels = -1;
    int mp3_len;

    while ((read = fread(mp3_buffer, sizeof(char), MP3_SIZE, mp3)) > 0) {
        mp3_len = read;
        cumulative_read += read * sizeof(char);
        do{
            samples = hip_decode1_headers(hip, mp3_buffer, mp3_len, pcm_l, pcm_r, &mp3data);
            //       
            if(mp3data.header_parsed == 1){
                nChannels = mp3data.stereo;
            }

            if(samples > 0){
                for(i = 0 ; i < samples; i++){
                    forHH.push_back(pcm_l[i]);
                    fwrite((char*)&pcm_l[i], sizeof(char), sizeof(pcm_l[i]), pcm);
                    if(nChannels == 2){
                        forHH.push_back(pcm_r[i]);
                        fwrite((char*)&pcm_r[i], sizeof(char), sizeof(pcm_r[i]), pcm);
                    }
                }
            }
            mp3_len = 0;
        }while(samples>0);
    }
    hip_decode_exit(hip);
    lame_close(lame);
    fclose(mp3);
    fclose(pcm);
    
//     forHH  short   float
    float* finalData = new float[forHH.size()];

    for(int z = 0;z