Mac 平台 Android FFmpeg 编译与集成实践
Posted 小羊子说
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mac 平台 Android FFmpeg 编译与集成实践相关的知识,希望对你有一定的参考价值。
文章目录
FFmpeg 是什么
FFmpeg 既是一款音视频编解码工具,同时也是一组音视频编解码开发套件,作为编解码开发套件,他为开发者提供了丰富的音视频处理的调用接口。
FFmpeg 提供了多种媒体格式的封装和解封装,包括多种音视频编码、多种协议的流媒体、多种色彩格式转换、多种采样率转换、多种码率转换等; FFmpeg 框架提供了多种丰富的插件模块,包含封装与解封转的插件、编码与解码的插件等。
官方地址:https://www.ffmpeg.org/
为什么要学 FFmpeg 开发
FFmpeg 是一款知名的开源音视频处理软件,它提供了丰富而友好的接口支持开发者进行二次开发。
FFmpeg 读作 “ef ef em peg” ,其中的 “FF” 指的是 “Fast Forward”,“mpeg” 则是 “Moving Picture Experts Group” (动态图像专家组)。
FFmpeg 项目功能复杂而庞大,基本上支持所有常见的音视频处理操作,如封装格式转换、音视频转码、音视频播放和剪辑、视频添加水印滤镜等。
尽管 FFmpeg 功能强大,但是由于其采用的是带有传染性的 LGPL/GPL 开源协议,所以一些大厂基本上都是自己独立开发类似的音视频处理库,甚至在接口和组织模块上模仿 FFmpeg 。
因此,学习 FFmpeg 不仅能够帮助你掌握音视频开发的相关知识脉络,还能让你快速适应不同的音视频处理框架。
FFmpeg 编译
FFmpeg 有六个常用的功能模块:
- libavformat:多媒体文件或协议的封装和解封装库,如 Mp4、Flv 等文件封装格式,RTMP、RTSP 等网络协议封装格式;
- libavcodec:音视频编解码库;
- libavfilter:音视频、字幕滤镜库;
- libswscale:图像格式转换库;
- libswresample:音频重采样库;
- libavutil:工具库;
本文主要是帮助初学者快速上手 FFmpeg 的编译。
1. 编译环境准备
- MAC系统版本:
-
NDK版本:
NDK 从 android Studio 中配置中直接下载
版本号为:25.1.8937393
-
ffmpeg-5.0.1
编译前准备:
mac 环境
//1. 下载 ffmpeg-5.0.1
wget https://ffmpeg.org/releases/ffmpeg-5.0.1.tar.bz2
//2. 解压 FFmpeg 也可以直接解压
tar -jxvf ffmpeg-5.0.1.tar.bz2
遇到的问题:
在官网的链接中下载的 ndk 格式为 dmg 的 如何安装呢?(暂时没有解决,换成了其他方式下载)
https://developer.android.google.cn/ndk/downloads?hl=zh_cn
此种方式没有用,不能解压成功,如果大家能处理成功,求指导。
于是根据官方文档的提示 在Android studio中去下载
最后找到NDK的路径,后面的脚本需要用:
注意这里的路径:
刚开始我用的是 :~/Libraray/…… 这里的缩写路径,在文件夹右健进入 iterm 后出现的。不能用,需要用 pwd来找到绝对的路径。
以我的为例:
/Users/yangjun/Library/Android/sdk/ndk/25.1.8937393
2. FFmpeg 环境配置
使用 Android studio 打开configure文件,
- 搜索CMDLINE_SET,新增cross_prefix_clang
-
修改编译工具路径设置
-
新建编译脚本
build_android_so.sh
3. 完整的脚本
#!/bin/bash
#配置NDK路径 需要以你的为准
export NDK=/Users/xiaoyangzishuo/Library/Android/sdk/ndk/21.4.7075529
#配置toolchain路径
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64
#配置交叉编译环境的根路径
SYSROOT=$TOOLCHAIN/sysroot
#arm64-v8a
API=30
ARCH=arm64
CPU=armv8-a
CROSS_PREFIX="$TOOLCHAIN/bin/aarch64-linux-android"
CROSS_PREFIX_CLANG="$TOOLCHAIN/bin/aarch64-linux-android$API"
#armeabi-v7a
#API=30
#ARCH=arm
#CPU=armv7-a
#CROSS_PREFIX="$TOOLCHAIN/bin/arm-linux-androideabi"
#CROSS_PREFIX_CLANG="$TOOLCHAIN/bin/armv7a-linux-androideabi$API"
OPTIMIZE_CFLAGS="-march=$CPU"
#配置so输出路径
OUTPUT=/Users/xiaoyangzishuo/Documents/android/FFmpeg/ffmpeg-5.0.1/out/android/$CPU
fun build
./configure \\
--prefix=$OUTPUT \\
--target-os=android \\
--arch=$ARCH \\
--cpu=$CPU \\
--enable-neon \\
--enable-cross-compile \\
--enable-shared \\
--enable-jni \\
--disable-static \\
--disable-asm \\
--disable-doc \\
--disable-ffplay \\
--disable-ffprobe \\
--disable-symver \\
--disable-ffmpeg \\
--disable-avdevice \\
--disable-debug \\
--disable-postproc \\
--sysroot=$SYSROOT \\
--cross-prefix=$CROSS_PREFIX- \\
--cross_prefix_clang=$CROSS_PREFIX_CLANG- \\
--extra-cflags="-Os -fpic $OPTIMIZE_CFLAGS"
make clean all
make -j8
make install
echo '编译开始...'
build
echo '编译结束...'
最后执行脚本即可
chmod +x build_android_so.sh (如果没有权限,先添加权限,之后不再需要)
./build_android_so.sh
脚本已经执行成功,这里有个提示。先忽略。
大概 5-10 分钟后,得到了 6个 so 库 编译成功。
后面可以将此 so 放到 Android Stuido中集成。
4. FQA
后面完善。
编译小结
上面编译 ffmpeg 脚本流程:shell -> configure -> make
首先我们编写 build_android_so.sh
脚本,调用 configure 配置参数,最后调用 make 命令生成动态库。
其中的 make 就是调用 makefile,makefile 是一种构建工具,类似于Gradle(构建.apk)、Maven(构建.war)
遇到最大的问题,是环境的路径的配置,脚本很简单,也有一些莫名奇妙的小问题,不过不影响编译成功。
在Android Studio 中的集成
- 先建立C++的项目
按上图所示例一步一步运行,配置好ndk环境。目的在于接下来的操作的文件先准备好。
-
将 so库及头文件 copy到项目中来
-
设置
CMakeLists.txt
# 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.18.1) # 支持gnu++11 set(CMAKE_CXX_FLAGS "$CMAKE_CXX_FLAGS -std=gnu++11") # 1. 定义so库和头文件所在目录,方面后面使用 set(ffmpeg_lib_dir $CMAKE_SOURCE_DIR/../jniLibs/$ANDROID_ABI) set(ffmpeg_head_dir $CMAKE_SOURCE_DIR) # 2. 添加头文件目录 include_directories($ffmpeg_head_dir/include) # 3. 添加ffmpeg相关的so库 add_library( avutil SHARED IMPORTED ) set_target_properties( avutil PROPERTIES IMPORTED_LOCATION $ffmpeg_lib_dir/libavutil.so ) add_library( # 生成的库的名字 swresample # 动态库 SHARED # 源文件 IMPORTED ) set_target_properties( swresample PROPERTIES IMPORTED_LOCATION $ffmpeg_lib_dir/libswresample.so ) add_library( avcodec SHARED IMPORTED ) set_target_properties( avcodec PROPERTIES IMPORTED_LOCATION $ffmpeg_lib_dir/libavcodec.so ) add_library( avfilter SHARED IMPORTED) set_target_properties( avfilter PROPERTIES IMPORTED_LOCATION $ffmpeg_lib_dir/libavfilter.so ) add_library( swscale SHARED IMPORTED) set_target_properties( swscale PROPERTIES IMPORTED_LOCATION $ffmpeg_lib_dir/libswscale.so ) add_library( avformat SHARED IMPORTED) set_target_properties( avformat PROPERTIES IMPORTED_LOCATION $ffmpeg_lib_dir/libavformat.so ) # 查找代码中使用到的系统库 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 ) # 配置目标so库编译信息 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). native-lib.cpp ) # 指定编译目标库时,cmake要链接的库 target_link_libraries( # 指定目标库,native-lib 是在上面 add_library 中配置的目标库 native-lib # 4. 连接 FFmpeg 相关的库 avutil swresample avcodec avfilter swscale avformat # avdevice # Links the target library to the log library # included in the NDK. $log-lib )
-
设置
native-lib.cpp
#include <jni.h>
#include <string>
extern "C"
#include "include/libavutil/avutil.h"
extern "C" JNIEXPORT jstring JNICALL
Java_com_juneyang_cdemo_MainActivity_ffmpegInfo(JNIEnv *env, jobject thiz)
// 返回 ffmpeg 配置信息
return env->NewStringUTF(avutil_configuration());
- 最后设置
build.gradle
plugins
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
android
compileSdk 32
defaultConfig
applicationId "com.juneyang.cdemo"
minSdk 26
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild
cmake
cppFlags '-std=c++17'
// abiFilters
ndk
abiFilters "arm64-v8a"
buildTypes
release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
compileOptions
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
kotlinOptions
jvmTarget = '1.8'
externalNativeBuild
cmake
path file('src/main/cpp/CMakeLists.txt')
version '3.18.1'
buildFeatures
viewBinding true
sourceSets
main
//将依赖库打进apk,否则可能出现找不到库
jniLibs.srcDirs = ['libs']
dependencies
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
最后运行成功。
集成问题记录
目前出现一个问题,明明 NDK中有该文件,编译时却找不到。
NDK中有文件如图所示:
编译时出错。
CMakeLists.txt 配置如下:
# 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.18.1)
# 支持gnu++11
set(CMAKE_CXX_FLAGS "$CMAKE_CXX_FLAGS -std=gnu++11")
# 1. 定义so库和头文件所在目录,方面后面使用
set(ffmpeg_lib_dir $CMAKE_SOURCE_DIR/../jniLibs/$ANDROID_ABI)
set(ffmpeg_head_dir $CMAKE_SOURCE_DIR)
# 2. 添加头文件目录
include_directories($ffmpeg_head_dir/include)
# 3. 添加ffmpeg相关的so库
add_library( avutil
SHARED
IMPORTED )
set_target_properties( avutil
PROPERTIES IMPORTED_LOCATION
$ffmpeg_lib_dir/libavutil.so )
add_library(
# 生成的库的名字
swresample
# 动态库
SHARED
# 源文件
IMPORTED )
set_target_properties( swresample
PROPERTIES IMPORTED_LOCATION
$ffmpeg_lib_dir/libswresample.so )
add_library(
avcodec
SHARED
IMPORTED )
set_target_properties(
avcodec
PROPERTIES IMPORTED_LOCATION
$ffmpeg_lib_dir/libavcodec.so )
add_library(
avfilter
SHARED
IMPORTED)
set_target_properties(
avfilter
PROPERTIES IMPORTED_LOCATION
$ffmpeg_lib_dir/libavfilter.so )
add_library(
swscale
SHARED
IMPORTED)
set_target_properties(
swscale
PROPERTIES IMPORTED_LOCATION
$ffmpeg_lib_dir/libswscale.so )
add_library(
avformat
SHARED
IMPORTED)
set_target_properties(
avformat
PROPERTIES IMPORTED_LOCATION
$ffmpeg_lib_dir/libavformat.so )
#add_library(
# avdevice
# SHARED
# IMPORTED)
#set_target_properties( avdevice
# PROPERTIES IMPORTED_LOCATION
# $ffmpeg_lib_dir/libavdevice.so )
# 查找代码中使用到的系统库
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 )
# 配置目标so库编译信息
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).
native-lib.cpp
)
# 指定编译目标库时,cmake要链接的库
target_link_libraries(
# 指定目标库,native-lib 是在上面 add_library 中配置的目标库
native-lib
# 4. 连接 FFmpeg 相关的库
avutil
swresample
avcodec
avfilter
swscale
avformat
# avdevice
# Links the target library to the log library
# included in the NDK.
$log-lib )
native-lib.cpp 如下:
#include <jni.h>
#include <unistd.h>
#include <cstdint>
#include <string>
extern "C"
#include "include/libavcodec/avcodec.h"
extern "C" JNIEXPORT jstring JNICALL
Java_com_juneyang_cdemo_MainActivity_ffmpegInfo(JNIEnv *env, jobject thiz)
// 返回ffmpeg配置信息
return env->NewStringUTF(avcodec_configuration());
编译时出错,最后在在 avcodec_configuration引用时选择了几个不同的头文件,并检查了 CmakeLists.txt
中的头文件路径,几次尝试后解决了,这里有点困惑。
写在最后
折腾了两个晚上,记录了整个编译流程和集成的问题,如有问题,欢迎指正。
参考资料:
https://zhuanlan.zhihu.com/p/498073893
以上是关于Mac 平台 Android FFmpeg 编译与集成实践的主要内容,如果未能解决你的问题,请参考以下文章