Android多媒体开发(3)————使用Android NKD编译havlenapetr-FFMpeg-7c27aa2

http://blog.csdn.net/conowen/article/details/7526398

分类: Android多媒体&流媒体开发

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

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


1、

使用NDK去编译官方的FFmpeg原版的话,还得自己实现JNI层与java层工程量比较大。所以移植FFmpeg到Android平台时,可以移植一些已经实现JNI与JAVA层的开源项目,毕竟软件行业从来都是站在巨人肩膀上发展的。


2、移植havlenapetr/FFMpeg


havlenapetr的开源项目是比较出名的一个FFmpeg工程,很多Android多媒体项目都是在此基础上面修改的。


下载地址:https://github.com/havlenapetr/FFMpeg

可以直接ZIP包:https://github.com/havlenapetr/FFMpeg/zipball/debug

或者通过git方式下载,新建一个目录,然后在linux的终端下执行,当然了,你要事情安装git的相关工具

[java] view plain copy print ?
  1. gitclonehttps://github.com/havlenapetr/FFMpeg.git

3、利用NDK编译生成so库


下载后直接在havlenapetr-FFMpeg-7c27aa2的顶级目录下执行

[java] view plain copy print ?
  1. $ndk/ndk-build

是可以编译通过的,不会提示任何error。

关于如何利用NDK编译,可以参考我之前的博文:http://blog.csdn.net/conowen/article/details/7518870


4、导入java工程,实现播放

然后把在eclipse里面,把havlenapetr-FFMpeg-7c27aa2这个项目import进来,就可以播放视频了。


4.1、需要注意的是:这个版本的havlenapetr FFmpeg工程只能在Android 2.2上面运行,因为havlenapetr采用的是音视频直接在JNI层输入。可以注意到havlenapetr-FFMpeg-7c27aa2目录下有prebuilt这样一个目录,此目录下有Android 2.2版本的libjniaudio.so和libjnivideo.so两个库文件。


4.2、Android版本不同导致不能播放:

havlenapetr的FFmpeg项目音视频输出如下

音频:采用Android底层的audiotrack输出。

视频:在FFmpeg解码之后,得到YUV信号,然后转换成RGB信号,最终通过Android底层的surface输出。


提示:可以移植SDL开源库实现音视频输出,因为SDL的视频输出机制是通过OPenGL呈现画面,这样就可以兼容所有的Android平台。


但是问题就来了,Android每个版本的framework都是不大一样的,所以要在底层使用Android的audiotrack和surface来输入音视频信号,就要在相应版本的Android源代码中,重新编译生成libjniaudio.so和libjnivideo.so两个库文件了。


5、编译havlenapetr FFmpeg工程Android 2.3版本的libjniaudio.so和libjnivideo.so

首先要明白一点,Android的官方源代码编译之后,是不会生成libjniaudio.so和libjnivideo.so的。所以要自己添加audiotrack.cpp、surface.cpp和Android.mk文件到Android源代码里面编译生成。(每次编译libjniaudio.so和libjnivideo.so都要重新编译这个Android源代码,时间比较长。)


5.1下载audio与video文件夹

可以在https://github.com/havlenapetr/android_frameworks_base下载audiotrack.cpp、surface.cpp和Android.mk,注意要选择正确的branch(分支)

froyo---->Android 2.2

gingerbread---->Android 2.3

ICS---->Android 4.0


关于havlenapetr-FFMpeg在Android 4.0(ICS)的补充说明



5.2、编译Android系统源代码

下载之后,然后找到里面的native文件夹,把里面的audio和video文件夹拖进Android源代码的frameworks/base/native目录下。

绿色的是新加入的文件


需要注意的一点是:

gingerbread下载之后,里面是没有audio和video文件夹的,但是可以用froyo版本的audio和video文件夹。(也就是下载gingerbread感觉也没啥用Orz~~~)

但是我们可以使用froyo的audio和video文件夹,编译Android源代码是可以成功通过的,ndk-build也可以通过,但是在Android的java工程里面使用就会有以下错误信息。

