本次编译环境为windows,linux和mac大同小异(windows都异类了,其他环境编译没啥问题)
下载好MINGW,咋个配置的,百度吧,忘了。
下载好NDK文件,我是R20版本的;在从ffmpeg的官方下载源码,版本4.2.2
ffmpeg从四点几开始的不想了解了,就已经默认对android编译进行了设置。
也默认开启了clang编译
所以只需要写个编译脚本就van事了。
#!/bin/bash
export TMPDIR=`dirname $0`/tmpdir
NDK=D:/technology/android-ndk-r20
API=16
# arm aarch64 i686 x86_64
ARCH=arm
# armv7a aarch64 i686 x86_64
PLATFORM=armv7a
TARGET=$PLATFORM-linux-androideabi
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/windows-x86_64/bin
SYSROOT=$NDK/sysroot
PREFIX=`dirname $0`/Android/$PLATFORM
CFLAG="-D__ANDROID_API__=$API -U_FILE_OFFSET_BITS -DBIONIC_IOCTL_NO_SIGNEDNESS_OVERLOAD -Os -fPIC -DANDROID -D__thumb__ -mthumb -Wfatal-errors -Wno-deprecated -mfloat-abi=softfp -marm"
mkdir -p $TMPDIR
build_one()
{
./configure \
--ln_s="cp -rf" \
--prefix=$PREFIX \
--cc=$TOOLCHAIN/$TARGET$API-clang \
--cxx=$TOOLCHAIN/$TARGET$API-clang++ \
--ld=$TOOLCHAIN/$TARGET$API-clang \
--target-os=android \
--arch=$ARCH \
--cpu=$PLATFORM \
--cross-prefix=$TOOLCHAIN/$ARCH-linux-androideabi- \
--enable-cross-compile \
--enable-shared \
--disable-static \
--enable-runtime-cpudetect \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-doc \
--disable-symver \
--enable-small \
--enable-gpl --enable-nonfree --enable-version3 --disable-iconv --enable-neon --enable-hwaccels \
--enable-jni \
--enable-mediacodec \
--enable-avdevice \
--disable-decoders --enable-decoder=vp9 --enable-decoder=h264 --enable-decoder=mpeg4 --enable-decoder=aac --enable-decoder=h264_mediacodec \
--disable-postproc \
--extra-cflags="$CFLAG" \
--extra-ldflags="-marm"
}
build_one
make clean
make -j4
make install
针对配置开开关关的到处打log看为什么错误。哎。最终这个配置能使用。
编译结束后会直接有文件Android的生成,需要的动态库和文件都在这里面
PS:以上配置要用64位的需要重新编写文件路径(换成自己的就好了)
将刚刚编译好的包以及头文件进行移动
整个最后的文件类似于这种,你也可以按照自己的喜好来,ffmpeg.c
这个是为了执行ffmpeg的各种命令
从之前的源码包里,在fftools
这个文件夹里能够找到各个文件,然后导入进来
build.gradle
的配置
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt" //改成自己的路径
}
}
编写CMakaList.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.4.1)
include_directories(
${CMAKE_SOURCE_DIR}/include/
${CMAKE_SOURCE_DIR}/
D:/technology/ffmpeg-422
)
#定义全局 my_source_path 变量
file(GLOB my_source_path
${CMAKE_SOURCE_DIR}/*.cpp
${CMAKE_SOURCE_DIR}/*.c
)
# Creates and names a library, sets it as either STATICw
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
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).
${my_source_path})
add_library(avcodec SHARED IMPORTED)
add_library(avdevice SHARED IMPORTED)
add_library(avfilter SHARED IMPORTED)
add_library(avformat SHARED IMPORTED)
add_library(avutil SHARED IMPORTED)
add_library(swresample SHARED IMPORTED)
add_library(swscale SHARED IMPORTED)
#add_library(postproc SHARED IMPORTED)
set_target_properties(avcodec PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libavcodec.so)
set_target_properties(avdevice PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libavdevice.so)
set_target_properties(avfilter PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libavfilter.so)
set_target_properties(avformat PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libavformat.so)
set_target_properties(avutil PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libavutil.so)
set_target_properties(swresample PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libswresample.so)
set_target_properties(swscale PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libswscale.so)
#set_target_properties(postproc PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libpostproc.so)
# 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.
native-lib
avcodec
avdevice
avfilter
avformat
avutil
swresample
swscale
# postproc
# Links the target library to the log library
# included in the NDK.
${log-lib})
接着需要改动一些东西,方法名随意
ffmpeg.c
里的int main()
改为int ffmpeg_exec()
在该函数的末尾添加:
nb_filtergraphs = 0;
nb_output_files = 0;
nb_output_streams = 0;
nb_input_files = 0;
nb_input_streams = 0;
注释掉exit_program()
方法,可注释掉该函数内的所有这个方法,不过注意一下if
的作用域
// exit_program(received_nb_signals ? 255 : main_return_code); // 退出程序,不过以报错的形式
接着在ffmpeg.h
头文件里,对方法进行添加
int ffmpeg_exec(int argc, char **argv);
然后按照JNI的方式调用方法进行命令行的执行
native-lib.cpp
#include
#include
#include "android_log.h"
extern "C" {
#include "ffmpeg.h"
JNIEXPORT jint JNICALL
Java_cn_krisez_vvv_FFmpegUtil_exec(JNIEnv *env, jclass, jobjectArray cmd) {
int leng = env->GetArrayLength(cmd);
char *argv[leng];
for (int i = 0; i < leng; ++i) {
argv[i] = (char*) env->GetStringUTFChars((jstring) env->GetObjectArrayElement(cmd, i), nullptr);
}
return ffmpeg_exec(leng,argv);
}
}
Java层:
public class FFmpegUtil {
static {
System.loadLibrary("avcodec");
System.loadLibrary("avdevice");
System.loadLibrary("avfilter");
System.loadLibrary("avformat");
System.loadLibrary("avutil");
System.loadLibrary("swresample");
System.loadLibrary("swscale");
// System.loadLibrary("postproc");
System.loadLibrary("native-lib");
}
public static native String stringFromJNI();
public static native int exec(String[] cmd);
}
执行的时候直接调用FFmpegUtil.exec();
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new Thread(new Runnable() {
@Override
public void run() {
String out = Environment.getExternalStorageDirectory() + "/" + System.currentTimeMillis() + ".mp4";
//以数组的方式传递参数
tv.setText("a "+FFmpegUtil.exec(new String[]{
"ffmpeg",
"-i",
Environment.getExternalStorageDirectory()+"/ysgs.mp4",
"-ss","14",
"-c","copy","-t","10",
out
}));
}
}).run();
}
});
如此将ffmpeg的命令调用方式编译进了Android
仓库自取:Github