Android Studio通过cmake创建FFmpeg项目

在上一篇博客《FFmpeg(3.3.2)移植Android平台》 中介绍了FFmpeg移植到Android平台上来,通过博客我们最终得到了Android开发FFmpeg所需要的动态库(.so)和库文件(.h),博客结尾也上传了一个Android集成FFmpeg的demo,但是此demo是在eclipse下开发的,因为现在Android开发都是用的Android Studio了,所以就来讲讲在AS中怎么搭建FFmpeg开发环境吧。

一:首先下载需要的组件CMake和LLDB,前者是构建工具,后者是调试工具,注意这里我没有用SDK下载NDK,我喜欢单独下载NDK,后面导入。

二:创建支持C++的AS项目

新建工程,并勾选“C++ Support”,如图:

后面默认直接下一步,直到创建好工程。

三:此时工程编译出错,因为还没有导入NDK编译目录(注:最好用最新的NDK来构建,我原来的是10e,导致cmake构建失败,升级NDK就行了,下载地址:https://developer.android.com/ndk/downloads/index.html)我这里用的是现在最新14b版本。

下载后,配置环境变量,并为工程导入NDK编译目录:

Window配置:

ANDROID_NDK:E:\Android\android-ndk-r14b

Path:%ANDROID_NDK%

项目配置:

配置好后,再构建项目就可以了,下面是构建好的项目:

运行项目,效果如下就证明我们的C/C++项目创建成功了

四:AS默认C/C++项目介绍

1):c文件所在目录默认为cpp,并有一个简单的返回字符串的方法

2):我们看build.gradle里面

其中第一个cmake里面可以配置一些需要的参数,这里暂时就默认,不用更改;第二个cmakd里面导入了要参与构建的CMakeLists.txt脚本,这个脚本里面就是我们需要改写的,如:添加自己的c文件和系统库以及第三方库等。

3):CMakeLists.txt文件简析

这是根据功能推敲的,如有不对的,还请指正,哈哈。

4):生成的libxxxx.so位置

就在这里了,不用移动动态库位置,系统会自动调用这里面的。

5):Java调用

好的,默认的项目基本介绍完了,应该对AS中的c编译过程大概清楚了,接下来改造成我们自己的项目。

五:搭建FFmpeg目录

1):删除main下面的cpp目录和文件,创建jni目录(个人喜欢,其实在cpp目录里面也可以)

现在看着是不是熟悉又清爽了。

2):导入我们的FFmpeg库和头文件

因为只编译了arm平台下的FFmpeg,所以这里就只创建armeabi了,这样FFmpeg需要的库和头文件就导入到了项目中。

3):在activity同级目录下(这里就不新建包了,原理一样)添加我们自己的类,FFmpegPlayer.java

[java] view plain copy

  1. package com.ywl5320.ffmpegas;  
  2.   
  3. /** 
  4.  * Created by ywl on 2017-7-14. 
  5.  */  
  6.   
  7. public class FFmpegPlayer {  
  8.   
  9.     static  
  10.     {  
  11.         System.loadLibrary("avutil-55");  
  12.         System.loadLibrary("swresample-2");  
  13.         System.loadLibrary("avcodec-57");  
  14.         System.loadLibrary("avformat-57");  
  15.         System.loadLibrary("swscale-4");  
  16.         System.loadLibrary("postproc-54");  
  17.         System.loadLibrary("avfilter-6");  
  18.         System.loadLibrary("avdevice-57");  
  19.     }  
  20.     public native void playMyMedia(String url);  
  21.   
  22. }  

首先是导入FFmpeg的动态库,然后自定义一个native方法来调用c代码。接下来生成xxx.c文件,AS挺智能的,把鼠标移到我们的native方法上面,然后 “alt+回车” 就能在jni中生成包含我们native方法的.c文件,文件名可以改一下,我这里改成的是play.c

这样就生成了我们需要的.c文件,不需要我们在命令行用javah来生成.h再写.c文件了,原来红色的native方法也变成

灰色的了:

4)接下来重点来了,配置CMakeLists.txt文件

4.1:为我们自己的c文件生成的动态库命名,这里就命名为wlffmpeg,把默认的改成如下:

[html] view plain copy

  1. add_library( # Sets the name of the library.  
  2.              wlffmpeg  
  3.   
  4.              # Sets the library as a shared library.  
  5.              SHARED  
  6.   
  7.              # Provides a relative path to your source file(s).  
  8.              src/main/jni/player.c )  

4.2:添加FFmpeg动态库:

