FFmpeg 有六个常用的功能模块:
配置
Android NDK
环境创建
Android
项目,并与NDK
进行关联在
Android
项目中声明所需要调用的Native
方法使用
Android
需要交互的本地代码 实现在Android
中声明的Native
方法通过
ndk - bulid
命令编译产生.so
库文件编译
Android Studio
工程,从而实现Android
调用本地代码
Java类型 | JNI别名 | 本地类型 |
---|---|---|
boolean | jboolean | unsigned char |
byte | jbyte | signed char |
char | jchar | unsigned short |
short | jshort | short |
int | jint | int |
long | jlong | long long |
float | jfloat | float |
double | jdouble | double |
JNI与NDK关系
git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg
./configure --disable-x86asm
在源码目录下创建编译脚本build_android_arm64-v8a_clang.sh
#!/bin/bash
export NDK=/Users/comochirs/Documents/andriod_project/NDK/android-ndk-r21e
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64
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 -j16
make install
echo "============================ build android arm64-v8a success =========================="
}
#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"
build_android
中间会出现无法确认开发者身份的情况,按照系统提示更改即可,编译成功后会在 android 目录下生成对应六个模块的静态库和动态库,若是编译出错,需要查看ffbuild/config.log
。
创建工程后提示安装NDK,直接使用之前下载好的文件,opt + cmd + c
复制NDK路径,粘贴至local.properties文件下如图:
切换至project选项,将 FFmpeg 各个模块的静态库和头文件放置到指定目录下
编译成功!
调用API测试环境配置是否成功
cmake_minimum_required(VERSION 3.10.2)
# Add FFmpeg
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
set(jnilibs ${CMAKE_SOURCE_DIR}/../jniLibs)
set(libname test-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.
# FFmpeg
${libname}
# Links the target library to the log library
# included in the NDK.
#FFmpeg
${third-party-libs}
${native-libs}
${log-lib} )
调用如下java库,
package com.example.ffmpegproject_20210211;
public class FFMediaPlayer {
static {
System.loadLibrary("test-ffmpeg");
}
public static String GetFFmpegVersion() {
return native_GetFFmpegVersion();
}
private static native String native_GetFFmpegVersion();
}
值得注意的是可以使用AS直接生产对应JNI函数定义,添加宏后代码如下
#include
#include
#include "jni.h"
//由于 FFmpeg 库是 C 语言实现的,告诉编译器按照 C 的规则进行编译
extern "C" {
#include
#include
#include
#include
#include
#include
#include
};
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Java_com_example_ffmpegproject_120210211_FFMediaPlayer_native_1GetFFmpegVersion
* Method: native_GetFFmpegVersion
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL
Java_com_example_ffmpegproject_120210211_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());
return env->NewStringUTF(strBuffer);
}
#ifdef __cplusplus
}
#endif
构建后没有问题!成功输出配置信息。