Android多媒体开发(4)————移植Libmad到android平台

http://blog.csdn.net/conowen/article/details/7727145 分类: Android多媒体&流媒体开发

/********************************************************************************************
* author:conowen@大钟
* E-mail:conowen@hotmail.com
* http://blog.csdn.net/conowen
* 注:本文为原创,仅作为学习交流使用,转载请标明作者及出处。

********************************************************************************************/


众所周知,Android的audiotrack只能播放原始的音频,也就是PCM数据,若是播放mp3编码格式的音频的话,就是出现沙沙的噪音。所以,可以使用第三方库Libmad来对mp3文件解码称为PCM数据,再送给audiotrack播放即可。


1、Libmad简介

Libmad是一个开源的高精度 MPEG 音频解码库,支持 MPEG-1(Layer I, Layer II 和 LayerIII(也就是 MP3)。LIBMAD 提供 24-bit 的 PCM 输出,完全是定点计算,非常适合没有浮点支持的平台上使用。使用 libmad 提供的一系列 API,就可以非常简单地实现 MP3 数据解码工作。在 libmad 的源代码文件目录下的 mad.h 文件中,可以看到绝大部分该库的数据结构和 API 等。


2、实现过程

2.1、下载Android平台下的Libmad工程

http://gitorious.org/rowboat/external-libmad

或者直接执行

[java] view plain copy print ?
  1. mkdirlibmad
  2. cdlibmad
  3. gitclonegit://gitorious.org/rowboat/external-libmad.git


下载的project可以直接用NDK编译通过的,但是要使用还是要写jni层供java层调用,关于NDK开发,可以参看我之前的博文。

但是Android.mk要改成如下形式。

[java] view plain copy print ?
  1. #ifeq($(strip$(BUILD_WITH_GST)),true)
  2. LOCAL_PATH:=$(callmy-dir)
  3. include$(CLEAR_VARS)
  4. LOCAL_SRC_FILES:=\
  5. version.c\
  6. fixed.c\
  7. bit.c\
  8. timer.c\
  9. stream.c\
  10. frame.c\
  11. synth.c\
  12. decoder.c\
  13. layer12.c\
  14. layer3.c\
  15. huffman.c
  16. LOCAL_ARM_MODE:=arm
  17. LOCAL_MODULE:=libmad
  18. LOCAL_C_INCLUDES:=\
  19. $(LOCAL_PATH)/android
  20. LOCAL_CFLAGS:=-DHAVE_CONFIG_H-DFPM_ARM-ffast-math-O3
  21. include$(BUILD_SHARED_LIBRARY)
  22. #endif

2.2、C代码编写API

需要注意一点的是,得到音频的Samplerate(采样率)要先进行一次readSamples操作才能发采样率读出。具体看代码即可。


[cpp] view plain copy print ?
  1. #defineTAG"NativeMP3Decoder"
  2. #include"FileSystem.h"
  3. #include"Mad.h"
  4. #include"NativeMP3Decoder.h"
  5. #include<stdio.h>
  6. #include<string.h>
  7. #include<stdlib.h>
  8. #include<android/log.h>
  9. #defineSHRT_MAX(32767)
  10. #defineINPUT_BUFFER_SIZE(8192/4)
  11. #defineOUTPUT_BUFFER_SIZE8192/*Mustbeanintegermultipleof4.*/
  12. //intg_size;
  13. externintfile_open(constchar*filename,intflags);
  14. externintfile_read(T_pFILEfd,unsignedchar*buf,intsize);
  15. externintfile_write(T_pFILEfd,unsignedchar*buf,intsize);
  16. externint64_tfile_seek(T_pFILEfd,int64_tpos,intwhence);
  17. externintfile_close(T_pFILEfd);
  18. /**
  19. *Structholdingthepointertoawavefile.
  20. */
  21. typedefstruct
  22. {
  23. intsize;
  24. int64_tfileStartPos;
  25. T_pFILEfile;
  26. structmad_streamstream;
  27. structmad_frameframe;
  28. structmad_synthsynth;
  29. mad_timer_ttimer;
  30. intleftSamples;
  31. intoffset;
  32. unsignedcharinputBuffer[INPUT_BUFFER_SIZE];
  33. }MP3FileHandle;
  34. /**staticWaveFileHandlearray**/
  35. staticinlineintreadNextFrame(MP3FileHandle*mp3);
  36. staticMP3FileHandle*Handle;
  37. unsignedintg_Samplerate;
  38. /**
  39. *Seeksafreehandleinthehandlesarrayandreturnsitsindexor-1ifnohandlecouldbefound
  40. */
  41. staticinlinevoidcloseHandle()
  42. {
  43. file_close(Handle->file);
  44. mad_synth_finish(&Handle->synth);
  45. mad_frame_finish(&Handle->frame);
  46. mad_stream_finish(&Handle->stream);
  47. free(Handle);
  48. Handle=NULL;
  49. }
  50. staticinlinesignedshortfixedToShort(mad_fixed_tFixed)
  51. {
  52. if(Fixed>=MAD_F_ONE)
  53. return(SHRT_MAX);
  54. if(Fixed<=-MAD_F_ONE)
  55. return(-SHRT_MAX);
  56. Fixed=Fixed>>(MAD_F_FRACBITS-15);
  57. return((signedshort)Fixed);
  58. }
  59. intNativeMP3Decoder_init(char*filepath,unsignedlongstart/*,unsignedlongsize*/)
  60. {
  61. __android_log_print(ANDROID_LOG_INFO,TAG,"start=%d*******\n",start);
  62. //__android_log_print(ANDROID_LOG_INFO,TAG,"size=%d*******\n",size);
  63. //g_size=size;
  64. T_pFILEfileHandle=file_open(filepath,_FMODE_READ);
  65. if(fileHandle==0)
  66. return-1;
  67. MP3FileHandle*mp3Handle=(MP3FileHandle*)malloc(sizeof(MP3FileHandle));
  68. memset(mp3Handle,0,sizeof(MP3FileHandle));
  69. mp3Handle->file=fileHandle;
  70. //mp3Handle->size=size;
  71. mp3Handle->fileStartPos=start;
  72. file_seek(mp3Handle->file,start,SEEK_SET);
  73. mad_stream_init(&mp3Handle->stream);
  74. mad_frame_init(&mp3Handle->frame);
  75. mad_synth_init(&mp3Handle->synth);
  76. mad_timer_reset(&mp3Handle->timer);
  77. Handle=mp3Handle;
  78. readNextFrame(Handle);
  79. g_Samplerate=Handle->frame.header.samplerate;
  80. return1;
  81. }
  82. staticinlineintreadNextFrame(MP3FileHandle*mp3)
  83. {
  84. do
  85. {
  86. if(mp3->stream.buffer==0||mp3->stream.error==MAD_ERROR_BUFLEN)
  87. {
  88. intinputBufferSize=0;
  89. if(mp3->stream.next_frame!=0)
  90. {
  91. intleftOver=mp3->stream.bufend-mp3->stream.next_frame;
  92. inti;
  93. for(i=0;i<leftOver;i++)
  94. mp3->inputBuffer[i]=mp3->stream.next_frame[i];
  95. intreadBytes=file_read(mp3->file,mp3->inputBuffer+leftOver,INPUT_BUFFER_SIZE-leftOver);
  96. if(readBytes==0)
  97. return0;
  98. inputBufferSize=leftOver+readBytes;
  99. }
  100. else
  101. {
  102. intreadBytes=file_read(mp3->file,mp3->inputBuffer,INPUT_BUFFER_SIZE);
  103. if(readBytes==0)
  104. return0;
  105. inputBufferSize=readBytes;
  106. }
  107. mad_stream_buffer(&mp3->stream,mp3->inputBuffer,inputBufferSize);
  108. mp3->stream.error=MAD_ERROR_NONE;
  109. }
  110. if(mad_frame_decode(&mp3->frame,&mp3->stream))
  111. {
  112. if(mp3->stream.error==MAD_ERROR_BUFLEN||(MAD_RECOVERABLE(mp3->stream.error)))
  113. continue;
  114. else
  115. return0;
  116. }
  117. else
  118. break;
  119. }
  120. while(1);
  121. mad_timer_add(&mp3->timer,mp3->frame.header.duration);
  122. mad_synth_frame(&mp3->synth,&mp3->frame);
  123. mp3->leftSamples=mp3->synth.pcm.length;
  124. mp3->offset=0;
  125. return-1;
  126. }
  127. intNativeMP3Decoder_readSamples(short*target,intsize)
  128. {
  129. MP3FileHandle*mp3=Handle;
  130. //short*target=(short*)env->GetDirectBufferAddress(buffer);
  131. intpos=0;
  132. intidx=0;
  133. while(idx!=size)
  134. {
  135. if(mp3->leftSamples>0)
  136. {
  137. for(;idx<size&&mp3->offset<mp3->synth.pcm.length;mp3->leftSamples--,mp3->offset++)
  138. {
  139. intvalue=fixedToShort(mp3->synth.pcm.samples[0][mp3->offset]);
  140. if(MAD_NCHANNELS(&mp3->frame.header)==2)
  141. {
  142. value+=fixedToShort(mp3->synth.pcm.samples[1][mp3->offset]);
  143. value/=2;
  144. }
  145. target[idx++]=value;
  146. }
  147. }
  148. else
  149. {
  150. pos=file_seek(mp3->file,0,SEEK_CUR);
  151. intresult=readNextFrame(mp3);
  152. if(result==0)
  153. return0;
  154. }
  155. }
  156. /*if(pos>mp3->fileStartPos+mp3->size)
  157. {
  158. __android_log_print(ANDROID_LOG_INFO,TAG,"*****return-1**\n");
  159. return-1;
  160. }
  161. */
  162. if(idx>size)
  163. return0;
  164. //returnsize;
  165. returnpos;
  166. }
  167. intNativeMP3Decoder_getAduioSamplerate()
  168. {
  169. returng_Samplerate;
  170. }
  171. voidNativeMP3Decoder_closeAduioFile()
  172. {
  173. if(Handle!=0)
  174. {
  175. closeHandle();
  176. Handle=0;
  177. }
  178. }

头文件声明

[cpp] view plain copy print ?
  1. /*DONOTEDITTHISFILE-itismachinegenerated*/
  2. #include<jni.h>
  3. #include<stdlib.h>
  4. intNativeMP3Decoder_init(char*filepath,unsignedlongstart/*,unsignedlongsize*/);
  5. intNativeMP3Decoder_readSamples(short*target,intsize);
  6. voidNativeMP3Decoder_closeAduioFile();
  7. intNativeMP3Decoder_getAduioSamplerate();

2.2、编写JNI调用代码,往上提供接口

[cpp] view plain copy print ?
  1. #defineTAG"native_libmad"
  2. #include"FileSystem.h"
  3. #include<stdlib.h>
  4. #include<jni.h>
  5. #include<android/log.h>
  6. externintNativeMP3Decoder_readSamples(short*target,intsize);
  7. externvoidNativeMP3Decoder_closeAduioFile();
  8. externintNativeMP3Decoder_getAduioSamplerate();
  9. externintNativeMP3Decoder_init(char*filepath,unsignedlongstart);
  10. jintJava_com_conowen_libmad_NativeMP3Decoder_initAudioPlayer(JNIEnv*env,jobjectobj,jstringfile,jintstartAddr)
  11. {
  12. char*fileString=(*env)->GetStringUTFChars(env,file,NULL);
  13. returnNativeMP3Decoder_init(fileString,startAddr);
  14. }
  15. jintJava_com_conowen_libmad_NativeMP3Decoder_getAudioBuf(JNIEnv*env,jobjectobj,jshortArrayaudioBuf,jintlen)
  16. {
  17. intbufsize=0;
  18. intret=0;
  19. if(audioBuf!=NULL){
  20. bufsize=(*env)->GetArrayLength(env,audioBuf);
  21. jshort*_buf=(*env)->GetShortArrayElements(env,audioBuf,0);
  22. memset(_buf,0,bufsize*2);
  23. ret=NativeMP3Decoder_readSamples(_buf,len);
  24. (*env)->ReleaseShortArrayElements(env,audioBuf,_buf,0);
  25. }
  26. else{
  27. __android_log_print(ANDROID_LOG_DEBUG,TAG,"getAudiofailed");
  28. }
  29. returnret;
  30. }
  31. jintJava_com_conowen_libmad_NativeMP3Decoder_getAudioSamplerate()
  32. {
  33. returnNativeMP3Decoder_getAduioSamplerate();
  34. }
  35. voidJava_com_conowen_libmad_NativeMP3Decoder_closeAduioFile()
  36. {
  37. NativeMP3Decoder_closeAduioFile();
  38. }


2.3、文件读写操作


[java] view plain copy print ?
  1. #include<unistd.h>
  2. #include<sys/stat.h>
  3. #include<sys/time.h>
  4. #include<sys/types.h>
  5. #include<stdlib.h>
  6. #include<fcntl.h>
  7. #include"FileSystem.h"
  8. intfile_open(constchar*filename,intflags)
  9. {
  10. intaccess;
  11. T_pFILEfd=0;
  12. if(flags==_CREATE){
  13. access=O_CREAT|O_TRUNC|O_RDWR;
  14. }elseif(flags==_WRONLY){
  15. access=O_CREAT|O_TRUNC|O_WRONLY;
  16. }elseif(flags==_RDONLY){
  17. access=O_RDONLY;
  18. }elseif(flags==_RDWR){
  19. access=O_RDWR;
  20. }else{
  21. return-1;
  22. }
  23. #ifdefO_BINARY
  24. access|=O_BINARY;
  25. #endif
  26. fd=open(filename,access,0666);
  27. if(fd==-1)
  28. return-1;
  29. returnfd;
  30. }
  31. intfile_read(T_pFILEfd,unsignedchar*buf,intsize)
  32. {
  33. returnread(fd,buf,size);
  34. }
  35. intfile_write(T_pFILEfd,unsignedchar*buf,intsize)
  36. {
  37. returnwrite(fd,buf,size);
  38. }
  39. int64_tfile_seek(T_pFILEfd,int64_tpos,intwhence)
  40. {
  41. if(whence==0x10000){
  42. structstatst;
  43. intret=fstat(fd,&st);
  44. returnret<0?-1:st.st_size;
  45. }
  46. returnlseek(fd,pos,whence);
  47. }
  48. intfile_close(T_pFILEfd)
  49. {
  50. returnclose(fd);
  51. }

头文件

[java] view plain copy print ?
  1. #include<stdlib.h>
  2. typedefsignedlongT_S32;/*signed32bitinteger*/
  3. #defineT_pFILET_S32
  4. #defineT_hFILET_S32
  5. #define_CREATE0//"wb+"//0
  6. #define_RDONLY1//"rb"//1
  7. #define_WRONLY2//"wb"//2
  8. #define_RDWR3//"rb+"//3
  9. #define_FMODE_READ_RDONLY
  10. #define_FMODE_WRITE_WRONLY
  11. #define_FMODE_CREATE_CREATE
  12. #define_FMODE_OVERLAY_RDWR
  13. #define_FSEEK_CURRENT1
  14. #define_FSEEK_END2
  15. #define_FSEEK_SET0
  16. #define_FOPEN_FAIL-1
  17. #defineSEEK_CURRENT1
  18. #defineSEEK_CUR1
  19. #defineSEEK_END2
  20. #defineSEEK_SET0
  21. #defineFS_SEEK_SET0


把上述两个c文件,加入Android文件编译即可生成。90K左右

更多相关文章

  1. Android(安卓)studio3.0 com.android.tools.aapt2.Aapt2Exceptio
  2. Android之访问下载文件
  3. 【android开发】android操作文件
  4. ubuntu 不是 识别 android 设备 解决方法
  5. 短视频带货源码模仿QQ 测滑菜单
  6. Android文件图片上传的详细讲解(三)---模式回调类
  7. Android中设置全屏的方法
  8. react-native apk打包 android
  9. NPM 和webpack 的基础使用

随机推荐

  1. Android中的资源与国际化
  2. Android - 数据存储
  3. Android-webview访问本地HTML5及本地HTML
  4. Android(安卓)中判断是否存在虚拟按键
  5. Android原生(Native)C开发之一 环境搭建
  6. android实现推送实践
  7. android+XML使用
  8. android 如何使用Parcelable接口
  9. android 中获取所有有效网卡和对应的IP地
  10. Android加密之全盘加密