這幾天的開發任務是編寫Android 4.4以上的視頻處理模塊。由于MediaCodec及MediaExtrator的NDK接口只有Android 5.0以上才有,故使用FFmpeg解析MP4文件。
當然,也可以像ijkplayer一樣,把Java層的接口在JNI_OnLoad函數中映射到C/C++運行環境,這反而維護起來更復雜,暫不考慮。
編譯FFmpeg(最新版本為3.2.2)64及32位動態庫時遇到不少問題,在此一一描述,相關工作環境:
- 宿主機:Ubuntu 14
- NDK 13
- 調用設備:Nexus 6p(Android 6.0)
- FFmpeg源碼版本:3.2.2
結論:編譯成armeabi動態庫可正常使用,其余在CMakeList或gradle中都存在編譯問題。具體原因留待進一步了解。
參考編譯腳本:
#!/bin/bash
NDK=$HOME/Android/Sdk/ndk-bundle
SYSROOT=$NDK/platforms/android-21/arch-arm64/
TOOLCHAIN=$NDK/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64
ARCH=aarch64
function build_one
{
./configure \
--prefix=$PREFIX \
--disable-debug \
--disable-shared \
--enable-static \
--enable-pthreads \
--enable-pic \
--enable-asm \
--enable-version3 \
--enable-gpl \
--disable-muxers \
--enable-muxer=mp4 \
--disable-protocols \
--enable-protocol=file \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-avdevice \
--disable-programs \
--disable-network \
--disable-swresample \
--disable-avresample \
--disable-avfilter \
--disable-swscale \
--disable-postproc \
--disable-doc \
--disable-symver \
--disable-encoders \
--disable-decoders \
--enable-decoder=h264 \
--disable-muxers \
--enable-muxer=mp4 \
--disable-parsers \
--enable-parser=h264 \
--disable-devices \
--disable-filters \
--disable-iconv \
--disable-audiotoolbox \
--disable-videotoolbox \
--enable-yasm \
--disable-hwaccels \
--cross-prefix=$TOOLCHAIN/bin/aarch64-linux-android- \
--target-os=linux \
--arch=$ARCH \
--enable-cross-compile \
--sysroot=$SYSROOT \
--extra-cflags="-DANDROID -O3 -fpic"
make clean
make
make install
}
CPU=$ARCH
PREFIX=$(pwd)/android/$CPU
build_one
從腳本上看,最終要編譯的是64位ARM靜態庫。另外,有些編譯腳本配置禁用nasm,在FFmpeg3.2.2的編譯中存在如下錯誤提示,需改成yasm。
嘗試一:可成功編譯64位靜態庫,CMakeList中導入對應的靜態庫出現鏈接失敗,相應靜態庫并沒被拷貝到apk中,修改gradle配置也無效。
值得注意的是,平臺需要21以上才有64位交叉編譯鏈。感謝@大牙的提醒,開始我用android-19,找不到arch-arm64子目錄。
SYSROOT=$NDK/platforms/android-21/arch-arm64/
嘗試二:編譯64位動態庫失敗。經多次修改編譯腳本,禁用各種協議、編解碼器,始終出現文件格式錯誤,如下所示。
有時能編譯到生成libutil才報錯。
另外,編譯動態庫時提示pthread、啟用pic等找不到,而編譯靜態庫則無pthread找不到提示。
config.log中雖然提示UCLIBC等條件不滿足錯誤,并不影響32位動態庫的正常編譯,而64位也能繼續編譯流程,可以認為也不受此影響。
對此問題,部分博客提示配置上-llibc
,在FFmpeg3.2.2的編譯中,這是無效的。
最后,雖然編譯成功,但是CMake鏈接時還是提示文件格式錯誤,如下圖所示。
這里存在的疑問是CMake使用了linux-x84_64目錄下的clang++,而不像我們在FFmpeg編譯腳本中指定為aarch64-linux-android-4.9目錄。因對CMake不了解,留待進一步嘗試。
嘗試三:編譯32位armeabi-v7a動態庫。雖然指定arch為arm-v7a或armeabi-v7a,然而,最終編譯得到的靜態庫通過讀取文件CPU架構信息都顯示是v5TE,和armeabi一樣。
readelf -A your.so