闲来无事,学习下手机直播相关的知识。其中ffmpeg是必不可少的,下面简单介绍下如何在Android Studio上搭建一个可用的ffmpeg开发环境。
0.前置条件
首先你要准备以下环境:
Android Studio:我用的是2.3.3版本的,然后尝试编译一个非常一般的apk,并可以编译通过
其他的Android Build Tools:CMake、LLDB、NDK,这些都可以在SDK Manager里面下载到,如下图
编译出的ffmpeg的so文件:如何编译ffmpeg网上教程很多,这里不再赘述了,我们需要编译出来的include、libavcodec-57.so、libavdevice-57.so、libavfilter-6.so、libavformat-57.so、libavutil-55.so、libswresample-2.so、libswscale-4.so
1.新建工程,勾选C++ Support,然后无脑下一步,完成(有一步会有两个复选框和一个下拉框,下拉框是编译工具、复选框一个是C++异常处理,一个是运行时支持)
新建出来的工程应该是可以直接运行的,其中已经包含了C++代码和Jni调用,大家可以先看一下。
2.添加ffmpeg到Android工程,在项目根目录中新建ffmpeg文件夹,将我们编译好的so文件按照如下文件结构复制进去
3.修改CMakeLists.txt,添加ffmpeg模块
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
set(FFMPEG_HOME ${CMAKE_SOURCE_DIR}/../ffmpeg)
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/native-lib.cpp )
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
# Import ffmpeg part
add_library( avcodec
SHARED
IMPORTED )
set_target_properties( avcodec
PROPERTIES IMPORTED_LOCATION
${FFMPEG_HOME}/libs/${ANDROID_ABI}/libavcodec-57.so )
add_library( avdevice
SHARED
IMPORTED )
set_target_properties( avdevice
PROPERTIES IMPORTED_LOCATION
${FFMPEG_HOME}/libs/${ANDROID_ABI}/libavdevice-57.so )
add_library( avfilter
SHARED
IMPORTED )
set_target_properties( avfilter
PROPERTIES IMPORTED_LOCATION
${FFMPEG_HOME}/libs/${ANDROID_ABI}/libavfilter-6.so )
add_library( avformat
SHARED
IMPORTED )
set_target_properties( avformat
PROPERTIES IMPORTED_LOCATION
${FFMPEG_HOME}/libs/${ANDROID_ABI}/libavformat-57.so )
add_library( avutil
SHARED
IMPORTED )
set_target_properties( avutil
PROPERTIES IMPORTED_LOCATION
${FFMPEG_HOME}/libs/${ANDROID_ABI}/libavutil-55.so )
add_library( swresample
SHARED
IMPORTED )
set_target_properties( swresample
PROPERTIES IMPORTED_LOCATION
${FFMPEG_HOME}/libs/${ANDROID_ABI}/libswresample-2.so )
add_library( swscale
SHARED
IMPORTED )
set_target_properties( swscale
PROPERTIES IMPORTED_LOCATION
${FFMPEG_HOME}/libs/${ANDROID_ABI}/libswscale-4.so )
include_directories(${FFMPEG_HOME}/include/)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
avcodec
avdevice
avfilter
avformat
avutil
swresample
swscale
# Links the target library to the log library
# included in the NDK.
${log-lib} )
在MainActivity中添加一个native方法string2FromJNI,然后点击左侧红色感叹号,让IDE自动生成C++对应方法,生成后会是多出这部分代码
JNIEXPORT jstring JNICALL
Java_coding_yu_helloffmpeg_MainActivity_string2FromJNI(JNIEnv *env, jobject instance) {
return env->NewStringUTF(result);
}
然后我们稍加修改,返回ffmpeg的编译信息,改成如下样子
#include "libavcodec/avcodec.h"
extern "C"
JNIEXPORT jstring JNICALL
Java_coding_yu_helloffmpeg_MainActivity_string2FromJNI(JNIEnv *env, jobject instance) {
char info[10000] = {0};
sprintf(info, "%s\n", avcodec_configuration());
return env->NewStringUTF(info);
}
问题1:提示不能解决mips的依赖
解决方法:在gradle的defaultConfig中添加ndk平台指定
ndk {
abiFilters "armeabi"
}
原因分析:因为当时编译的时候只编译了arm的ffmpeg二进制库,因此咱们只创建了armeabi文件夹,详情在第二步。编译器为什么会去找其他平台的呢?因为在CMakeLists.txt文件中有个变量是这样写的 /libs/${ANDROID_ABI}/libswscale-4.so,详情见第三步。因此我们只要指定apk的abi平台即可。
问题2:loadLibrary失败,Link不到 avcodec-57.so
解决方法:在app/src/main下新建jniLibs,将armeabi复制进去
原因分析:不是工程下已经导入了ffmpeg的so和include了么?为什么找不到?咱们在第二步导入的是编译用的,apk打包并不会打进去,Studio默认会把jniLibs的so打入apk,加上可以了(和集成第三方API的so一致)
问题3:avcodec_configuration方法未定义、string2FromJNI方法未实现
解决方法:添加extern “C”标识,修改后效果如下
#include
#include
extern "C" {
#include "libavcodec/avcodec.h"
}
extern "C"
JNIEXPORT jstring JNICALL
Java_coding_yu_helloffmpeg_MainActivity_string2FromJNI(JNIEnv *env, jobject instance) {
char info[10000] = {0};
sprintf(info, "%s\n", avcodec_configuration());
return env->NewStringUTF(info);
}
extern "C"
JNIEXPORT jstring JNICALL
Java_coding_yu_helloffmpeg_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
这是项目地址:https://github.com/yuruxuan/HelloFFMpeg