[cpp] view plain copy print ?
  1. java.lang.NoSuchFieldError:nofieldwithname='mSurface'signature='I'inclassLandroid/view/Surface;

加载库时,找不到mSruface类
修改方法是:
将surface.cpp中mSurface改为 mNativeSurface 然后重新编译即可。当然了,你也可以用ICS的surface.cpp文件,这个版本是没有问题的。


另外编译havlenapetr FFmpeg工程Android 4.0版本的libjniaudio.so和libjnivideo.so与上面步骤差不多。


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

附上我所使用的audio与video(来源havlenapetr的项目)

video/jni/surface.cpp(注意目录结构)


[cpp] view plain copy print ?
  1. /*
  2. *Copyright(C)2009TheAndroidOpenSourceProject
  3. *
  4. *LicensedundertheApacheLicense,Version2.0(the"License");
  5. *youmaynotusethisfileexceptincompliancewiththeLicense.
  6. *YoumayobtainacopyoftheLicenseat
  7. *
  8. *http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. *Unlessrequiredbyapplicablelaworagreedtoinwriting,software
  11. *distributedundertheLicenseisdistributedonan"ASIS"BASIS,
  12. *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
  13. *SeetheLicenseforthespecificlanguagegoverningpermissionsand
  14. *limitationsundertheLicense.
  15. */
  16. #include<android/surface.h>
  17. #include<surfaceflinger/Surface.h>
  18. #include<utils/Log.h>
  19. #include<SkBitmap.h>
  20. #include<SkCanvas.h>
  21. #defineTAG"SurfaceWrapper"
  22. usingnamespaceandroid;
  23. staticSurface*sSurface;
  24. staticSkBitmapsBitmapClient;
  25. staticSkBitmapsBitmapSurface;
  26. staticSurface*getNativeSurface(JNIEnv*env,jobjectjsurface){
  27. jclassclazz=env->FindClass("android/view/Surface");
  28. jfieldIDfield_surface=env->GetFieldID(clazz,"mNativeSurface","I");
  29. if(field_surface==NULL){
  30. returnNULL;
  31. }
  32. return(Surface*)env->GetIntField(jsurface,field_surface);
  33. }
  34. staticintinitBitmap(SkBitmap*bitmap,intformat,intwidth,intheight,boolallocPixels){
  35. switch(format){
  36. casePIXEL_FORMAT_RGBA_8888:
  37. bitmap->setConfig(SkBitmap::kARGB_8888_Config,width,height);
  38. break;
  39. casePIXEL_FORMAT_RGBA_4444:
  40. bitmap->setConfig(SkBitmap::kARGB_4444_Config,width,height);
  41. break;
  42. casePIXEL_FORMAT_RGB_565:
  43. bitmap->setConfig(SkBitmap::kRGB_565_Config,width,height);
  44. break;
  45. casePIXEL_FORMAT_A_8:
  46. bitmap->setConfig(SkBitmap::kA8_Config,width,height);
  47. break;
  48. default:
  49. bitmap->setConfig(SkBitmap::kNo_Config,width,height);
  50. break;
  51. }
  52. if(allocPixels){
  53. bitmap->setIsOpaque(true);
  54. //--allocarrayofpixels
  55. if(!bitmap->allocPixels()){
  56. return-1;
  57. }
  58. }
  59. return0;
  60. }
  61. intAndroidSurface_register(JNIEnv*env,jobjectjsurface){
  62. __android_log_print(ANDROID_LOG_INFO,TAG,"registeringvideosurface");
  63. sSurface=getNativeSurface(env,jsurface);
  64. if(sSurface==NULL){
  65. returnANDROID_SURFACE_RESULT_JNI_EXCEPTION;
  66. }
  67. __android_log_print(ANDROID_LOG_INFO,TAG,"registered");
  68. returnANDROID_SURFACE_RESULT_SUCCESS;
  69. }
  70. intAndroidSurface_getPixels(intwidth,intheight,void**pixels){
  71. __android_log_print(ANDROID_LOG_INFO,TAG,"gettingsurface'spixels%ix%i",width,height);
  72. if(sSurface==NULL){
  73. returnANDROID_SURFACE_RESULT_JNI_EXCEPTION;
  74. }
  75. if(initBitmap(&sBitmapClient,PIXEL_FORMAT_RGB_565,width,height,true)<0){
  76. returnANDROID_SURFACE_RESULT_COULDNT_INIT_BITMAP_CLIENT;
  77. }
  78. *pixels=sBitmapClient.getPixels();
  79. __android_log_print(ANDROID_LOG_INFO,TAG,"getted");
  80. returnANDROID_SURFACE_RESULT_SUCCESS;
  81. }
  82. staticvoiddoUpdateSurface(){
  83. SkCanvascanvas(sBitmapSurface);
  84. SkRectsurface_sBitmapClient;
  85. SkRectsurface_sBitmapSurface;
  86. SkMatrixmatrix;
  87. surface_sBitmapSurface.set(0,0,sBitmapSurface.width(),sBitmapSurface.height());
  88. surface_sBitmapClient.set(0,0,sBitmapClient.width(),sBitmapClient.height());
  89. matrix.setRectToRect(surface_sBitmapClient,surface_sBitmapSurface,SkMatrix::kFill_ScaleToFit);
  90. canvas.drawBitmapMatrix(sBitmapClient,matrix);
  91. }
  92. staticintprepareSurfaceBitmap(Surface::SurfaceInfo*info){
  93. if(initBitmap(&sBitmapSurface,info->format,info->w,info->h,false)<0){
  94. return-1;
  95. }
  96. sBitmapSurface.setPixels(info->bits);
  97. return0;
  98. }
  99. intAndroidSurface_updateSurface(){
  100. staticSurface::SurfaceInfosurfaceInfo;
  101. if(sSurface==NULL){
  102. returnANDROID_SURFACE_RESULT_JNI_EXCEPTION;
  103. }
  104. if(!Surface::isValid(sSurface)){
  105. returnANDROID_SURFACE_RESULT_NOT_VALID;
  106. }
  107. if(sSurface->lock(&surfaceInfo)<0){
  108. returnANDROID_SURFACE_RESULT_COULDNT_LOCK;
  109. }
  110. if(prepareSurfaceBitmap(&surfaceInfo)<0){
  111. returnANDROID_SURFACE_RESULT_COULDNT_INIT_BITMAP_SURFACE;
  112. }
  113. doUpdateSurface();
  114. if(sSurface->unlockAndPost()<0){
  115. returnANDROID_SURFACE_RESULT_COULDNT_UNLOCK_AND_POST;
  116. }
  117. returnANDROID_SURFACE_RESULT_SUCCESS;
  118. }
  119. intAndroidSurface_unregister(){
  120. __android_log_print(ANDROID_LOG_INFO,TAG,"unregisteringvideosurface");
  121. __android_log_print(ANDROID_LOG_INFO,TAG,"unregistered");
  122. returnANDROID_SURFACE_RESULT_SUCCESS;
  123. }


