ffmpeg編譯的文章很多了,理論上沒必要寫了,可是架不住Android Studio在不斷升級(jí),Android Studio 3.3.1版本,這個(gè)版本不允許你只編譯arm版本的so庫了,所以這個(gè)文章目標(biāo)編譯armv7-a。
為什么要編譯armv7-a,百度吧,為了apk大小和兼容性,放armv7-a比較合適。
ndk 是android-ndk-r14b 從NDK r18b開始刪除了gcc,用clang替換了,所以用這套腳本是不能成功的,最后一個(gè)支持gcc的版本是r17c。(18開始gcc被刪除用一個(gè)腳本替換指向到了llvm目錄下的clang,由于這個(gè)兼容腳本沒用19就刪除掉了)
后續(xù)更新:使用r20b來編譯,請(qǐng)拉到本文最后。
android-ndk-r14b 放到/usr/ndk/android-ndk-r14b,修改權(quán)限。
在FFMPEG-3.4.5目錄下新建build_android.sh,改可執(zhí)行。
#!/bin/bash
# 設(shè)置NDK路徑
NDK=/usr/ndk/android-ndk-r14b
# 設(shè)置編譯針對(duì)的平臺(tái),可以根據(jù)實(shí)際需求進(jìn)行設(shè)置
# 當(dāng)前設(shè)置為最低支持android-14版本,arm架構(gòu)
SYSROOT=$NDK/platforms/android-14/arch-arm
# 設(shè)置編譯工具鏈,4.9為版本號(hào)
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
function build_one
{
./configure \
--enable-cross-compile \
--enable-shared \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-avdevice \
--disable-doc \
--disable-symver \
--prefix=$PREFIX \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--target-os=android \
--arch=arm \
--sysroot=$SYSROOT \
--extra-cflags="-Os -fpic $ADDI_CFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make
make install
}
# 設(shè)置編譯后文件的輸出目錄
CPU=armv7-a
PREFIX=$(pwd)/android/$CPU
ADDI_CFLAGS="-march=armv7-a -mfloat-abi=softfp -mfpu=neon"
build_one
后面就可以用這個(gè)腳本編譯了,編譯20分鐘左右,看你的CPU速度了,多核cpu的可以把倒數(shù)第8行的make 改make -j4 多進(jìn)程跑,加速。
這個(gè)里面比較容易出錯(cuò)的地方就是,如果你按網(wǎng)上以前的教程,那些教程都是教你編譯arm版本的,機(jī)械替換arm到armv7-a 是不能成功的,關(guān)鍵就在于 --extra-cflags里ADDI_CFLAGS 這個(gè)flag的設(shè)置,設(shè)置好了就可以編譯成功,在當(dāng)前目錄下的android里,腳本已經(jīng)設(shè)置過了,所以只有so、頭文件、例子。

