使用Android Studio编写第一个ffmpeg程序
所需材料
1、android studio 2.3
2、android-ndk-r13
3、ffmpeg编译结果(include,libs)
本文实例中需要使用到编译的ffmpeg头文件和静态库。
本文使用Android Studio2.3 来开发,主要是考虑到Android Studio对NDK开发已经支持得很好了。
Android Sutdio 既可以支持ndk-build构建,又支持新的CMake构建,而且代码提示、单步调试等功能也大大提高了开发效率。
1、创建一个NDK工程
打开Android Studio,新建一个工程,勾选“Include C++support”,使工程支持C++开发。如下图:
下一步,
下一步,
下一步,
C++编译选项采用默认的就可以了,以后可以在“build.gradle”里面进行更改。
完成工程的创建。
2、安装CMake
新建工程后,出现如下错误,原因是:新版本的Android Studio默认使用CMake进行构建,与以往使用mk和ndk-build不一样,需要下载CMake工具才行。
点击上面的链接“Install CMake and sync project”,自动下载所需的组件。
完成成后,点击“Finish”即可。
3、配置NDK
NDK没配置好的话,会提示上面的错误。
使用CMake构建C++程序的话,需要使用NDK>=12r,如果没有的话,请自行百度搜索下载。
打开工程中的“local.properties”文件,追加一行代码“ndk.dir=NDK的目录”,如下所示:
sync一下,即可解决NDK编译环境的问题。
4、导入ffmpeg编译结果
将前面编译的ffmpeg结果拷贝到工程目录中,路径“app/src/main/cpp/ffmpeg”,结构如下图所示:
其中“native-lib.cpp”是这个IDE自动生成的源文件,“CMakeLists.txt”是这个IED自动生成的构建脚本文件。
1
|
# For more information about using CMake with Android Studio, read the
|
1
|
# documentation: https:
//d.android.com/studio/projects/add-native-code.html
|
1
|
?
|
1
|
# Sets the minimum version of CMake required to build the
native
library.
|
1
|
?
|
1
|
cmake_minimum_required(VERSION
3.4
.
1
)
|
1
|
?
|
1
|
# Creates and names a library, sets it as either STATIC
|
1
|
# or SHARED, and provides the relative paths to its source code.
|
1
|
# You can define multiple libraries, and CMake builds them
for
you.
|
1
|
# Gradle automatically packages shared libraries with your APK.
|
1
|
?
|
1
|
add_library( # Sets the name of the library.
|
1
|
native
-lib
|
1
|
?
|
1
|
# Sets the library as a shared library.
|
1
|
SHARED
|
1
|
?
|
1
|
# Provides a relative path to your source file(s).
|
1
|
src/main/cpp/
native
-lib.cpp )
|
1
|
?
|
1
|
#增加头文件搜索目录
|
1
|
include_directories(src/main/cpp/ffmpeg/include/)
|
1
|
?
|
1
|
# Searches
for
a specified prebuilt library and stores the path as a
|
1
|
# variable. Because CMake includes system libraries in the search path by
|
1
|
#
default
, you only need to specify the name of the
public
NDK library
|
1
|
# you want to add. CMake verifies that the library exists before
|
1
|
# completing its build.
|
1
|
?
|
1
|
find_library( # Sets the name of the path variable.
|
1
|
log-lib
|
1
|
?
|
1
|
# Specifies the name of the NDK library that
|
1
|
# you want CMake to locate.
|
1
|
log )
|
1
|
?
|
1
|
# Specifies libraries CMake should link to your target library. You
|
1
|
# can link multiple libraries, such as libraries you define in
this
|
1
|
# build script, prebuilt third-party libraries, or system libraries.
|
1
|
?
|
1
|
target_link_libraries( # Specifies the target library.
|
1
|
native
-lib
|
1
|
?
|
1
|
#增加ffmpeg库,注意顺序(具体看lib/pkgconfig的依赖关系)
|
1
|
${CMAKE_SOURCE_DIR}/src/main/cpp/ffmpeg/lib/libavfilter.a
|
1
|
${CMAKE_SOURCE_DIR}/src/main/cpp/ffmpeg/lib/libavformat.a
|
1
|
${CMAKE_SOURCE_DIR}/src/main/cpp/ffmpeg/lib/libavcodec.a
|
1
|
${CMAKE_SOURCE_DIR}/src/main/cpp/ffmpeg/lib/libswresample.a
|
1
|
${CMAKE_SOURCE_DIR}/src/main/cpp/ffmpeg/lib/libswscale.a
|
1
|
${CMAKE_SOURCE_DIR}/src/main/cpp/ffmpeg/lib/libavutil.a
|
1
|
?
|
1
|
#增加ffmpeg所需要的依赖库
|
1
|
-lm -lz
|
1
|
?
|
1
|
# Links the target library to the log library
|
1
|
# included in the NDK.
|
1
|
${log-lib}
|
1
|
)
|
- 指定ffmpeg头文件的搜索路径;
- 将ffmpeg的静态库添加到构建中。
6、编写代码
1
|
#include
|
1
|
#include
"libavcodec/avcodec.h"
|
1
|
extern
"C"
|
1
|
JNIEXPORT jstring JNICALL
|
1
|
Java_cn_bassy_ffmpeg01_MainActivity_stringFromJNI(JNIEnv* env, jobject
/* this */
) {
|
1
|
return
env->NewStringUTF(avcodec_configuration());
|
1
|
}
|
Android Studio 有代码提示功能,鼠标放在“”函数上面,可以看到相关注释。
如果没有显示,请进入Settings配置,如下图所示。
Java代码就用IDE自动生成的就可以了。
7、编译程序
编译程序很简单,Android Studio已经集成了NDK开发,只需要点击“Run App”就可以了。
当然,肯定还会有很多错误的,所以下面给出了常见错误及解决方法。
8、错误问题及解决方法
注意,编译ffmpeg时所指定的Android Platform版本,与使用ffmpeg时指定的minSdkVersion有很大的关系,大部分错误都是因为minSdkVersion大于编译ffmpeg时指定的Android Platform版本所导致的!!
1、ffmpeg函数不能被识别
编译是出现" undefined reference to 'avcodec_register_all()"和“Error:(15) undefined reference to 'avcodec_configuration()”,错误如下:
1
|
Error:(
15
) undefined reference to
'avcodec_register_all()'
|
1
|
?
|
1
|
Error:(
15
) undefined reference to
'avcodec_configuration()'
|
1
|
#include
|
1
|
#include
|
1
|
?
|
1
|
#ifdef __cplusplus
|
1
|
extern
"C"
{
|
1
|
#endif
|
1
|
?
|
1
|
#include
"libavcodec/avcodec.h"
|
1
|
?
|
1
|
?
|
1
|
JNIEXPORT jstring JNICALL
|
1
|
Java_cn_bassy_ffmpeg01_MainActivity_stringFromJNI(JNIEnv* env, jobject
/* this */
) {
|
1
|
return
env->NewStringUTF(avcodec_configuration());
|
1
|
}
|
1
|
?
|
1
|
#ifdef __cplusplus
|
1
|
|
1
|
#endif
|
1
|
Error:error: undefined reference to
'av_log'
|
1
|
Error:error: undefined reference to
'av_log'
|
1
|
Error:error: undefined reference to
'av_log'
|
1
|
Error:error: undefined reference to
'av_log'
|
1
|
Error:error: undefined reference to
'av_get_bytes_per_sample'
|
1
|
Error:error: undefined reference to
'av_crc'
|
1
|
Error:error: undefined reference to
'av_crc'
|
1
|
Error:error: undefined reference to
'av_crc'
|
1
|
target_link_libraries( # Specifies the target library.
|
1
|
native
-lib
|
1
|
#增加ffmpeg库,注意顺序(具体看lib/pkgconfig的依赖关系)
|
1
|
${CMAKE_SOURCE_DIR}/src/main/cpp/ffmpeg/lib/libavfilter.a
|
1
|
${CMAKE_SOURCE_DIR}/src/main/cpp/ffmpeg/lib/libavformat.a
|
1
|
${CMAKE_SOURCE_DIR}/src/main/cpp/ffmpeg/lib/libavcodec.a
|
1
|
${CMAKE_SOURCE_DIR}/src/main/cpp/ffmpeg/lib/libswresample.a
|
1
|
${CMAKE_SOURCE_DIR}/src/main/cpp/ffmpeg/lib/libswscale.a
|
1
|
${CMAKE_SOURCE_DIR}/src/main/cpp/ffmpeg/lib/libavutil.a
|
1
|
#增加ffmpeg所需要的依赖库
|
1
|
-lm -lz
|
1
|
# Links the target library to the log library
|
1
|
# included in the NDK.
|
1
|
${log-lib}
|
1
|
)
|
1
|
defaultConfig {
|
1
|
applicationId
"cn.bassy.ffmpeg01"
|
1
|
minSdkVersion
16
|
1
|
targetSdkVersion
25
|
1
|
versionCode
1
|
1
|
versionName
"1.0"
|
1
|
}
|
1
|
APP_STL := gnustl_static
|
1
|
APP_PLATFORM := android-
17
|
1
|
APP_ABI := armeabi
|
1
|
libavutil/common.h:
30
:
2
: error: missing -D__STDC_CONSTANT_MACROS
|
1
|
libavutil/common.h:
205
:
28
: error: use of undeclared identifier
'UINT64_C'
|
1
|
#ifdef __cplusplus
|
1
|
#define __STDC_CONSTANT_MACROS
|
1
|
#ifdef _STDINT_H
|
1
|
#undef _STDINT_H
|
1
|
#endif
|
1
|
# include
"stdint.h"
|
1
|
#endif
|
1
|
?
|
1
|
?
|
1
|
#ifndef INT64_C
|
1
|
#define INT64_C(c) (c ## LL)
|
1
|
#define UINT64_C(c) (c ## ULL)
|
1
|
#endif
|