引言
目前在学习FFmpeg的使用,肯定是要从源码编译开始一步步摸啦,编译过程中也是遇到了大大小小很多问题,查到的资料基本也都是比较老旧的版本,经过各种试错吧,终于是编译成功了,现在就来记录一下编译的过程,也希望能帮助到看这篇文章的你。
源码与环境
编译安卓系统使用的库,需要用到NDK的工具链进行交叉编译,我们这里使用的是 r20b 版本。
还有就是需要下载的源码了,包括 FFmpeg 和 OpenSSL 的源代码,我们直接去官网下载最新的版本。
NDK历史版本:https://developer.android.google.cn/ndk/downloads/revision_history
FFmpeg源码:http://www.ffmpeg.org/download.html
OpenSSL源码:https://www.openssl.org/source/snapshot/
准备编译脚本
哎呀,现在还没有时间写详细介绍,就先把脚本直接贴到这里吧。挖个坑,后面有时间再补,放个狗头保命🐶
OpenSSL脚本
当然如果你不需要支持https,就可以跳过openssl,直接去编译ffmpeg。
#!/bin/bash
set -x
# NDK的路径,根据自己的NDK位置进行设置
export ANDROID_NDK_ROOT=/Users/xxx/env/android-sdk/ndk/android-ndk-r20b
# 编译工具链路径
TOOLCHAIN=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/darwin-x86_64
# 编译环境
SYSROOT=$TOOLCHAIN/sysroot
# 目标Android版本
API=21
# 目标指令集
ARCH=NONE
#so库输出目录
OUTPUT_DIR=NONE
function build_armv7a() {
ARCH=android-arm
OUTPUT_DIR=$PWD/outputs/armeabi-v7a
build_one
}
function build_aarch64() {
ARCH=android-arm64
OUTPUT_DIR=$PWD/outputs/arm64-v8a
build_one
}
function build_one() {
CC=clang
export PATH=$TOOLCHAIN/bin:$PATH
./configure \
$ARCH \
-D__ANDROID_API__=$API \
--prefix=$OUTPUT_DIR
make clean all
# 这里是定义用几个CPU编译
make -j12
make install
}
# 懒,就这么写吧,编哪个就放开哪个
build_armv7a
#build_aarch64
放在OpenSSL源码更目录下,命令行进入文件夹并执行该脚本,成功后会在当前目录下生成如下目录,需要用到的头文件和静态、动态库,就在对应的 include 和 lib 文件夹下。
FFmpeg脚本
#!/bin/bash
set -x
# NDK的路径,根据自己的NDK位置进行设置
NDK=/Users/wwf/Desktop/env/android-sdk/ndk/android-ndk-r20b
# 编译工具链路径
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64
# 编译环境
SYSROOT=$TOOLCHAIN/sysroot
# 目标Android版本
API=21
# 目标指令集
ARCH=NONE
#so库输出目录
OUTPUT_DIR=NONE
# 交叉编译命令前缀
CROSS_PREFIX=NONE
CROSS_PREFIX_CLANG=NONE
# 若不添加 openssl 支持,这项不需要配置
OPENSSL_DIR=NONE
function build_armv7a() {
ARCH=arm
OUTPUT_DIR=$PWD/outputs/armeabi-v7a
CROSS_PREFIX=$TOOLCHAIN/bin/arm-linux-androideabi-
CROSS_PREFIX_CLANG=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-
OPENSSL_DIR=$PWD/openssl/armeabi-v7a
del_temp_config
build_one
}
function build_aarch64() {
ARCH=aarch64
OUTPUT_DIR=$PWD/outputs/arm64-v8a
CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android-
CROSS_PREFIX_CLANG=$TOOLCHAIN/bin/aarch64-linux-android$API-
OPENSSL_DIR=$PWD/openssl/arm64-v8a
del_temp_config
build_one
}
function del_temp_config {
rm -rf config_components.h
rm -rf config.h
}
function build_one() {
./configure \
--prefix=$OUTPUT_DIR \
--target-os=android \
--arch=$ARCH \
--enable-asm \
--enable-neon \
--enable-cross-compile \
--enable-shared \
--disable-static \
--disable-doc \
--disable-ffplay \
--disable-ffprobe \
--disable-symver \
--disable-ffmpeg \
--sysroot=$SYSROOT \
--cc=${CROSS_PREFIX_CLANG}clang \
--cxx=${CROSS_PREFIX_CLANG}clang++ \
--cross-prefix=$CROSS_PREFIX \
--enable-openssl \
--enable-protocols \
--enable-protocol=https \
--enable-nonfree \
--extra-cflags="-I$OPENSSL_DIR/include -fPIC" \
--extra-ldflags="-L$OPENSSL_DIR/lib -lssl -lcrypto" \
# 若不添加 openssl 支持,上面几项不需要配置,替换成下面这句
# --extra-cflags="-fPIC"
make clean all
# 这里是定义用几个CPU编译
make -j12
make install
}
# 懒,就这么写吧,编哪个就放开哪个
build_armv7a
#build_aarch64
其中与openssl相关的部分就是 --enable-openssl 及后面的几句,作用是允许使用openssl和执行要链接的头文件和静态库路径。
如果不需要链接编译 openssl 的话,脚本中的这一部分就是这样的:
function build_one() {
./configure \
--prefix=$OUTPUT_DIR \
...... 忽略部分 ......
--cross-prefix=$CROSS_PREFIX \
--extra-cflags="-fPIC" \
make clean all
# 这里是定义用几个CPU编译
make -j12
make install
}
安卓项目使用与 CMakeList 编写
还是这句话,直接把脚本贴上吧,有时间在补充详细说明。
# 最低版本支持
cmake_minimum_required(VERSION 3.18.1)
# 项目名,就是编译后生成的 so 库名字
project("ffmpegdemo")
# 支持gnu++11
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
# 1. 添加头文件目录, 定义so库和头文件所在目录
include_directories(${CMAKE_SOURCE_DIR}/ffmpeg/include)
set(lib_dir ${CMAKE_SOURCE_DIR}/ffmpeg/lib/${ANDROID_ABI})
add_library( avcodec
SHARED
IMPORTED )
set_target_properties( avcodec
PROPERTIES IMPORTED_LOCATION
${lib_dir}/libavcodec.so )
add_library( avfilter
SHARED
IMPORTED )
set_target_properties( avfilter
PROPERTIES IMPORTED_LOCATION
${lib_dir}/libavfilter.so )
add_library( avformat
SHARED
IMPORTED )
set_target_properties( avformat
PROPERTIES IMPORTED_LOCATION
${lib_dir}/libavformat.so )
add_library( avutil
SHARED
IMPORTED )
set_target_properties( avutil
PROPERTIES IMPORTED_LOCATION
${lib_dir}/libavutil.so )
add_library( swresample
SHARED
IMPORTED )
set_target_properties( swresample
PROPERTIES IMPORTED_LOCATION
${lib_dir}/libswresample.so )
add_library( swscale
SHARED
IMPORTED )
set_target_properties( swscale
PROPERTIES IMPORTED_LOCATION
${lib_dir}/libswscale.so )
add_library( avdevice
SHARED
IMPORTED )
set_target_properties( avdevice
PROPERTIES IMPORTED_LOCATION
${lib_dir}/libavdevice.so )
add_library( ssl
SHARED
IMPORTED )
set_target_properties( ssl
PROPERTIES IMPORTED_LOCATION
${lib_dir}/libssl.so )
add_library( crypto
SHARED
IMPORTED )
set_target_properties( crypto
PROPERTIES IMPORTED_LOCATION
${lib_dir}/libcrypto.so )
# 当前cmake文件所在目录下搜索所有源码文件,命名为 SRC_LIST 供下面使用
aux_source_directory(. SRC_ROOT)
aux_source_directory(./audiosample SRC_AUDIO)
add_library( # Sets the name of the library.
ffmpegdemo
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
${SRC_ROOT}
${SRC_AUDIO}
# 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)
# 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.
ffmpegdemo
# ffmpeg
avcodec
avfilter
avformat
avutil
swresample
swscale
avdevice
ssl
crypto
OpenSLES
# Links the target library to the log library
# included in the NDK.
${log-lib})
这里再贴一下我的目录结构吧,这些东西怎么放其实都无所谓,主要是要跟 gradle 和 cmake 文件中用到的路径对得上号。
先写到这里吧,没有详细说明很是惭愧,后面有时间一定补上。