Android libmp3lame详解

来源:互联网 发布:如何自学linux 编辑:程序博客网 时间:2024/05/03 06:04

转自:http://wenku.baidu.com/view/70cebd3e580216fc700afd51?from_page=view&from_mod=download


练习Jni项目

一 下载 lame-3.98.4.tar.gz

 

二 创建 android 项目 lame

         创建jni目录 并

         复制 lame-3.98.4 包下的libmp3lame 目录下的所有 .c和.h文件和 include目录下的lame.h

 

三 在jni目录下创建 Android.mk文件

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := mp3lame

LOCAL_SRC_FILES := bitstream.c fft.c id3tag.c mpglib_interface.c presets.c  quantize.c   reservoir.c tables.c  util.c  VbrTag.c encoder.c  gain_analysis.c lame.c  newmdct.c   psymodel.c quantize_pvt.c set_get.c  takehiro.c vbrquantize.c version.c

include $(BUILD_SHARED_LIBRARY)

        

 

四, 编辑 jni/utils.h,

把 extern ieee754_float32_t fast_log2(ieee754_float32_t x); 替换为 extern float fast_log2(float x);

 

 

五 ndk-build

        

        

 

六 导入libmp3lame.so, 并创建native方法 然后生成头文件 cn_kq_lame_LameActivity.h

 

        

 

 

 

 

七 创建hello.c文件并将其加入Andorid.mk文件中的源代码位置后面, 然后按上面的步骤重新编译

        

 

 

 

好了我的测试通过 了, 现在来为它加入新的功能 mp3转码的功能

********************************************************************************

一 修改LameActivity 为其加入新的本地执行方法  并加入访问sdcard卡和外部存储权限

 package cn.kq.lame;

 

import android.app.Activity;

import android.app.ProgressDialog;

import android.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.view.View;

import android.widget.EditText;

import android.widget.Toast;

/**

 * @author zhaopan - 2011-10-5

 */

public class LameActivity extends Activity {

         static{

                   System.loadLibrary("mp3lame");

         }

         EditText etInput;

         EditText etOutput;

         private ProgressDialog pd;

         private Handler handler = new Handler(){

                   public void handleMessage(Message msg) {

                            //主线程收到通知消毁对话框

                            pd.dismiss();

                            super.handleMessage(msg);

                   }

         };

         public native String getVersion();

         public native void convert(String input, String output);

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        etInput = (EditText) this.findViewById(R.id.input);

        etOutput = (EditText) this.findViewById(R.id.output);

    }

   

    public void getVersion(View v){

             Toast.makeText(this, getVersion(), 1).show();

    }

    //完成从源文件到目标文件的转换

    public void convert(View v){

             final String input = etInput.getText().toString();

             final String output = etOutput.getText().toString();

             //调用c代码来完成 文件的转换

            

             pd = new ProgressDialog(this);

             pd.setMessage("转换中");

             pd.show();

            

             //起动一个线程来完成 这个耗时的操作

             new Thread(new Runnable(){

                            public void run() {

                                     convert(input, output);

                                     //转换工作完成 后发送一条消息到主线程

                                     handler.sendEmptyMessage(0);

                            }

             }).start();

    }

   

}

 

         <?xmlversion="1.0"encoding="utf-8"?>

<manifestxmlns:android="http://schemas.android.com/apk/res/android"

      package="cn.kq.lame"

      android:versionCode="1"

      android:versionName="1.0">

    <applicationandroid:icon="@drawable/icon"android:label="@string/app_name">

        <activityandroid:name=".LameActivity"

                  android:label="@string/app_name">

            <intent-filter>

                <actionandroid:name="android.intent.action.MAIN"/>

                <categoryandroid:name="android.intent.category.LAUNCHER"/>

            </intent-filter>

        </activity>

 

    </application>

    <uses-sdkandroid:minSdkVersion="8"/>

    <uses-permissionandroid:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"></uses-permission>

    <uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>

</manifest>

 

二 产生新的头文件cn_kq_lame_LameActivity.h  并将其复制到jni目录下

 

三 为Android.mk文件加入日志处理的库文件并 修改 hello.c文件加入新的处理方法   然后重新编译

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := mp3lame

LOCAL_SRC_FILES := bitstream.c fft.c id3tag.c mpglib_interface.c presets.c  quantize.c   reservoir.c tables.c  util.c  VbrTag.c encoder.c  gain_analysis.c lame.c  newmdct.c   psymodel.c quantize_pvt.c set_get.c  takehiro.c vbrquantize.c version.c hello.c