[html] view plain copy

  1. #添加libavcodec-57.so  
  2. add_library( avcodec-57  
  3.              SHARED  
  4.              IMPORTED)  
  5. set_target_properties( avcodec-57  
  6.                        PROPERTIES IMPORTED_LOCATION  
  7.                        ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libavcodec-57.so)  
  8.                          
  9. #添加libavdevice-57.so                    
  10. add_library( avdevice-57  
  11.              SHARED  
  12.              IMPORTED)  
  13. set_target_properties( avdevice-57  
  14.                        PROPERTIES IMPORTED_LOCATION  
  15.                        ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libavdevice-57.so)  
  16.   
  17. add_library( avfilter-6  
  18.              SHARED  
  19.              IMPORTED)  
  20. set_target_properties( avfilter-6  
  21.                        PROPERTIES IMPORTED_LOCATION  
  22.                        ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libavfilter-6.so)  
  23.   
  24. add_library( avformat-57  
  25.              SHARED  
  26.              IMPORTED)  
  27. set_target_properties( avformat-57  
  28.                        PROPERTIES IMPORTED_LOCATION  
  29.                        ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libavformat-57.so)  
  30.   
  31. add_library( avutil-55  
  32.              SHARED  
  33.              IMPORTED)  
  34. set_target_properties( avutil-55  
  35.                        PROPERTIES IMPORTED_LOCATION  
  36.                        ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libavutil-55.so)  
  37.   
  38. add_library( swresample-2  
  39.              SHARED  
  40.              IMPORTED)  
  41. set_target_properties( swresample-2  
  42.                        PROPERTIES IMPORTED_LOCATION  
  43.                        ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libswresample-2.so)  
  44.   
  45. add_library( swscale-4  
  46.              SHARED  
  47.              IMPORTED)  
  48. set_target_properties( swscale-4  
  49.                        PROPERTIES IMPORTED_LOCATION  
  50.                        ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libswscale-4.so)  
  51.                          
  52. add_library( postproc-54  
  53.              SHARED  
  54.              IMPORTED)  
  55. set_target_properties( postproc-54  
  56.                        PROPERTIES IMPORTED_LOCATION  
  57.                        ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libpostproc-54.so)  

简单介绍一下如图:

4.3:添加了FFmpeg动态库,最后还需要连接到系统中:

在此之前还需要导入FFmpeg的头文件才行:

[html] view plain copy

  1. include_directories(src/main/jni/ffmpeg/include)  

然后再连接FFmpeg动态库

[html] view plain copy

  1. target_link_libraries( # Specifies the target library.  
  2.   
  3.                        wlffmpeg  
  4.                        avcodec-57  
  5.                        avdevice-57  
  6.                        avfilter-6  
  7.                        avformat-57  
  8.                        avutil-55  
  9.                        swresample-2  
  10.                        swscale-4  
  11.                        postproc-54  
  12.   
  13.                        # Links the target library to the log library  
  14.                        # included in the NDK.  
  15.                        ${log-lib} )  

4.4:现在还不能编译,现在编译会报“找不到mip64或其他cpu类型的错误”,因为我们这里只有arm的值,此时需要在build.gradle中配置编译的cup的类型,这里就只配置arm的:

[html] view plain copy

  1. externalNativeBuild {  
  2.             cmake {  
  3.                 cppFlags ""  
  4.             }  
  5.             ndk {  
  6.                 abiFilters "armeabi"  
  7.             }  
  8.         }  

4.5:此时也还不能编译,会报“找不到FFmpeg的库的错误”,因为我们还需要给系统指定jniLibs的目录:

[html] view plain copy

  1. sourceSets {  
  2.             main {  
  3.                 jniLibs.srcDirs = ['src/main/jni/ffmpeg']  
  4.             }  
  5.         }  

4.6:至此我们就可以愉快的编译代码了

完整的CMakeLists.txt

