FFmpeg 4.1.3 + Ubuntu 18.04 + Android Studio 3.4.1编译
环境搭建
安装配置 Ubuntu
- 安装Ubuntu 18.04(我使用的是Windows10应用商店里的版本,后期引入头文件比较方便)
启动系统后会提示设置用户名密码,按照提示设置就好,进入系统后执行以下命令提高到root权限(方便操作,不然老提示你权限不足)sudo su
- 安装完成后执行以下命令:
apt-get update
apt-get install yasm
apt-get install pkg-config
下载 NDK
版本是NDK17c(这个版本匹配度最高,修改最少)
需要下载两个版(源码编译和android studio编译分别会用到):
- Ubuntu 下载(下载到Ubuntu中)
下载完成后用unzip工具解压缩apt-get install unzip
unzip android-ndk-r17c-linux-x86_64.zip - Windows 下载(下载到Windows中)
下载完成后用winRAR工具解压缩
下载 FFmpeg
版本是4.1.3 下载 (下载到Ubuntu中)
下载完成后用tar解压
tar -zxvf ffmpeg-4.1.3.tar.bz2
编译 FFmpeg
-
编写编译脚本
在Ubuntu下进入FFmpeg-n4.1.3目录,用vim或vi工具创建文件build_android.sh,在文件中编写以下内容:#!/bin/bash clear function build_android { ./configure \ --prefix=$PREFIX \ --enable-shared \ --disable-static \ --disable-ffmpeg \ --disable-ffplay \ --disable-ffprobe \ --target-os=android \ --disable-doc \ --enable-cross-compile \ --cross-prefix=$CROSS_PREFIX \ --arch=$ARCH \ --sysroot=$SYSROOT \ --extra-cflags="-I$NDK/sysroot/usr/include/arm-linux-androideabi -isysroot $NDK/sysroot -fPIC -DANDROID -D__thumb__ -mthumb -Wfatal-errors -Wno-deprecated -mfloat-abi=softfp -marm -march=armv7-a" \ --enable-neon make clean all make -j4 make install } NDK=/home/wuppa/android-ndk-r17c #填写自己ndk的解压路径 #armv7-a API=26 ARCH=arm CPU=armv7-a PREFIX=$(pwd)/android/$CPU TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64 SYSROOT=$NDK/platforms/android-$API/arch-$ARCH CROSS_PREFIX=$TOOLCHAIN/bin/arm-linux-androideabi- build_android
-
设置脚本权限
chmod 777 build_android.sh
-
执行脚本
./build_android.sh
-
检查编译结果
编译完后,在FFmpeg-n4.1.3目录下,会生成android目录,进入目录可以看到armv7-a目录,进入目录会看到如下目录:
-include里就是编译完的头文件;
-lib里就是编译好的.so文件;到这里FFmpeg的源码就编译成功了!!!
Android交叉编译
-
创建Android jni项目
-
复制文件
在项目下创建ffmpeg目录,并创建子目录armeabi-v7a,将之前编好的lib目录下的动态库复制到此目录。
将源码中fftools目录中如图所示的.h.c文件拷贝到ffmpeg目录。
-
修改ffmpeg.h ffmpeg.c cmdutils.h cmdutils.c文件
在ffmpeg.c中找到main函数(在文件最后),将名称改为run,并在头文件中声明该函数。
在cmdutils.h文件中找到"0x%"PRIx64所在的行,在PR前加入一个空格,不然编译会报错。 -
编写jni调用文件
在cpp目录下创建ffmpeg-cmd.cpp文件并编写以下内容:#include <jni.h> #include <string> #include "android/log.h" extern "C" { #include "ffmpeg.h" #include "libavutil/avutil.h" #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libavfilter/avfilter.h" } #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , "ffmpeg-lib", __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , "ffmpeg-lib", __VA_ARGS__) extern "C" JNIEXPORT jint JNICALL Java_com_demo_ffmpeg_FFmpegCmd_run(JNIEnv *env, jclass type, jobjectArray cmd) { int cmdLen = env->GetArrayLength(cmd); char *argCmd[cmdLen] ; jstring buf[cmdLen]; for (int i = 0; i < cmdLen; ++i) { buf[i] = static_cast<jstring>(env->GetObjectArrayElement(cmd, i)); char *string = const_cast<char *>(env->GetStringUTFChars(buf[i], JNI_FALSE)); argCmd[i] = string; LOGD("argCmd=%s",argCmd[i]); } int retCode = run(cmdLen, argCmd); LOGD("ffmpeg-invoke: retCode=%d",retCode); return retCode; }
-
修改CMakeList.txt文件
cmake_minimum_required(VERSION 3.4.1) set(CMAKE_CXX_FLAGS "-std=c++11") include_directories(自己的ndk路径\\sysroot\\usr\\include\\arm-linux-androideabi) include_directories(对应的Ubuntu在windows中的路径(每个人不一样,自己百度)\\FFmpeg-n4.1.3) include_directories(自己项目路径\\app\\src\\main\\cpp\\ffmpeg) #ffmpeg库设置 add_library( avcodec SHARED IMPORTED) set_target_properties( avcodec PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/ffmpeg/${ANDROID_ABI}/libavcodec.so) add_library( avdevice SHARED IMPORTED) set_target_properties( avdevice PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/ffmpeg/${ANDROID_ABI}/libavdevice.so) add_library( avfilter SHARED IMPORTED) set_target_properties( avfilter PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/ffmpeg/${ANDROID_ABI}/libavfilter.so) add_library( avformat SHARED IMPORTED) set_target_properties( avformat PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/ffmpeg/${ANDROID_ABI}/libavformat.so) add_library( avutil SHARED IMPORTED) set_target_properties( avutil PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/ffmpeg/${ANDROID_ABI}/libavutil.so) add_library( swresample SHARED IMPORTED) set_target_properties( swresample PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/ffmpeg/${ANDROID_ABI}/libswresample.so) add_library( swscale SHARED IMPORTED) set_target_properties( swscale PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/ffmpeg/${ANDROID_ABI}/libswscale.so) #本地cpp文件配置 add_library( ffmpeg-cmd SHARED ffmpeg/cmdutils.c ffmpeg/ffmpeg_filter.c ffmpeg/ffmpeg_opt.c ffmpeg/ffmpeg_hw.c ffmpeg/ffmpeg.c ffmpeg-cmd.cpp) find_library( log-lib log) target_link_libraries( ffmpeg-cmd avcodec avdevice avfilter avformat avutil swresample swscale -landroid ${log-lib})
-
修改build.gradle文件
-
创建FFmpegCmd.java文件并写入如下内容:
public class FFmpegCmd { static { System.loadLibrary("avutil"); System.loadLibrary("swresample"); System.loadLibrary("avcodec"); System.loadLibrary("avformat"); System.loadLibrary("swscale"); System.loadLibrary("avfilter"); System.loadLibrary("avdevice"); System.loadLibrary("ffmpeg-cmd"); } public static native int run(String[] cmd); }
-
修改MainActivity如下:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ffmpegTest(); } private void ffmpegTest() { new Thread() { @Override public void run() { long startTime = System.currentTimeMillis(); String input = "/sdcard/mv.mp4"; String output = "/sdcard/output.mp4"; String cmd = "ffmpeg -i %s -ss 00:00:01 -t 00:00:03 %s"; cmd = String.format(cmd, input, output); FFmpegCmd.run(cmd.split(" ")); } }.start(); } }
-
编译运行
在系统的根目录中放一个mv.mp4文件,点击运行开始编译项目,如果一切顺利,在手机里的根目录里会生成output.mp4文件,这个文件是原视频裁剪后得到的。
参考了如下博文:
编译FFmpeg4.1.3并移植到Android app中使用(最详细的FFmpeg-Android编译教程)
文中错误欢迎指正!!!