Android NDK Development (vi)--using open source lame transcoding mp3

Source: Internet
Author: User

Reprint Please specify source:http://blog.csdn.net/allen315410/article/details/42456661

Some of the previous blogs in this column have covered some of the basics of Android NDK development, from the environment to the use of JNI for Java and C-side code to call each other, and the demo is very easy to understand, I believe that the majority of the previous blog content, You can start using JNI for the NDK development in a real project, and since the basics are over, I'll try to use the real project here. We know that C language because of high efficiency, but also one of the earliest advanced programming, has survived nearly 40 years, so many use C developed efficient class library can be reused, so not only to achieve high efficiency, but also reduce the project development cycle. Here I found an audio file transcoding the most commonly used class library--lame, this blog is based on LAME development of a WAV audio file transcoding into MP3 audio files of small projects.


I. INTRODUCTION of LAME

Lame is currently the best MP3 coding engine. Lame encoded MP3 tone 祝着, broad space, clear bass, good detail performance, its original psychological sound model technology to ensure the authenticity of CD audio restoration, with VBR and ABR parameters, the sound quality can almost be comparable to CD audio, but the file volume is very small. For a free engine, lame's advantages are self-evident. About lame introduction can be found in the Baidu Encyclopedia, Wikipedia, I do not repeat here, but to know that lame can help us to convert WAV lossless audio files into mp3 This volume of relatively small audio format files.

Note: About WAV and MP3 is a series of audio codec algorithm, specifically I am not particularly aware of its strong and implementation principle, want to learn more about audio coding also need to find some relevant documents to read, but it is not clear that this does not prevent us from developing such a project.

Lame source is hosted on the SourceForge.net, we develop a project based on lame, we have to download its source code for compiling.

Lame Home: http://lame.sourceforge.net/

Lame Download: http://sourceforge.net/projects/lame/files/lame/3.99/

At present, the latest version of Lame is 3.99.5, can not connect to the SourceForge homepage of a friend may click Csdn Download, I have uploaded, the address is: http://download.csdn.net/detail/lee_tianya/8332357


Ii. preparation of local methods

When developing this transcoding project, do simple processing, write two simple native methods, one is Convertmp3 (String wav,string mp3), this method is the main native method, The purpose is to pass the path of the two audio files obtained from the Java layer to the C-end, and the C-end to the two paths, read-write and encode and decode operations, and another native method is Getlameversion (), the method is to obtain the lame version number, The return value is a string that is useful for verifying that the. So file is successfully compiled locally. The source code is as follows

/** * wav Convert to MP3 local method *  * @param wav * @param mp3 */public native void Convertmp3 (string wav, string mp3);/** * Get lame Version information *  * @return */public native String getlameversion ();

Third, compile the header file

Learning from the previous blogs, we know that after defining the native method we need in the Java layer, we need to compile the method signature required in the C file using the Javah command provided by the JDK, which is 1, If you are using jdk1.6 and the following versions, switch the directory to the classes directory under the project directory, 2, if you are using the jdk1.7 version, please switch the directory to the SRC directory under the project directory and execute the following Javah command:,


Good! See no error, it means that our method signature file and generated, in the SRC directory found this method signature file, in the project directory to create a new JNI directory, the method signature file copied into the JNI directory, we first open this file to see the content.

/* Don't EDIT this file-it are machine generated */#include <jni.h>/* Header for class Com_example_lame_mainactivi Ty */#ifndef _included_com_example_lame_mainactivity#define _included_com_example_lame_mainactivity#ifdef __ Cplusplusextern "C" {#endif */* Class:     com_example_lame_mainactivity * Method:    Convertmp3 * Signature: (ljava/ lang/string; ljava/lang/string;) V */jniexport void Jnicall Java_com_example_lame_mainactivity_convertmp3  (JNIENV *, Jobject, Jstring, jstring);/* Class:     com_example_lame_mainactivity * Method:    getlameversion * Signature: () Ljava/lang /string; */jniexport jstring jnicall java_com_example_lame_mainactivity_getlameversion  (jnienv *, jobject); #ifdef __ Cplusplus} #endif #endif

Iv. Import the source code of lame into the JNI directory

It is particularly important and careful to get here, because you need to refer to the Open Source Library lame to this project and recompile the library for this platform.

1, the downloaded lame source extracted to the local, open the extracted directory, find the Libmp3lame directory, the directory of all the files are copied to the JNI directory.