[html] view plain copy

  1. # For more information about using CMake with Android Studio, read the  
  2. # documentation: https://d.android.com/studio/projects/add-native-code.html  
  3.   
  4. # Sets the minimum version of CMake required to build the native library.  
  5.   
  6. cmake_minimum_required(VERSION 3.4.1)  
  7.   
  8. # Creates and names a library, sets it as either STATIC  
  9. # or SHARED, and provides the relative paths to its source code.  
  10. # You can define multiple libraries, and CMake builds them for you.  
  11. # Gradle automatically packages shared libraries with your APK.  
  12.   
  13. add_library( # Sets the name of the library.  
  14.              wlffmpeg  
  15.   
  16.              # Sets the library as a shared library.  
  17.              SHARED  
  18.   
  19.              # Provides a relative path to your source file(s).  
  20.              src/main/jni/player.c )  
  21.   
  22.   
  23. #添加libavcodec-57.so  
  24. add_library( avcodec-57  
  25.              SHARED  
  26.              IMPORTED)  
  27. set_target_properties( avcodec-57  
  28.                        PROPERTIES IMPORTED_LOCATION  
  29.                        ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libavcodec-57.so)  
  30.   
  31.   
  32. #添加libavdevice-57.so  
  33. add_library( avdevice-57  
  34.              SHARED  
  35.              IMPORTED)  
  36. set_target_properties( avdevice-57  
  37.                        PROPERTIES IMPORTED_LOCATION  
  38.                        ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libavdevice-57.so)  
  39.   
  40. add_library( avfilter-6  
  41.              SHARED  
  42.              IMPORTED)  
  43. set_target_properties( avfilter-6  
  44.                        PROPERTIES IMPORTED_LOCATION  
  45.                        ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libavfilter-6.so)  
  46.   
  47. add_library( avformat-57  
  48.              SHARED  
  49.              IMPORTED)  
  50. set_target_properties( avformat-57  
  51.                        PROPERTIES IMPORTED_LOCATION  
  52.                        ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libavformat-57.so)  
  53.   
  54. add_library( avutil-55  
  55.              SHARED  
  56.              IMPORTED)  
  57. set_target_properties( avutil-55  
  58.                        PROPERTIES IMPORTED_LOCATION  
  59.                        ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libavutil-55.so)  
  60.   
  61. add_library( swresample-2  
  62.              SHARED  
  63.              IMPORTED)  
  64. set_target_properties( swresample-2  
  65.                        PROPERTIES IMPORTED_LOCATION  
  66.                        ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libswresample-2.so)  
  67.   
  68. add_library( swscale-4  
  69.              SHARED  
  70.              IMPORTED)  
  71. set_target_properties( swscale-4  
  72.                        PROPERTIES IMPORTED_LOCATION  
  73.                        ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libswscale-4.so)  
  74.   
  75. add_library( postproc-54  
  76.              SHARED  
  77.              IMPORTED)  
  78. set_target_properties( postproc-54  
  79.                        PROPERTIES IMPORTED_LOCATION  
  80.                        ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libpostproc-54.so)  
  81.   
  82.   
  83. # Searches for a specified prebuilt library and stores the path as a  
  84. # variable. Because CMake includes system libraries in the search path by  
  85. # default, you only need to specify the name of the public NDK library  
  86. # you want to add. CMake verifies that the library exists before  
  87. # completing its build.  
  88.   
  89. find_library( # Sets the name of the path variable.  
  90.               log-lib  
  91.   
  92.               # Specifies the name of the NDK library that  
  93.               # you want CMake to locate.  
  94.               log )  
  95.   
  96. # Specifies libraries CMake should link to your target library. You  
  97. # can link multiple libraries, such as libraries you define in this  
  98. # build script, prebuilt third-party libraries, or system libraries.  
  99.   
  100. include_directories(src/main/jni/ffmpeg/include)  
  101.   
  102. target_link_libraries( # Specifies the target library.  
  103.   
  104.                        wlffmpeg  
  105.                        avcodec-57  
  106.                        avdevice-57  
  107.                        avfilter-6  
  108.                        avformat-57  
  109.                        avutil-55  
  110.                        swresample-2  
  111.                        swscale-4  
  112.                        postproc-54  
  113.   
  114.                        # Links the target library to the log library  
  115.                        # included in the NDK.  
  116.                        ${log-lib} )  


 

完整的build.gradle

[html] view plain copy

  1. apply plugin: 'com.android.application'  
  2.   
  3. android {  
  4.     compileSdkVersion 25  
  5.     buildToolsVersion "25.0.3"  
  6.     defaultConfig {  
  7.         applicationId "com.ywl5320.ffmpegas"  
  8.         minSdkVersion 14  
  9.         targetSdkVersion 25  
  10.         versionCode 1  
  11.         versionName "1.0"  
  12.         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"  
  13.         externalNativeBuild {  
  14.             cmake {  
  15.                 cppFlags ""  
  16.             }  
  17.             ndk {  
  18.                 abiFilters "armeabi"  
  19.             }  
  20.         }  
  21.   
  22.         sourceSets {  
  23.             main {  
  24.                 jniLibs.srcDirs = ['src/main/jni/ffmpeg']  
  25.             }  
  26.         }  
  27.   
  28.     }  
  29.     buildTypes {  
  30.         release {  
  31.             minifyEnabled false  
  32.             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  
  33.         }  
  34.     }  
  35.     externalNativeBuild {  
  36.         cmake {  
  37.             path "CMakeLists.txt"  
  38.         }  
  39.     }  
  40. }  
  41.   
  42. dependencies {  
  43.     compile fileTree(dir: 'libs', include: ['*.jar'])  
  44.     androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {  
  45.         exclude group: 'com.android.support', module: 'support-annotations'  
  46.     })  
  47.     compile 'com.android.support:appcompat-v7:25.3.1'  
  48.     compile 'com.android.support.constraint:constraint-layout:1.0.0-beta5'  
  49.     testCompile 'junit:junit:4.12'  
  50. }  