LOCAL_LDLIBS += -llog

include $(BUILD_SHARED_LIBRARY)

 

 

#include "lame.h"

#include "cn_kq_lame_LameActivity.h"

#include <jni.h>

#include<android/log.h>

#define LOG_TAG"System.out"

#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

 

char*   Jstring2CStr(JNIEnv*   env,   jstring   jstr)

{

 char*   rtn   =   NULL; //rtn 一块能够存放char类型内存的首地址

 // 找到 jvm里面 String

 jclass   clsstring   =   (*env)->FindClass(env,"java/lang/String");

 // 创建一个jstring的字符串内容 GB2312

 jstring   strencode   =   (*env)->NewStringUTF(env,"GB2312");

 // 寻找 String类的一个方法 getBytes   getBytes方法的参数 Ljava/lang/String;

 // getBytes 方法的返回值 [B

 jmethodID   mid   =   (*env)->GetMethodID(env,clsstring,   "getBytes",   "(Ljava/lang/String;)[B");

 

 // "String".getBytes("GB2312");

 jbyteArray   barr=   (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode);

 //获取到barr的长度

 jsize   alen   =   (*env)->GetArrayLength(env,barr);

//获取到的jbyte数据放入到ba为开始地址的内存空间中

 jbyte*   ba   =   (*env)->GetByteArrayElements(env,barr,JNI_FALSE);

 if(alen   >   0)

 {

  rtn   =   (char*)malloc(alen+1);        //new   char[alen+1]; "\0" 字符串的结束

  //内存拷贝的操作 ,

  memcpy(rtn,ba,alen);

  //给字符数组最后一个元素 表示字符串结束

  rtn[alen]=0;

 }

 (*env)->ReleaseByteArrayElements(env,barr,ba,0);

 

 return rtn;

}

JNIEXPORT jstring JNICALL Java_cn_kq_lame_LameActivity_getVersion

  (JNIEnv * env, jobject obj){

 

    // lame版本号返回给java

    return (*env)->NewStringUTF(env, get_lame_version());

}

 

JNIEXPORT void JNICALL Java_cn_kq_lame_LameActivity_convert

  (JNIEnv * env, jobject obj, jstring input, jstring output, jint channel , jint sample){

    //javastring类型的文件转化成c能识别的char字符串

    char* inputfile = Jstring2CStr(env,input);

    LOGI("%s",inputfile);

 

    char* outputfile = Jstring2CStr(env,output);

    LOGI("%s",outputfile);

 

 

    FILE *pcm = fopen(inputfile, "rb");

    FILE *mp3 = fopen(outputfile, "wb");

 

    int read, write;

 

 

    const int PCM_SIZE = 8192;

    const int MP3_SIZE = 8192;

 

    short int pcm_buffer[PCM_SIZE*2];

    unsigned char mp3_buffer[MP3_SIZE];

    //初始化lame解码器

    lame_t lame = lame_init();

    // 设置音频的采样率

    lame_set_in_samplerate(lame, 44100);

    // 设置lame编码器的声道

    lame_set_num_channels(lame,2);

    // vbr 设置采样压缩格式

    lame_set_VBR(lame, vbr_default);

    //初始化lame的编码器

    lame_init_params(lame);

    LOGI("INIT LAME FININSH ");

    do {

        read = fread(pcm_buffer, 2*sizeof(shortint), PCM_SIZE, pcm);  

//读出来的pcm数据放在 pcm_buffer里面

//pcm文件里面读PCM_SIZE 2*sizeof(short int)个数据,放倒pcm_buffer

        if (read == 0)

            write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);

        else

            write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);

                                                 //pcm_buffer pcm数据

                                                 //read  /* number of samples per channel,

                                                 //mp3_buffer 编码后mp3数据

                                                 // 要写入多少个数据

 

        fwrite(mp3_buffer, 1, write, mp3);

       //mp3_buffer 缓冲区

        // 1是一个字节

        //write是要写的长度

        //mp3 是写入的文件名

    } while (read != 0);

 

    LOGI("LAME ENCODE FININSH");

    lame_close(lame);

    fclose(mp3);

    fclose(pcm);

}

 

 

由于后面在convert方法中多加了两个参数指定采样率和通道的入参来替换c代码中的 441000 和2

所以报了下面的错误 , 把那两个参数加入或删除就行了, 28和30的warning不用管。

 

 

 

 

 


0 3