2. Remove unnecessary file directories. For example i386 this directory to delete, but also to delete a few non-. h,.c as the extension of the file, has been Linux under the batch file, because these files are not necessary under the Android platform.

3, introduce lame.h header file. Locate the Include directory under the Lame decompression directory, copy the lame.h header file under it to the JNI directory, and if this directory is not introduced, it will report the following error


4, modify the source code of Util.h. Locate the Util.h file in the JNI directory, find the ieee754_float32_t data type in line 574, and modify it to float type, because ieee754_float32_t is a data type supported by Linux or UNIX, Not supported under Android. If you do not modify, compile the source code will report the following error



Five, write the local C language code, to achieve the transcoding of audio files

about how to write this C language code, is really some difficulty, need a certain C language knowledge, But also to be able to understand the Lame.h file provided in the API and comments, here I do not explain, because this thing is more complicated, just a blog is not complete, the following paste C code, the Code provides a more detailed comments, with comments to see the code, easy to understand!

#include <stdio.h> #include <jni.h> #include <malloc.h> #include <string.h> #include <lame.h > #include "com_example_lame_mainactivity.h" #include <android/log.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__)/** * Return value char* This represents the first address of the char array * JSTRING2CSTR converts the type of jstring in Java into a char string in the C language */char* JSTRING2CSTR (jnienv* env, jstring jstr) {char* Rtn = Null;jclass clsstring = (*env)->findclass (env, "java/lang/string" ); Stringjstring Strencode = (*env)->newstringutf (env, "GB2312"); Get a Java string "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); The length of the byte array jbyte* ba = (*env)->geTbytearrayelements (env, Barr, Jni_false); if (Alen > 0) {rtn = (char*) malloc (alen + 1);//"memcpy" (RTN, BA, Alen); RTN [Alen] = 0;} (*env)->releasebytearrayelements (env, Barr, BA, 0); return RTN;} int flag = 0;/** * wav conversion mp3 */jniexport void Jnicall Java_com_example_lame_mainactivity_convertmp3 (jnienv * env, Jobject o BJ, Jstring jwav, jstring Jmp3) {char* cwav =jstring2cstr (env,jwav); char* cmp3=jstring2cstr (Env,jmp3); Logi ("wav =%s", cwav); Logi ("MP3 =%s", Cmp3);//1. Open Wav,mp3 file file* fwav = fopen (Cwav, "RB"); file* Fmp3 = fopen (Cmp3, "WB"); short int wav_buffer[8192*2];unsigned char MP3_BUFFER[8192];//1. To initialize the lame encoder lame_t lame = l Ame_init ();//2. Set LAME MP3 encoded sample rate lame_set_in_samplerate (lame, 44100); Lame_set_num_channels (lame,2);//3. Set MP3 encoding method LAME_SET_VBR (lame, vbr_default); Lame_init_params (lame); Logi ("lame init finish"); int read; int write; Delegate read how many times and write how many times int total=0; The byte number of the current read WAV file Do{if (flag==404) {return;} Read = Fread (wav_buffer,sizeof (short int) * *, 8192,fwav); Total + = read* sizeof (short int) * *; Logi ("Converting ....%d", total);p ublishjavaprogress (env,obj,total);//Call the Java Code completion progress bar Update if (read!=0) {write = Lame_ Encode_buffer_interleaved (lame,wav_buffer,read,mp3_buffer,8192);//write the converted MP3 data into the file fwrite (mp3_buffer,sizeof ( unsigned char), Write,fmp3);} if (read==0) {Lame_encode_flush (lame,mp3_buffer,8192);}} while (read!=0); Logi ("Convert Finish"); Lame_close (lame); fclose (fwav); fclose (Fmp3);} /** * Call the Java Code Updater progress bar */void publishjavaprogress (jnienv * env, Jobject obj, jint progress) {//1. Find Java's mainactivity CLA Ssjclass clazz = (*env)->findclass (env, "com/example/lame/mainactivity"); if (clazz = = 0) {logi ("can ' t find Clazz");} Logi ("Find Clazz");//2 find the method definition inside class Jmethodid Methodid = (*env)->getmethodid (env, Clazz, "Setconvertprogress", "(I ), if (Methodid = = 0) {logi ("can ' t find Methodid");} Logi ("Find Methodid");//3. Invoke Method (*env)->callvoidmethod (env, obj, Methodid, progress);} /** * Get Lame version number */jniexport jstring Jnicall java_com_example_lame_mainactivity_getlameveRsion (JNIENV * env, Jobject obj) {return (*env)->newstringutf (env, get_lame_version ());} 
The above creates a new convert.c C source file, the source code first refers to some related class library to use, for example <stdio.h><jni.h><malloc.h><string.h> These are the standard class libraries for C, which are introduced in the code. Next, we need to refer to the compiled method signature file in the third topic above com_example_lame_ MainActivity.h, this file defines the signature of the native method, facilitates the compiler to find the corresponding native method, there is a very important header file Lame.h, this project is lame, so this lame.h header file must be referenced, and finally log.h Introduced and defined, are fixed content, look at the source is good.