编译后我们运行一下apk吧:

哈哈,there is nothing !当然了,因为我们在play.c里面还没有写什么代码,也还没有调用呢。

六:测试FFmpeg,调用里面的简单api,这里也查看其编码器的信息(本来想播放一段视频的声音或者画面,但是还需要集成SDL,所以就下次吧)。

player.c

[cpp] view plain copy

  1. #include <jni.h>  
  2.   
  3. //ffmpeg库  
  4. #include "libavformat/avformat.h"  
  5.   
  6. //打印日志  
  7. #include <android/log.h>  
  8. #define LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO,"ywl5320",FORMAT,##__VA_ARGS__);  
  9. #define LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,"ywl5320",FORMAT,##__VA_ARGS__);  
  10.   
  11. JNIEXPORT void JNICALL  
  12. Java_com_ywl5320_ffmpegas_FFmpegPlayer_playMyMedia(JNIEnv *env, jobject instance, jstring url_) {  
  13.     const char *url = (*env)->GetStringUTFChars(env, url_, 0);  
  14.   
  15.     LOGI("url:%s", url);  
  16.   
  17.     av_register_all();  
  18.     AVCodec *c_temp = av_codec_next(NULL);  
  19.     while (c_temp != NULL)  
  20.     {  
  21.         switch (c_temp->type)  
  22.         {  
  23.             case AVMEDIA_TYPE_VIDEO:  
  24.                 LOGI("[Video]:%s", c_temp->name);  
  25.                 break;  
  26.             case AVMEDIA_TYPE_AUDIO:  
  27.                 LOGI("[Audio]:%s", c_temp->name);  
  28.                 break;  
  29.             default:  
  30.                 LOGI("[Other]:%s", c_temp->name);  
  31.                 break;  
  32.         }  
  33.         c_temp = c_temp->next;  
  34.     }  
  35.     // TODO  
  36.   
  37.     (*env)->ReleaseStringUTFChars(env, url_, url);  
  38. }  

调用代码:MainActivity.java

[java] view plain copy

  1. package com.ywl5320.ffmpegas;  
  2.   
  3. import android.support.v7.app.AppCompatActivity;  
  4. import android.os.Bundle;  
  5. import android.widget.TextView;  
  6.   
  7. public class MainActivity extends AppCompatActivity {  
  8.   
  9.     FFmpegPlayer fFmpegPlayer;  
  10.   
  11.     @Override  
  12.     protected void onCreate(Bundle savedInstanceState) {  
  13.         super.onCreate(savedInstanceState);  
  14.         setContentView(R.layout.activity_main);  
  15.         fFmpegPlayer = new FFmpegPlayer();  
  16.         fFmpegPlayer.playMyMedia("http://blog.csdn.net/ywl5320");  
  17.     }  
  18. }  

别忘了在FFmpegPlayer.java中添加我们自己的动态库(libwlffmpeg.so)哦:

[java] view plain copy

  1. package com.ywl5320.ffmpegas;  
  2.   
  3. /** 
  4.  * Created by ywl on 2017-7-14. 
  5.  */  
  6.   
  7. public class FFmpegPlayer {  
  8.   
  9.     static  
  10.     {  
  11.         System.loadLibrary("avutil-55");  
  12.         System.loadLibrary("swresample-2");  
  13.         System.loadLibrary("avcodec-57");  
  14.         System.loadLibrary("avformat-57");  
  15.         System.loadLibrary("swscale-4");  
  16.         System.loadLibrary("postproc-54");  
  17.         System.loadLibrary("avfilter-6");  
  18.         System.loadLibrary("avdevice-57");  
  19.         System.loadLibrary("wlffmpeg");  
  20.     }  
  21.     public native void playMyMedia(String url);  
  22.   
  23. }  

其中libwlffmpeg.so的生成位置在这里:

因为只是打印了FFmpeg的编解码器信息,所以在AS的log日志中可以看到FFmpeg的信息了:


看到了我们的信息,说明FFmpeg已经在Android Studio上面跑起了,它能跑多快,就看各位大神的发挥了哈,搞定收工!!

且慢,还是总结一下:授人以鱼不如授人以渔,通过本次对FFmpeg的集成,基本了解了AS中用CMake来构建c/c++项目的过程了,以后遇到其他的库(c/c++优秀的库太多了)就可以迎刃而解了。最后附上github下载地址,里面有eclipse和AS两个版本的,仅供大家参考,eclipse版本的没有写博客,创建过程和博客《Android编译SDL2和demo展示(2.0.5)》中SDL一样,相信大家没问题的。

GitHub下载地址:https://github.com/wanliyang1990/FFmpeg-Android

猜你喜欢

转载自blog.csdn.net/weixin_37897683/article/details/82586395