CPP下新建inlude把頭文件拷貝過來,新建jniLibs/armeabi-v7a把so拷貝過來。
還是android studio 3.3.1的改動(dòng),CMakeLists改到CPP目錄下了,所以層級(jí)目錄就是以cpp為工程目錄,又是一個(gè)坑人的地方。
# 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)
set(JNI_LIBS_DIR ${CMAKE_SOURCE_DIR}/../jniLibs)
message("JNI_LIBS_DIR:"${JNI_LIBS_DIR})
add_library(avutil
SHARED
IMPORTED)
set_target_properties(avutil
PROPERTIES IMPORTED_LOCATION
${JNI_LIBS_DIR}/${ANDROID_ABI}/libavutil.so)
add_library(swresample
SHARED
IMPORTED)
set_target_properties(swresample
PROPERTIES IMPORTED_LOCATION
${JNI_LIBS_DIR}/${ANDROID_ABI}/libswresample.so)
add_library(swscale
SHARED
IMPORTED)
set_target_properties(swscale
PROPERTIES IMPORTED_LOCATION
${JNI_LIBS_DIR}/${ANDROID_ABI}/libswscale.so)
add_library(avcodec
SHARED
IMPORTED)
set_target_properties(avcodec
PROPERTIES IMPORTED_LOCATION
${JNI_LIBS_DIR}/${ANDROID_ABI}/libavcodec.so)
add_library(avformat
SHARED
IMPORTED)
set_target_properties(avformat
PROPERTIES IMPORTED_LOCATION
${JNI_LIBS_DIR}/${ANDROID_ABI}/libavformat.so)
add_library(avfilter
SHARED
IMPORTED)
set_target_properties(avfilter
PROPERTIES IMPORTED_LOCATION
${JNI_LIBS_DIR}/${ANDROID_ABI}/libavfilter.so)
include_directories(./include)
aux_source_directory(. NATIVE_SRC)
# Creates and names a library, sets it as either STATIC
# 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).
# native-lib.cpp)
${NATIVE_SRC})
# 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)
find_library(android-lib
android )
# 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
avutil
swresample
swscale
avcodec
avformat
avfilter
${android-lib}
# Links the target library to the log library
# included in the NDK.
${log-lib})
CMakeLists 的內(nèi)容如上
native-lib.cpp
導(dǎo)入
extern "C" {
#include "include/libavcodec/avcodec.h"
#include "include/libavfilter/avfilter.h"
#include "include/libswscale/swscale.h"
#include "include/libavformat/avformat.h"
#include "include/libavutil/avutil.h"
#include "include/libswresample/swresample.h"
}
activity里導(dǎo)入庫
companion object {
// Used to load the 'native-lib' library on application startup.
init {
System.loadLibrary("native-lib")
}
}
還有一個(gè)設(shè)置,指定模塊只編譯armeabi-v7a,因?yàn)槲覀兙幾g的native-lib依賴的so都是arm-v7a格式的,在XXX.gradle設(shè)置。
defaultConfig {
//skip
externalNativeBuild {
cmake {
cppFlags "-std=c++11"
}
ndk {
abiFilters 'armeabi-v7a'
}
}
}
主要是講和以前版本的不同,看不懂請(qǐng)找?guī)讉€(gè)老版本的參考,有一些博客明明編譯的是arm版本,直接集成到armv7a里使用,我也不確定這樣有沒有問題,v7a的體積會(huì)相對(duì)小一點(diǎn),也是個(gè)優(yōu)點(diǎn)了。
更新NDK r20B的編譯方法
在17之后,18開始就刪除了gcc,上面的腳本指定到gcc編譯器是沒有用的。
18的gcc編譯器,是一個(gè)指向clang的腳本,根本沒用,在19干脆就刪掉了這個(gè)腳本。
18和19的clang編譯器那邊結(jié)構(gòu)還不一樣,clang需要指定編譯器的腳本名,因?yàn)槟_本是由platform+后綴+api版本來編寫的,所以還是直接用最新的20b版本好了,使用18版本需要你自己配bulid腳本。
總結(jié):要么17c使用gcc編譯,要么直接20b配clang,別搞18版本浪費(fèi)時(shí)間
換了R20B后發(fā)現(xiàn),再編譯3.3.1有編譯錯(cuò)誤了,可能是需要更新ffmpeg版本了,測(cè)試了一下3.4.7、4.1都是可以的。直接上腳本了,clang需要配置的就是cc、ld、cxx這3個(gè)在config的默認(rèn)腳本里是用cross-prefix做前綴,需要修改名字。
這是由于,在/usr/ndk/android-ndk-r20b/toolchains/llvm/prebuilt/linux-x86_64/bin
目錄里起名相當(dāng)混亂
-rwxr-xr-x 1 jack jack 187 10月 17 15:43 aarch64-linux-android21-clang*
-rwxr-xr-x 1 jack jack 191 10月 17 15:43 aarch64-linux-android21-clang++*
...
-rwxr-xr-x 1 jack jack 817728 10月 17 15:34 arm-linux-androideabi-addr2line*
-rwxr-xr-x 1 jack jack 845832 10月 17 15:34 arm-linux-androideabi-ar*
-rwxr-xr-x 1 jack jack 1436624 10月 17 15:34 arm-linux-androideabi-as*
...
-rwxr-xr-x 1 jack jack 190 10月 17 15:43 armv7a-linux-androideabi16-clang*
-rwxr-xr-x 1 jack jack 194 10月 17 15:43 armv7a-linux-androideabi16-clang++*
...
-rwxr-xr-x 1 jack jack 199 10月 17 15:43 i686-linux-android16-clang*
-rwxr-xr-x 1 jack jack 203 10月 17 15:43 i686-linux-android16-clang++*
clang的名字是用PLATFORM+api+clang,負(fù)責(zé)clang和clang++的腳本名
但是cross-prefix又是$ARCH-linux-androideabi,負(fù)責(zé)剩下的通用編譯工具名
都要對(duì)應(yīng)好,都不能出錯(cuò)。
--ld=$TOOLCHAIN/$TARGET$API-clang
這行沒有錯(cuò)。
最后記得make install
#!/bin/bash
export NDK=/usr/ndk/android-ndk-r20b
export API=21
# arm aarch64 i686 x86_64
export ARCH=arm
# armv7a aarch64 i686 x86_64
export PLATFORM=armv7a
export TARGET=$PLATFORM-linux-androideabi
export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin
#正確的sysroot
export SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
export CPU=$PLATFORM
export PREFIX=./android/armeabi-v7a2
export CFLAG="-D__ANDROID_API__=$API -Os -fPIC -DANDROID "
./configure \
--prefix=$PREFIX \
--cc=$TOOLCHAIN/$TARGET$API-clang \
--ld=$TOOLCHAIN/$TARGET$API-clang \
--cxx=$TOOLCHAIN/$TARGET$API-clang++ \
--target-os=android \
--arch=$ARCH \
--cpu=$PLATFORM \
--cross-prefix=$TOOLCHAIN/$ARCH-linux-androideabi- \
--disable-asm \
--enable-cross-compile \
--enable-shared \
--disable-doc \
--enable-runtime-cpudetect \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-decoders \
--disable-encoders \
--disable-devices \
--enable-gpl --enable-nonfree --enable-version3 --disable-iconv \
--enable-jni \
--enable-mediacodec \
--disable-decoders --enable-decoder=vp9 --enable-decoder=h264 --enable-decoder=mpeg4 --enable-decoder=aac \
--disable-encoders --enable-encoder=vp9_vaapi --enable-encoder=h264_nvenc --enable-encoder=h264_v4l2m2m --enable-encoder=hevc_nvenc \
--disable-demuxers --enable-demuxer=rtsp --enable-demuxer=rtp --enable-demuxer=flv --enable-demuxer=h264 \
--disable-muxers --enable-muxer=rtsp --enable-muxer=rtp --enable-muxer=flv --enable-muxer=h264 \
--disable-parsers --enable-parser=mpeg4video --enable-parser=aac --enable-parser=h264 --enable-parser=vp9 \
--disable-protocols --enable-protocol=rtmp --enable-protocol=rtp --enable-protocol=tcp --enable-protocol=udp \
--disable-bsfs \
--disable-indevs \
--disable-outdevs \
--disable-filters \
--disable-postproc \
--sysroot=$SYSROOT \
--extra-cflags="$CFLAG" \
--extra-ldflags=""