最近在学习Android上的FFmpeg开发。记录下在Mac上交叉编译和使用Android FFmpeg库的过程。
1. 交叉编译
# 1.下载ffmpeg-4.2.2源码
wget https://ffmpeg.org/releases/ffmpeg-4.2.2.tar.bz2
# 2. 解压
# 3. 运行configure脚本配置项目
./configure --disable-x86asm
在当前文件夹下创建编译脚本build_android_arm64-v8a_clang.sh
:
#!/bin/zsh
export NDK=~/Library/Android/android-ndk-r20b #这里配置先你的 NDK 路径
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64
#arm64-v8a
ARCH=arm64
CPU=armv8-a
API=21
CC=$TOOLCHAIN/bin/aarch64-linux-android$API-clang
CXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++
SYSROOT=$NDK/toolchains/llvm/prebuilt/darwin-x86_64/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=$CPU"
#armv7-a
#ARCH=arm
#CPU=armv7-a
#API=21
#CC=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang
#CXX=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang++
#SYSROOT=$NDK/toolchains/llvm/prebuilt/darwin-x86_64/sysroot
#CROSS_PREFIX=$TOOLCHAIN/bin/arm-linux-androideabi-
#PREFIX=$(pwd)/android/$CPU
#OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfp -marm -march=$CPU "
function build_android {
./configure
--prefix=$PREFIX
--enable-neon
--enable-hwaccels
--enable-gpl
--disable-postproc
--disable-debug
--enable-small
--enable-jni
--enable-mediacodec
--enable-decoder=h264_mediacodec
--enable-static
--enable-shared
--disable-doc
--enable-ffmpeg
--disable-ffplay
--disable-ffprobe
--disable-avdevice
--disable-doc
--disable-symver
--cross-prefix=$CROSS_PREFIX
--target-os=android
--arch=$ARCH
--cpu=$CPU
--cc=$CC
--cxx=$CXX
--enable-cross-compile
--sysroot=$SYSROOT
--extra-cflags="-Os -fpic $OPTIMIZE_CFLAGS"
--extra-ldflags="$ADDI_LDFLAGS"
make clean
make -j16
echo "============================ build android arm64-v8a success =========================="
}
build_android
运行脚本编译,之后会在android/armv8-a/lib/
下生成动态和静态库。
# 修改 build_android_arm64-v8a_clang.sh 可执行权限
chmod +x build_android_arm64-v8a_clang.sh
# 运行编译脚本
./build_android_arm64-v8a_clang.sh
2. Android上集成测试
新建Android项目。
2.1 JNI接口
app/src/jniLibs/arm64-v8a
目录下。package com.zzakafool.androidffmpeg;
public class FFMediaPlayer {
static {
System.loadLibrary("learn-ffmpeg");
}
public static String GetFFmpegVersion() {
return native_GetFFmpegVersion();
}
private static native String native_GetFFmpegVersion();
}
app/src/main/cpp/
下添加对应native实现FFMediaPlayer.cpp
。#include
#include
//#include "util/LogUtil.h"
#include "jni.h"
//由于 FFmpeg 库是 C 语言实现的,告诉编译器按照 C 的规则进行编译
extern "C" {
#include
#include
#include
#include
#include
#include
#include
};
extern "C"
JNIEXPORT jstring JNICALL
Java_com_zzakafool_androidffmpeg_FFMediaPlayer_native_1GetFFmpegVersion(JNIEnv *env, jclass clazz) {
// TODO: implement native_GetFFmpegVersion()
char strBuffer[1024 * 4] = {0};
strcat(strBuffer, "libavcodec : ");
strcat(strBuffer, AV_STRINGIFY(LIBAVCODEC_VERSION));
strcat(strBuffer, "nlibavformat : ");
strcat(strBuffer, AV_STRINGIFY(LIBAVFORMAT_VERSION));
strcat(strBuffer, "nlibavutil : ");
strcat(strBuffer, AV_STRINGIFY(LIBAVUTIL_VERSION));
strcat(strBuffer, "nlibavfilter : ");
strcat(strBuffer, AV_STRINGIFY(LIBAVFILTER_VERSION));
strcat(strBuffer, "nlibswresample : ");
strcat(strBuffer, AV_STRINGIFY(LIBSWRESAMPLE_VERSION));
strcat(strBuffer, "nlibswscale : ");
strcat(strBuffer, AV_STRINGIFY(LIBSWSCALE_VERSION));
strcat(strBuffer, "navcodec_configure : n");
strcat(strBuffer, avcodec_configuration());
strcat(strBuffer, "navcodec_license : ");
strcat(strBuffer, avcodec_license());
// LOGCATE("GetFFmpegVersionn%s", strBuffer);
return env->NewStringUTF(strBuffer);
}
app/src/main/cpp/
下添加CMakeLists.txt
。# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
set(jnilibs ${CMAKE_SOURCE_DIR}/../jniLibs)
set(libname learn-ffmpeg)
include_directories(
include
${CMAKE_SOURCE_DIR}/util
)
link_directories(
${jnilibs}/${ANDROID_ABI})
file(GLOB src-files
${CMAKE_SOURCE_DIR}/*.cpp)
add_library( # Sets the name of the library.
${libname}
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
${src-files}
)
set(third-party-libs
avformat
avcodec
avfilter
swresample
swscale
avutil
)
set(native-libs
android
EGL
GLESv3
OpenSLES
log
m
z
)
target_link_libraries( # Specifies the target library.
${libname}
# Links the target library to the log library
# included in the NDK.
${log-lib}
${third-party-libs}
${native-libs}
)
import static com.zzakafool.androidffmpeg.R.id.*;
import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.zzakafool.androidffmpeg.R.id;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((TextView)findViewById(text_view)).setText(FFMediaPlayer.GetFFmpegVersion());
}
}
参考资料
FFmpeg 开发(01):FFmpeg 编译和集成