video/jni/Android.mk (注意目录结构)

[cpp] view plain copy print ?
  1. LOCAL_PATH:=$(callmy-dir)
  2. include$(CLEAR_VARS)
  3. #oursourcefiles
  4. #
  5. LOCAL_SRC_FILES:=\
  6. surface.cpp
  7. LOCAL_SHARED_LIBRARIES:=\
  8. libskia\
  9. libsurfaceflinger_client\
  10. libutils\
  11. liblog
  12. LOCAL_C_INCLUDES+=\
  13. $(JNI_H_INCLUDE)\
  14. external/skia/src/core\
  15. external/skia/include/core\
  16. frameworks/base/include\
  17. frameworks/base/native/include
  18. #Optionaltagwouldmeanitdoesn'tgetinstalledbydefault
  19. LOCAL_MODULE_TAGS:=optional
  20. LOCAL_PRELINK_MODULE:=false
  21. LOCAL_MODULE:=libjnivideo
  22. include$(BUILD_SHARED_LIBRARY)

/audio/jni/audiotrack.cpp(注意目录结构)

[cpp] view plain copy print ?
  1. /*
  2. *Copyright(C)2009TheAndroidOpenSourceProject
  3. *
  4. *LicensedundertheApacheLicense,Version2.0(the"License");
  5. *youmaynotusethisfileexceptincompliancewiththeLicense.
  6. *YoumayobtainacopyoftheLicenseat
  7. *
  8. *http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. *Unlessrequiredbyapplicablelaworagreedtoinwriting,software
  11. *distributedundertheLicenseisdistributedonan"ASIS"BASIS,
  12. *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
  13. *SeetheLicenseforthespecificlanguagegoverningpermissionsand
  14. *limitationsundertheLicense.
  15. */
  16. #include<android/audiotrack.h>
  17. #include<utils/Log.h>
  18. #include<media/AudioTrack.h>
  19. #include<media/AudioSystem.h>
  20. #include<utils/Errors.h>
  21. #include<binder/MemoryHeapBase.h>
  22. #include<binder/MemoryBase.h>
  23. #defineTAG"AudioTrackWrapper"
  24. usingnamespaceandroid;
  25. //structaudiotrack_fields_t{
  26. staticAudioTrack*track;
  27. //sp<MemoryHeapBase>memHeap;
  28. //sp<MemoryBase>memBase;
  29. //};
  30. //staticstructaudiotrack_fields_taudio;
  31. staticAudioTrack*getNativeAudioTrack(JNIEnv*env,jobjectjaudioTrack){
  32. jclassclazz=env->FindClass("android/media/AudioTrack");
  33. jfieldIDfield_track=env->GetFieldID(clazz,"mNativeTrackInJavaObj","I");
  34. if(field_track==NULL){
  35. returnNULL;
  36. }
  37. return(AudioTrack*)env->GetIntField(jaudioTrack,field_track);
  38. }
  39. /*
  40. staticboolallocSharedMem(intsizeInBytes){
  41. memHeap=newMemoryHeapBase(sizeInBytes);
  42. if(memHeap->getHeapID()<0){
  43. returnfalse;
  44. }
  45. memBase=newMemoryBase(memHeap,0,sizeInBytes);
  46. returntrue;
  47. }
  48. */
  49. intAndroidAudioTrack_register(){
  50. __android_log_print(ANDROID_LOG_INFO,TAG,"registeringaudiotrack");
  51. track=newAudioTrack();
  52. if(track==NULL){
  53. returnANDROID_AUDIOTRACK_RESULT_JNI_EXCEPTION;
  54. }
  55. __android_log_print(ANDROID_LOG_INFO,TAG,"registered");
  56. returnANDROID_AUDIOTRACK_RESULT_SUCCESS;
  57. }
  58. intAndroidAudioTrack_start(){
  59. //__android_log_print(ANDROID_LOG_INFO,TAG,"startingaudiotrack");
  60. if(track==NULL){
  61. returnANDROID_AUDIOTRACK_RESULT_ALLOCATION_FAILED;
  62. }
  63. track->start();
  64. returnANDROID_AUDIOTRACK_RESULT_SUCCESS;
  65. }
  66. intAndroidAudioTrack_set(intstreamType,
  67. uint32_tsampleRate,
  68. intformat,
  69. intchannels){
  70. if(track==NULL){
  71. returnANDROID_AUDIOTRACK_RESULT_ALLOCATION_FAILED;
  72. }
  73. __android_log_print(ANDROID_LOG_INFO,TAG,"settingaudiotrack");
  74. status_tret=track->set(streamType,
  75. sampleRate,
  76. format,
  77. channels,
  78. 0,
  79. 0,
  80. 0,
  81. 0,
  82. false);
  83. if(ret!=NO_ERROR){
  84. returnANDROID_AUDIOTRACK_RESULT_ERRNO;
  85. }
  86. returnANDROID_AUDIOTRACK_RESULT_SUCCESS;
  87. }
  88. intAndroidAudioTrack_flush(){
  89. if(track==NULL){
  90. returnANDROID_AUDIOTRACK_RESULT_ALLOCATION_FAILED;
  91. }
  92. track->flush();
  93. returnANDROID_AUDIOTRACK_RESULT_SUCCESS;
  94. }
  95. intAndroidAudioTrack_stop(){
  96. if(track==NULL){
  97. returnANDROID_AUDIOTRACK_RESULT_ALLOCATION_FAILED;
  98. }
  99. track->stop();
  100. returnANDROID_AUDIOTRACK_RESULT_SUCCESS;
  101. }
  102. intAndroidAudioTrack_reload(){
  103. if(track==NULL){
  104. returnANDROID_AUDIOTRACK_RESULT_ALLOCATION_FAILED;
  105. }
  106. if(track->reload()!=NO_ERROR){
  107. returnANDROID_AUDIOTRACK_RESULT_ERRNO;
  108. }
  109. returnANDROID_AUDIOTRACK_RESULT_SUCCESS;
  110. }
  111. intAndroidAudioTrack_unregister(){
  112. __android_log_print(ANDROID_LOG_INFO,TAG,"unregisteringaudiotrack");
  113. if(!track->stopped()){
  114. track->stop();
  115. }
  116. //memBase.clear();
  117. //memHeap.clear();
  118. free(track);
  119. //track=NULL;
  120. __android_log_print(ANDROID_LOG_INFO,TAG,"unregistered");
  121. returnANDROID_AUDIOTRACK_RESULT_SUCCESS;
  122. }
  123. intAndroidAudioTrack_write(void*buffer,intbuffer_size){
  124. //givethedatatothenativeAudioTrackobject(thedatastartsattheoffset)
  125. ssize_twritten=0;
  126. //regularwrite()orcopythedatatotheAudioTrack'ssharedmemory?
  127. if(track->sharedBuffer()==0){
  128. written=track->write(buffer,buffer_size);
  129. }else{
  130. //writingtosharedmemory,checkforcapacity
  131. if((size_t)buffer_size>track->sharedBuffer()->size()){
  132. __android_log_print(ANDROID_LOG_INFO,TAG,"buffersizewastoosmall");
  133. buffer_size=track->sharedBuffer()->size();
  134. }
  135. memcpy(track->sharedBuffer()->pointer(),buffer,buffer_size);
  136. written=buffer_size;
  137. }
  138. returnwritten;
  139. }