Vi. writing configuration files and cross-compiling

After completing the above steps and writing the source code, the rest is the configuration file. First look at the Android.mk file, this is troublesome, because we will lame the entire source files are copied to the JNI directory, these files are to be recompiled, so we need to android.mk file local_src_files this field, will be so the source files are to be configured, not only our custom C files, but also lame C source files, because lame contains too many files, so in writing a local_src_files to be extra careful, write the wrong one is likely to code does not pass. Here is my configuration scenario:

Local_path: = $ (call My-dir) include $ (clear_vars) local_module    : = convertlocal_src_files: = convert.c 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.clocal_ldlibs + =-lloginclude $ (build_shared_library)
Application.mk

App_platform: = android-8
Cygwin under cross-compilation:

Good! See the tips at the bottom of our. So is compiled well, due to more files, compiling is a bit of time, and the above error is a lot of warnning warning prompt, but it does not matter, can be ignored, as long as not error, then this project can still run.


Vii. write code at the Java layer that calls the C-terminal

Before writing the Java write call code, we consider that because the codec is a very time-consuming operation, so this operation is not able to be executed in the main thread, must be opened new thread, because it is a time-consuming operation, so for a good user experience, We need to add a progress bar in the Transcoding Process dialog box, prompting a transcoding process, about this progress bar progress is also given to the C language implementation, we in Java only need to define a way to set the progress, in C language callback this Java method, Pass the progress data to the progress Bar dialog box in Java.

public class Mainactivity extends Activity {static {system.loadlibrary ("Convert");} Private EditText et_wav;private EditText et_mp3;private progressdialog pd;/** * wav conversion to MP3 local method * * @param wav * @param MP 3 */public native void Convertmp3 (string wav, string mp3);/** * Get Lame version information * * @return */public native String getlamever Sion (); @Overrideprotected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); Setcontentview (r.layout.activity_main); et_wav = (EditText) This.findviewbyid (r.id.et_wav); Et_mp3 = (EditText) This.findviewbyid (R.id.et_mp3);pd = new ProgressDialog (this);} /** * WAV conversion mp3 */public void convert (view view) {final string mp3path = Et_mp3.gettext (). toString (). Trim (); final String WA VPath = Et_wav.gettext (). toString (). Trim (); File File = new file (wavpath); int size = (int) file.length (); SYSTEM.OUT.PRINTLN ("File size" + size), if ("". Equals (Mp3path) | | "". Equals (Wavpath)) {Toast.maketext (mainactivity.this, "path cannot be empty", 1). Show (); return;} Pd.setmessage ("in conversion ....");pd.Setprogressstyle (Progressdialog.style_horizontal);pd. Setmax (size); Set the maximum value of the progress bar to Pd.setcancelable (false);pd. Show ();//transcoding is a time-consuming operation, so it is necessary to open a new thread to execute "{@Overridepublic void run () { Convertmp3 (Wavpath, Mp3path);pd. Dismiss ();}. Start ();} /** * Sets progress bar progress, provided to C language call * * @param progress */public void setconvertprogress (int progress) {pd.setprogress (progress);} /** * Gets lame version number */public void GetVersion (view view) {Toast.maketext (Mainactivity.this, Getlameversion (), 0). Show ();}}
Note that you need to add the permissions two article:

<uses-permission android:name= "Android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/><uses-permission android: Name= "Android.permission.WRITE_EXTERNAL_STORAGE"/>
Eight, test well, write here is finally a project completed, the following to test, first open an arm simulator, and then run the project.

1, test version number


2, test wav turn mp3

OK, let's take a look at the original WAV audio file under SDcard and the mp3 file after transcoding

From can see our transcoding is can be used, the original WAV file does transcode into a MP3 file, and size only the original file of 1/10, export this mp3 file, play with audio player, also can hear, the file is not damaged. What do you think? Do you have any interest to try the project finished?


Please download the source code here



Android NDK Development (vi)--using open source lame transcoding mp3

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.