當(dāng)我們需要使用opencv在android設(shè)備上進(jìn)行讀取和寫入結(jié)果視頻的時(shí)候蚜厉,需要使用視頻的解碼器。默認(rèn)opencv不帶解碼器。一般借助于ffmpeg第三方模塊惋耙。ffmpeg又依賴x264或者x265模塊乱陡。單獨(dú)編譯比較費(fèi)勁浇揩,使用以下腳本快速編譯:
以下編譯是aarch64位的版本,32位類似處理憨颠;
opencv版本是4.5.1
#!/bin/sh
BASE=`pwd`
BUILD_HOST=aarch64-linux-android
OUTPUT_PATH=${BASE}/aarch64-install
OTHER_LIB=${OUTPUT_PATH}/all_without_ffmpeg
set_env(){
export CROSS_COMPILE=/home/yw/android-toolchain_64/bin/aarch64-linux-android-
AS=${CROSS_COMPILE}as
AR=${CROSS_COMPILE}ar
NM=${CROSS_COMPILE}nm
CC=${CROSS_COMPILE}gcc
GG=${CROSS_COMPILE}g++
CXX=${CROSS_COMPILE}c++
LD=${CROSS_COMPILE}ld
RANLIB=${CROSS_COMPILE}ranlib
STRIP=${CROSS_COMPILE}strip
export AS AR NM CC GG LD RANLIB STRIP
export PATH=$PATH:/home/yw/android-toolchain_64/bin
}
make_dirs () {
#為了方便管理胳徽,創(chuàng)建有關(guān)的目錄
cd ${BASE} && mkdir compressed aarch64-install source -p
}
tget () { #try wget
filename=`basename $1`
echo "Downloading [${filename}]..."
if [ ! -f ${filename} ];then
wget $1
fi
echo "[OK] Downloaded [${filename}] "
}
download_package () {
cd ${BASE}/compressed
tget https://code.videolan.org/videolan/x264/-/archive/master/x264-master.tar.bz2
tget https://ffmpeg.org/releases/ffmpeg-4.4.2.tar.gz
tget http://download.videolan.org/videolan/x265/x265_3.2.tar.gz
}
tar_package () {
cd ${BASE}/compressed
ls * > /tmp/list.txt
for TAR in `cat /tmp/list.txt`
do
tar -xf $TAR -C ../source
done
rm -rf /tmp/list.txt
}
make_x264() {
cd ${BASE}/source/x264*
./configure \
--prefix=${OUTPUT_PATH}/x264 \
--host=${BUILD_HOST} \
--enable-shared \
--enable-static \
--enable-pic \
--disable-asm
make -j8 && make install
}
make_x265() {
cd ${BASE}/source/x265*/build
mkdir arm-x265
cd arm-x265
# 獲取 工具鏈所在位置
GCC_FULL_PATH=`whereis ${BUILD_HOST}-gcc | awk -F: '{ print $2 }' | awk '{print $1}'` # 防止多個(gè)結(jié)果
CROSS_PATH=`dirname ${GCC_FULL_PATH}`
touch crosscompile.cmake
#echo "set(CROSS_COMPILE_ARM 1)" > crosscompile.cmake
echo "set(CMAKE_SYSTEM_NAME Linux)" > crosscompile.cmake
echo "set(CMAKE_SYSTEM_PROCESSOR aarch64)" >> crosscompile.cmake
echo "" >> crosscompile.cmake
echo "# specify the cross compiler" >> crosscompile.cmake
echo "set(CMAKE_C_COMPILER ${CROSS_PATH}/${BUILD_HOST}-gcc)" >> crosscompile.cmake
echo "set(CMAKE_CXX_COMPILER ${CROSS_PATH}/${BUILD_HOST}-g++)" >> crosscompile.cmake
echo "set(CMAKE_SHARED_LINKER_FLAGS \"-ldl \${CMAKE_SHARED_LINKER_FLAGS}\")" >> crosscompile.cmake
echo "" >> crosscompile.cmake
echo "# specify the target environment" >> crosscompile.cmake
echo "SET(CMAKE_FIND_ROOT_PATH ${CROSS_PATH})" >> crosscompile.cmake
# 編譯安裝
cmake -DCMAKE_TOOLCHAIN_FILE=crosscompile.cmake -G "Unix Makefiles" \
-DCMAKE_C_FLAGS="-fPIC ${CMAKE_C_FLAGS}" -DCMAKE_CXX_FLAGS="-fPIC ${CMAKE_CXX_FLAGS}" \
-DCMAKE_SHARED_LINKER_FLAGS="-ldl ${CMAKE_SHARED_LINKER_FLAGS}" \
-DCMAKE_INSTALL_PREFIX=${OUTPUT_PATH}/x265 \
../../source && make -j8
make install
}
prepare_other_lib () {
# 這一個(gè)是針對(duì) ffmpeg 方便管理外部庫(kù)使用的
# 核心思想是把 所有的庫(kù)都放到一起积锅,再讓 ffmpeg ld的時(shí)候在這里找(而不是添加多行) --extra-cflags="-I${X264_DIR}/include -I${xxx}/include" \
cd ${BASE}/aarch64-install/
rm ${OTHER_LIB} -rf
ls > /tmp/list.txt
mkdir ${OTHER_LIB} -p
for sub_dir in `cat /tmp/list.txt`
do
cp ${sub_dir}/* ${OTHER_LIB} -r -v
done
rm -rf /tmp/list.txt
}
make_ffmpeg() {
MYPKGCONFIG=${BASE}/aarch64-install/x265/lib/pkgconfig/
export PKG_CONFIG_PATH=${MYPKGCONFIG}:$PKG_CONFIG_PATH
cd ${BASE}/source/ffmpeg*
./configure \
--prefix=${OUTPUT_PATH}/ffmpeg \
--enable-cross-compile \
--cross-prefix=${BUILD_HOST}- \
--arch=aarch64 \
--host-os=linux \
--target-os=android \
--cc=${BUILD_HOST}-gcc \
--enable-shared \
--enable-static \
--enable-pic \
--enable-gpl \
--enable-nonfree \
--enable-ffmpeg \
--enable-swscale \
--enable-libx264 \
--enable-libx265 \
--enable-decoder=hevc \
--enable-ffplay \
--disable-stripping \
--disable-doc --disable-debug --disable-iconv --disable-armv5te --disable-armv6 --disable-armv6t2 \
--pkg-config="pkg-config --static" \
--extra-cflags=-I${OTHER_LIB}/include \
--extra-ldflags=-L${OTHER_LIB}/lib
make -j8 && make install
}
echo "Using ${BUILD_HOST}-gcc"
make_dirs
download_package
tar_package
set_env
make_x264
make_x265
prepare_other_lib
make_ffmpeg
注意:x265選擇性編譯,可以不包含進(jìn)去养盗,只保留x264編譯即可缚陷。
上面腳本如果編譯x265存在編譯報(bào)錯(cuò)找不到pthread庫(kù),在android交叉編譯時(shí)需要在CMakeLists.txt中去掉pthread庫(kù)往核,其他Linux交叉編譯沒(méi)有此問(wèn)題箫爷。
參考鏈接
opencv編譯腳本如下:
OPENCV_ROOT="${WD}"
N_JOBS=48
INSTALL_DIR="${WD}/build_android"
rm -rf "${INSTALL_DIR}"
### Make each ABI target iteratly and sequentially
for i in "${ANDROID_ABI_LIST[@]}"
do
ANDROID_ABI="${i}"
echo "Start building ${ANDROID_ABI} version"
if [ "${ANDROID_ABI}" = "armeabi" ]; then
API_LEVEL=21
else
API_LEVEL=21
fi
temp_build_dir="${OPENCV_ROOT}/platforms/build_android_${ANDROID_ABI}"
### Remove the build folder first, and create it
rm -rf "${temp_build_dir}"
mkdir -p "${temp_build_dir}"
cd "${temp_build_dir}"
echo ${INSTALL_DIR}
cmake \
-DCMAKE_MAKE_PROGRAM=/usr/bin/make \
-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \
-DCMAKE_TOOLCHAIN_FILE=${NDK_ROOT}/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=${ANDROID_ABI} \
-DANDROID_STL=c++_static \
-DCMAKE_BUILD_TYPE=Release \
-DANDROID_NATIVE_API_LEVEL=${API_LEVEL} \
-DCMAKE_BUILD_TYPE=Release \
-DWITH_FFMPEG=ON \
-D BUILD_opencv_java=ON \
-D BUILD_ANDROID_PROJECTS=OFF \
-D WITH_CUDA=OFF \
-D WITH_MATLAB=OFF \
-D BUILD_ANDROID_EXAMPLES=OFF \
-D BUILD_DOCS=OFF \
-D BUILD_PERF_TESTS=OFF \
-D BUILD_TESTS=OFF \
-D BUILD_SHARED_LIBS=ON \
-D BUILD_TIFF=ON \
-D BUILD_PNG=ON \
-D OPENCV_GENERATE_PKGCONFIG=ON \
-D OPENCV_FFMPEG_USE_FIND_PACKAGE=ON \
-D OPENCV_FFMPEG_SKIP_BUILD_CHECK=ON \
-DFFMPEG_DIR=/home/yw/opensource/ffmpeg+h264/aarch64-install/ffmpeg \
-DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \
-DANDROID_SDK=${SDK_ROOT} \
../..
# Build it
make -j${N_JOBS}
# Install it
make install/strip
### Remove temp build folder
cd "${WD}"
rm -rf "${temp_build_dir}"
echo "end building ${ANDROID_ABI} version"
done
遇到問(wèn)題:opencv無(wú)法找到我們自己編譯的ffmpeg,參考如下:
??opencv+ffmpeg編譯打包全解指南 - 知乎 (zhihu.com)