环境
- OS:macOS Catalina 10.15.7
- IDE:Android Studio 4.1
- FFmpeg Version:4.3
下载
git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg
使用Homebrew下载
Mac-Pro:~ andy$ brew search ffmpeg
==> Formulae
ffmpeg ✔ ffmpeg2theora ffmpeg@2.8 ffmpegthumbnailer
查看版本
Mac-Pro:~ andy$ ffmpeg -version
ffmpeg version 4.3 Copyright (c) 2000-2020 the FFmpeg developers
built with Apple clang version 12.0.0 (clang-1200.0.32.2)
configuration:
libavutil 56. 51.100 / 56. 51.100
libavcodec 58. 91.100 / 58. 91.100
libavformat 58. 45.100 / 58. 45.100
libavdevice 58. 10.100 / 58. 10.100
libavfilter 7. 85.100 / 7. 85.100
libswscale 5. 7.100 / 5. 7.100
libswresample 3. 7.100 / 3. 7.100
如果使用的是brew 下载的ffmpeg,它的目录在 /usr/local/Cellar/ffmpeg
编写脚本
单编
在ffmpeg根目录创建build_android_clang.sh并添加以下代码
touch build_android_clang.sh && vim build_android_clang.sh
#!/bin/bash
# 目标Android版本
API=28
# x86、x86_64、armeabi、armeabi-v7a、arm64-v8a
CPU=$1
# so库输出目录
OUTPUT=/Users/andy/Development/workspace/StudioProjects/rep/ffmpeg-4.3/android/$CPU
# NDK的路径,根据自己的NDK位置进行设置
NDK=/Users/andy/Library/Android/sdk/ndk-bundle
# 编译工具链路径
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64
# 编译环境
SYSROOT=$TOOLCHAIN/sysroot
function build
{
./configure \
--prefix=$OUTPUT \
--target-os=android \
--arch=arm \
--cpu=armv7-a \
--enable-asm \
--enable-neon \
--enable-cross-compile \
--enable-shared \
--disable-static \
--disable-doc \
--disable-ffplay \
--disable-ffprobe \
--disable-symver \
--disable-ffmpeg \
--sysroot=$SYSROOT \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--cross-prefix-clang=$TOOLCHAIN/bin/armv7a-linux-androideabi$API- \
--extra-cflags="-fPIC"
make clean all
make -j12
make install
}
build
编译方式1(带参数):
Mac-Pro:ffmpeg-4.3 andy$ . build_android_clang.sh "x86"
编译方式2(不带参数):修改脚本把 CPU=$1
替换成CPU=x86
,然后直接执行
Mac-Pro:ffmpeg-4.3 andy$ . build_android_clang.sh
引用外文:如果编译出现失败,请尝试如下方案,修改configure,使用clang轻量编译器;
1.CMDLINE_SET中添加cross_prefix_clang
2.修改使用的默认交叉编译工具
## 替换前
cc_default="${cross_prefix}${cc_default}"
cxx_default="${cross_prefix}${cxx_default}"
##替换后
cc_default="${cross_prefix_clang}${cc_default}"
cxx_default="${cross_prefix_clang}${cxx_default}"
https://www.jianshu.com/p/350f8e083e82
其实查看configure配置,结合编译脚本配合的变量
${cross_prefix} = --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi-
${cross_prefix_clang} = --cross-prefix-clang=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-
整编,一次性编译x86、x86_64、armeabi、armeabi-v7a、arm64-v8a
,这里引用了外文脚本,并加以修改
https://www.jianshu.com/p/0a7f3175c1b9
但也可以修改单编译的脚本,其实就是增加fun 里面使用一个for或者while,修改一下脚本变量参数即可(要懂一些shell基本语法);附--arch=arm \ --cpu=armv7-a \
for cpu in 'x86' 'x86_64' 'armeabi' 'armeabi-v7a' 'arm64-v8a'
do
echo "start build ${cpu}"
build ${cpu}
done
整编
脚本文件,build_ffmpeg.sh
#!/bin/bash
NDK_PATH=/Users/andy/Library/Android/sdk/ndk-bundle
HOST_PLATFORM=darwin-x86_64
API=29
TOOLCHAINS="$NDK_PATH/toolchains/llvm/prebuilt/$HOST_PLATFORM"
SYSROOT="$TOOLCHAINS/sysroot"
CFLAG="-D__ANDROID_API__=$API -Os -fPIC -DANDROID "
LDFLAG="-lc -lm -ldl -llog "
PREFIX=android-build
CONFIG_LOG_PATH=${PREFIX}/log
COMMON_OPTIONS=
CONFIGURATION=
build() {
APP_ABI=$1
echo "======== > Start build $APP_ABI"
case ${APP_ABI} in
armeabi-v7a)
ARCH="arm"
CPU="armv7-a"
MARCH="armv7-a"
TARGET=armv7a-linux-androideabi
CC="$TOOLCHAINS/bin/$TARGET$API-clang"
CXX="$TOOLCHAINS/bin/$TARGET$API-clang++"
LD="$TOOLCHAINS/bin/$TARGET$API-clang"
CROSS_PREFIX="$TOOLCHAINS/bin/arm-linux-androideabi-"
EXTRA_CFLAGS="$CFLAG -mfloat-abi=softfp -mfpu=vfp -marm -march=$MARCH "
EXTRA_LDFLAGS="$LDFLAG"
EXTRA_OPTIONS="--enable-neon --cpu=$CPU "
;;
arm64-v8a)
ARCH="aarch64"
TARGET=$ARCH-linux-android
CC="$TOOLCHAINS/bin/$TARGET$API-clang"
CXX="$TOOLCHAINS/bin/$TARGET$API-clang++"
LD="$TOOLCHAINS/bin/$TARGET$API-clang"
CROSS_PREFIX="$TOOLCHAINS/bin/$TARGET-"
EXTRA_CFLAGS="$CFLAG"
EXTRA_LDFLAGS="$LDFLAG"
EXTRA_OPTIONS=""
;;
x86)
ARCH="x86"
CPU="i686"
MARCH="i686"
TARGET=i686-linux-android
CC="$TOOLCHAINS/bin/$TARGET$API-clang"
CXX="$TOOLCHAINS/bin/$TARGET$API-clang++"
LD="$TOOLCHAINS/bin/$TARGET$API-clang"
CROSS_PREFIX="$TOOLCHAINS/bin/$TARGET-"
EXTRA_CFLAGS="$CFLAG -march=$MARCH -mtune=intel -mssse3 -mfpmath=sse -m32"
EXTRA_LDFLAGS="$LDFLAG"
EXTRA_OPTIONS="--cpu=$CPU "
;;
x86_64)
ARCH="x86_64"
CPU="x86-64"
MARCH="x86_64"
TARGET=$ARCH-linux-android
CC="$TOOLCHAINS/bin/$TARGET$API-clang"
CXX="$TOOLCHAINS/bin/$TARGET$API-clang++"
LD="$TOOLCHAINS/bin/$TARGET$API-clang"
CROSS_PREFIX="$TOOLCHAINS/bin/$TARGET-"
EXTRA_CFLAGS="$CFLAG -march=$CPU -mtune=intel -msse4.2 -mpopcnt -m64"
EXTRA_LDFLAGS="$LDFLAG"
EXTRA_OPTIONS="--cpu=$CPU "
;;
esac
echo "-------- > Start clean workspace"
make clean
echo "-------- > Start build configuration"
CONFIGURATION="$COMMON_OPTIONS"
CONFIGURATION="$CONFIGURATION --logfile=$CONFIG_LOG_PATH/config_$APP_ABI.log"
CONFIGURATION="$CONFIGURATION --prefix=$PREFIX"
CONFIGURATION="$CONFIGURATION --libdir=$PREFIX/libs/$APP_ABI"
CONFIGURATION="$CONFIGURATION --incdir=$PREFIX/includes/$APP_ABI"
CONFIGURATION="$CONFIGURATION --pkgconfigdir=$PREFIX/pkgconfig/$APP_ABI"
CONFIGURATION="$CONFIGURATION --cross-prefix=$CROSS_PREFIX"
CONFIGURATION="$CONFIGURATION --arch=$ARCH"
CONFIGURATION="$CONFIGURATION --sysroot=$SYSROOT"
CONFIGURATION="$CONFIGURATION --cc=$CC"
CONFIGURATION="$CONFIGURATION --cxx=$CXX"
CONFIGURATION="$CONFIGURATION --ld=$LD"
CONFIGURATION="$CONFIGURATION $EXTRA_OPTIONS"
echo "-------- > Start config makefile with $CONFIGURATION --extra-cflags=${EXTRA_CFLAGS} --extra-ldflags=${EXTRA_LDFLAGS}"
./configure ${CONFIGURATION} \
--extra-cflags="$EXTRA_CFLAGS" \
--extra-ldflags="$EXTRA_LDFLAGS"
echo "-------- > Start make $APP_ABI with -j8"
make -j10
echo "-------- > Start install $APP_ABI"
make install
echo "++++++++ > make and install $APP_ABI complete."
}
build_all() {
COMMON_OPTIONS="$COMMON_OPTIONS --target-os=android"
COMMON_OPTIONS="$COMMON_OPTIONS --disable-static"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-shared"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-protocols"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-cross-compile"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-optimizations"
COMMON_OPTIONS="$COMMON_OPTIONS --disable-debug"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-small"
COMMON_OPTIONS="$COMMON_OPTIONS --disable-doc"
COMMON_OPTIONS="$COMMON_OPTIONS --disable-programs"
COMMON_OPTIONS="$COMMON_OPTIONS --disable-ffmpeg"
COMMON_OPTIONS="$COMMON_OPTIONS --disable-ffplay"
COMMON_OPTIONS="$COMMON_OPTIONS --disable-ffprobe"
COMMON_OPTIONS="$COMMON_OPTIONS --disable-symver"
COMMON_OPTIONS="$COMMON_OPTIONS --disable-network"
COMMON_OPTIONS="$COMMON_OPTIONS --disable-x86asm"
COMMON_OPTIONS="$COMMON_OPTIONS --disable-asm"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-pthreads"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-mediacodec"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-jni"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-zlib"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-pic"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-avresample"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=h264"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=mpeg4"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=mjpeg"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=png"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=vorbis"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=opus"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=flac"
echo "COMMON_OPTIONS=$COMMON_OPTIONS"
echo "PREFIX=$PREFIX"
echo "CONFIG_LOG_PATH=$CONFIG_LOG_PATH"
mkdir -p ${CONFIG_LOG_PATH}
build "armeabi-v7a"
build "arm64-v8a"
build "x86"
build "x86_64"
}
echo "-------- Start --------"
build_all
echo "-------- End --------"
其实以上代码略显复杂,同时也缺少了armeabi
,等待编译完成后查看.so
单编、整编so库目录
Mac-Pro:x86 andy$ ls
libavcodec.so libavformat.so libswscale.so
libavdevice.so libavutil.so
libavfilter.so libswresample.so
iShot2020-11-10 10.17.49.png
iShot2020-11-10 10.18.23.png
集成Android Studio
新建Native C++项目,复制编译好的so和头文件到相应目录,截图如下
iShot2020-11-10 14.09.47.png
build.gradle
defaultConfig{
...
externalNativeBuild {
cmake {
cppFlags "-frtti -fexceptions"
}
}
ndk {
//默认生成平台架构armeabi、x86、x86_64、armeabi-v7a、arm64-v8a
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
externalNativeBuild {
cmake {
//makefile编译语言文件路径,默认新建的C++项目会放在cpp目录下,这里我移到src/main/根目下了
path "src/main/CMakeLists.txt"
version "3.10.2"
}
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.10.2)
project("myapplication")
# 支持gnu++11 //默认创建C++时可选择C++11、C++14、C++17交叉工具链
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}/cpp/ffmpeg)
# 2. 添加头文件目录
include_directories(${ffmpeg_head_dir}/includes)
## log在3.10.3不显示,需要降级3.6.0或者3.4.1
message("cmake_source_dir = ${CMAKE_SOURCE_DIR}")
message("ffmpeg_lib_dir = ${ffmpeg_lib_dir}")
message("ffmpeg_head_dir = ${ffmpeg_head_dir}")
# 3. 添加ffmpeg相关的so库
## 编解码器库
add_library(
avcodec
SHARED
IMPORTED)
set_target_properties(
avcodec
PROPERTIES IMPORTED_LOCATION
${ffmpeg_lib_dir}/libavcodec.so)
## 设备库
add_library(
avdevice
SHARED
IMPORTED)
set_target_properties(
avdevice
PROPERTIES IMPORTED_LOCATION
${ffmpeg_lib_dir}/libavdevice.so)
## 滤镜库
add_library(
avfilter
SHARED
IMPORTED)
set_target_properties(
avfilter
PROPERTIES IMPORTED_LOCATION
${ffmpeg_lib_dir}/libavfilter.so)
## 格式库
add_library(
avformat
SHARED
IMPORTED)
set_target_properties(
avformat
PROPERTIES IMPORTED_LOCATION
${ffmpeg_lib_dir}/libavformat.so)
## 资源重采集库
add_library(
avresample
SHARED
IMPORTED)
set_target_properties(
avresample
PROPERTIES IMPORTED_LOCATION
${ffmpeg_lib_dir}/libavresample.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(
swscale
SHARED
IMPORTED)
set_target_properties(
swscale
PROPERTIES IMPORTED_LOCATION
${ffmpeg_lib_dir}/libswscale.so)
add_library( # Sets the name of the library.
native-lib
SHARED
cpp/native-lib.cpp)
find_library( # Sets the name of the path variable.
log-lib
log)
target_link_libraries( # Specifies the target library.
native-lib
# ffmpeg库关联
avcodec
avdevice
avfilter
avformat
avresample
avutil
swresample
swscale
# Links the target library to the log library
# included in the NDK.
${log-lib})
native-lib.cpp
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include <libavfilter/avfilter.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libswresample/swresample.h>
#include <libswscale/swscale.h>
JNIEXPORT jstring JNICALL
Java_top_andy_myapplication_FFmpegActivity_ffmpegConfigInfo(JNIEnv *env, jobject thiz) {
return env->NewStringUTF(avdevice_configuration());
}
//编解码器库
JNIEXPORT jstring JNICALL
Java_top_andy_myapplication_FFmpegActivity_avcodecInfo(JNIEnv *env, jobject thiz) {
return env->NewStringUTF(avcodec_configuration());
}
//设备库
JNIEXPORT jstring JNICALL
Java_top_andy_myapplication_FFmpegActivity_avdeviceInfo(JNIEnv *env, jobject thiz) {
return env->NewStringUTF(avdevice_configuration());
}
//滤镜库
JNIEXPORT jstring JNICALL
Java_top_andy_myapplication_FFmpegActivity_avfilterInfo(JNIEnv *env, jobject thiz) {
return env->NewStringUTF(avfilter_configuration());
}
//格式库
JNIEXPORT jstring JNICALL
Java_top_andy_myapplication_FFmpegActivity_avformatInfo(JNIEnv *env, jobject thiz) {
return env->NewStringUTF(avformat_configuration());
}
//工具库
JNIEXPORT jstring JNICALL
Java_top_andy_myapplication_FFmpegActivity_avutil(JNIEnv *env, jobject thiz) {
return env->NewStringUTF(avutil_configuration());
}
//音频重采样库
JNIEXPORT jstring JNICALL
Java_top_andy_myapplication_FFmpegActivity_swresample(JNIEnv *env, jobject thiz) {
return env->NewStringUTF(swresample_configuration());
}
//媒体缩放库(颜色转换和绽放)
JNIEXPORT jstring JNICALL
Java_top_andy_myapplication_FFmpegActivity_swscale(JNIEnv *env, jobject thiz) {
return env->NewStringUTF(swscale_configuration());
}
}
FFmpegActivity
class FFmpegActivity : AppCompatActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_ffmpeg_info)
ffmpeg_info.text = ffmpegConfigInfo();
avcodecInfo.setOnClickListener { ffmpeg_info.text = avcodecInfo() }
avdeviceInfo.setOnClickListener { ffmpeg_info.text = avdeviceInfo() }
avfilterInfo.setOnClickListener { ffmpeg_info.text = avfilterInfo() }
avformatInfo.setOnClickListener { ffmpeg_info.text = avformatInfo() }
avutil.setOnClickListener { ffmpeg_info.text = avutil() }
swresample.setOnClickListener { ffmpeg_info.text = swresample() }
swscale.setOnClickListener { ffmpeg_info.text = swscale() }
}
private external fun avcodecInfo():String //编解码器库
private external fun avdeviceInfo():String //设备库
private external fun avfilterInfo():String //滤镜库
private external fun avformatInfo():String //格式库
private external fun avutil():String //工具库
private external fun swresample():String //音频重采样库
private external fun swscale():String //媒体缩放库(颜色转换和绽放)
private external fun ffmpegConfigInfo():String//FFmpeg配置信息
companion object{
init {
System.loadLibrary("native-lib")
}
}
网友评论