/audio/jni/Android.mk(注意目录结构)

[cpp] view plain copy print ?
  1. LOCAL_PATH:=$(callmy-dir)
  2. include$(CLEAR_VARS)
  3. #oursourcefiles
  4. #
  5. LOCAL_SRC_FILES:=\
  6. audiotrack.cpp
  7. LOCAL_SHARED_LIBRARIES:=\
  8. libbinder\
  9. libmedia\
  10. libutils\
  11. liblog
  12. LOCAL_C_INCLUDES+=\
  13. $(JNI_H_INCLUDE)\
  14. frameworks/base/include\
  15. frameworks/base/native/include
  16. #Optionaltagwouldmeanitdoesn'tgetinstalledbydefault
  17. LOCAL_MODULE_TAGS:=optional
  18. LOCAL_PRELINK_MODULE:=false
  19. LOCAL_MODULE:=libjniaudio
  20. include$(BUILD_SHARED_LIBRARY)

更多相关文章

  1. Android版本检测\自动更新 (转的别人的)
  2. android 编译内核
  3. Android(安卓)日常报错之 Android(安卓)dependency 'com.android
  4. 开机不锁屏
  5. Android(安卓)Studio : Rendering Problems
  6. Android最新版本号与API级别对应关系
  7. NDK各版本下载
  8. android studio SDK版本的调节
  9. compileSdkVersion、buildToolsVersion、targetSdkVersion 、Fai

随机推荐

  1. android:hintText与android:inputType详
  2. android官方下载链接最新版 (Windows版本
  3. android计时器chronometer的基本使用
  4. Android(安卓)ShapeDrawable 虚线 的显示
  5. Android(安卓)浅谈AsyncTask异步
  6. Android - 4种基本布局
  7. Android(安卓)NDK进入发展
  8. Android动画之RotateAnimation使用
  9. 我的android 第7天 - 控件美化 和 编码性
  10. 模拟器上网