Obtenir une version x86 de JavaCV pour Android

Xavier Hallade

JavaCV est un wrapper pour les librairies bien connues que sont OpenCV, ffmpeg, et quelques autres. Si ces librairies sont parfaitement compatibles avec les versions x86 d'Android, JavaCV ne propose pour le moment pas leur intégration ni les scripts de compilation adéquats.

Commentez

- Titre : Obtenir une version x86 de JavaCV pour Android

- Auteur : Xavier Hallade

- Parution : 11 février 2014

- Licence : Copyright ® 2014 Xavier Hallade. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Recompiler les cppjars (OpenCV et ffmpeg)

- II. Créer un paquet Android x86 de JavaCV

- III. Ajouter cette version x86 à votre application

- IV. Remerciements

I - Recompiler les cppjars (OpenCV et ffmpeg)

Vous pouvez le faire facilement en réutilisant les scripts de compilation destinés aux versions ARM d'Android. Ces scripts sont fournis dans le paquet officiel :

wget https://javacv.googlecode.com/files/javacv-0.7-cppjars.zip
unzip javacv-0.7-cppjars.zip
cd javacv-cppjars

Les scripts de compilation pour Android sont :

build_opencv-android-arm.sh et build_ffmpeg-android-arm.sh .

Créons donc les équivalents x86 respectifs de ceux-ci :

build_opencv-android-x86.sh et build_ffmpeg-android-x86.sh .

Commencez par reprendre les scripts prévus pour ARM, puis faites ces modifications requises pour utiliser la chaîne de compilation x86 :

- arm-linux-androideabi - par i686-linux-android - (préfixe des binaires de la chaîne de compilation) ;

- arm-linux-androideabi- par x86 - (nom de la chaîne de compilation) ;

- -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mfpu=neon… par -mtune=atom -mssse3 -mfpmath=sse (options de compilation spécifiques à l'architecture) ;

- arm-linux par i686-linux  ;

- et autres suffixes -arm par -x86 .

Ne faites pas tout cela à l'aveugle, cela marchera mieux si vous comprenez ce que vous faites.

Après ces changements, voici ce que j'obtiens pour build_ffmpeg-android-x86.sh  :

ANDROID_BIN=$ANDROID_NDK/toolchains/x86-4.8/prebuilt/linux-x86_64/bin
ANDROID_ROOT=$ANDROID_NDK/platforms/android-14/arch-x86
tar -xjvf ffmpeg-$FFMPEG_VERSION.tar.bz2
mv ffmpeg-$FFMPEG_VERSION ffmpeg-$FFMPEG_VERSION-android-x86
cd ffmpeg-$FFMPEG_VERSION-android-x86
tar -xjvf ../last_stable_x264.tar.bz2
X264=`echo x264-snapshot-*`
cd $X264
./configure --enable-static --enable-pic --disable-cli --disable-opencl --cross-prefix=$ANDROID_BIN/i686-linux-android- --sysroot=$ANDROID_ROOT --host=i686-linux --extra-cflags="-fpic -pipe -DANDROID -DNDEBUG -mtune=atom -mssse3 -ffast-math -mfpmath=sse -fomit-frame-pointer -fstrict-aliasing -funswitch-loops -finline-limit=300" --extra-ldflags="-lm -lz -Wl,--no-undefined -Wl,-z,noexecstack"
make -j8
cd ../
patch -p1 < ../ffmpeg-$FFMPEG_VERSION-android-x86.patch
./configure --prefix=$ANDROID_NDK/../ --enable-shared --enable-gpl --enable-version3 --enable-libx264 \
--disable-static --disable-symver --disable-doc --disable-ffplay --disable-ffmpeg --disable-ffprobe --disable-ffserver --disable-encoders --disable-muxers --disable-devices --disable-demuxer=sbg --disable-demuxer=dts --disable-parser=dca --disable-decoder=dca --disable-decoder=svq3 --enable-network --enable-version3 --disable-amd3dnow --disable-amd3dnowext --disable-outdev=sdl\
--extra-cflags="-I$X264" --extra-ldflags="-L$X264" --enable-cross-compile --cc=$ANDROID_BIN/i686-linux-android-gcc --sysroot=$ANDROID_ROOT --target-os=linux --arch=x86 --cpu=i686 \
--enable-asm --enable-yasm --enable-pic --extra-cflags="-DANDROID -DNDEBUG -fPIC -pipe -mtune=atom -mssse3 -ffast-math -mfpmath=sse" \
--extra-ldflags="-lm -lz -Wl,--no-undefined -Wl,-z,noexecstack" --disable-stripping --disable-symver --disable-programs

make -j8
LIBS="libavcodec/libavcodec.so libavdevice/libavdevice.so libavfilter/libavfilter.so libavformat/libavformat.so libavutil/libavutil.so libpostproc/libpostproc.so libswresample/libswresample.so libswscale/libswscale.so"
$ANDROID_NDK/toolchains/x86-4.8/prebuilt/linux-x86_64/bin/i686-linux-android-strip $LIBS
mkdir -p com/googlecode/javacv/cpp/android-x86/
cp $LIBS com/googlecode/javacv/cpp/android-x86/
jar cvf../ffmpeg-$FFMPEG_VERSION-android-x86.jar com/
rm -Rf com/
cd../

Ici f fmpeg-$FFMPEG_VERSION-android-x86.patch est exactement la même que la version arm, vous pouvez directement la copier.

Et pour build_opencv-android-x86.sh :

tar -xzvf opencv-$OPENCV_VERSION.tar.gz
mkdir opencv-$OPENCV_VERSION/build_android-x86
cd opencv-$OPENCV_VERSION
cd build_android-x86
ANDROID_BIN=$ANDROID_NDK/toolchains/x86-4.6/prebuilt/linux-x86_64/bin/ \
ANDROID_CPP=$ANDROID_NDK/sources/cxx-stl/gnu-libstdc++/4.6/ \
ANDROID_ROOT=$ANDROID_NDK/platforms/android-9/arch-x86/ \
cmake -DCMAKE_TOOLCHAIN_FILE=platforms/android/android.toolchain.cmake -DANDROID_ABI=x86 -DOPENCV_EXTRA_C_FLAGS="-O3 -ffast-math -mtune=atom -mssse3 -mfpmath=sse" -DOPENCV_EXTRA_CXX_FLAGS="-O3 -ffast-math -mtune=atom -mssse3 -mfpmath=sse" -DCMAKE_INSTALL_PREFIX=$ANDROID_NDK/../ -DBUILD_SHARED_LIBS=ON -DBUILD_TESTS=OFF -DBUILD_PERF_TESTS=OFF -DBUILD_ANDROID_EXAMPLES=OFF -DBUILD_JASPER=ON -DBUILD_JPEG=ON -DBUILD_OPENEXR=ON -DBUILD_PNG=ON -DBUILD_TBB=ON -DBUILD_TIFF=ON -DBUILD_ZLIB=ON -DBUILD_opencv_java=OFF -DBUILD_opencv_python=OFF -DENABLE_PRECOMPILED_HEADERS=OFF -DWITH_1394=OFF -DWITH_FFMPEG=OFF -DWITH_GSTREAMER=OFF -DWITH_TBB=ON -DWITH_CUDA=OFF -DWITH_OPENCL=OFF..
make -j8
LIBS="lib/x86/libopencv*.so lib/x86/libtbb.so"
$ANDROID_NDK/toolchains/x86-4.6/prebuilt/linux-x86_64/bin/i686-linux-android-strip $LIBS
mkdir -p com/googlecode/javacv/cpp/android-x86/
cp $LIBS com/googlecode/javacv/cpp/android-x86/
jar cvf../../opencv-$OPENCV_VERSION-android-x86.jar com/
rm -Rf com/
cd../../

Ici, j'ai supprimé l'application du patch -arm qui générait un nouveau fichier android.mk pour directement utiliser celui présent dans platforms/android/android.toolchain.cmake , qui fait partie des sources OpenCV. J'ai aussi ajouté des options de compilation spécifiques pour générer un code plus optimisé :

-DANDROID_ABI=x86 -DOPENCV_EXTRA_C_FLAGS="-O3 -ffast-math -mtune=atom -mssse3 -mfpmath=sse" -DOPENCV_EXTRA_CXX_FLAGS="-O3 -ffast-math -mtune=atom -mssse3 -mfpmath=sse"

Maintenant si vous appelez :

sh./build_all.sh android-x86
cd..

Cela vous générera ffmpeg-2.1.1-android-x86.jar et opencv-2.4.8-android-x86.jar .

Vous pouvez maintenant créer le paquet JavaCV.

II - Créer un paquet Android x86 de JavaCV

Commencez par récupérer et installer JavaCPP :

git clone https://code.google.com/p/javacpp/
cd javacpp/
git checkout 0.6
mvn install
cd..

Une fois cela fait, téléchargez les sources de JavaCV :

git clone https://code.google.com/p/javacv/
cd javacv
git checkout 0.7

Vous pouvez maintenant créer le paquet android-x86, en passant la propriété « android-x86 » à javacpp :

mvn package -Pffmpeg -Djavacpp.options="-properties android-x86 -Dplatform.root=$ANDROID_NDK -Dcompiler.path=$ANDROID_NDK/toolchains/x86-4.6/prebuilt/linux-x86_64/bin/i686-linux-android-g++ -Dcompiler.includepath=$ANDROID_NDK/sources/cxx-stl/gnu-libstdc++/4.6/include\
:$ANDROID_NDK/sources/cxx-stl/gnu-libstdc++/4.6/libs/x86/include\
:../javacv-cppjars/opencv-2.4.8/build_android-x86/\
:../javacv-cppjars/opencv-2.4.8/modules/core/include\
:../javacv-cppjars/opencv-2.4.8/modules/androidcamera/include\
:../javacv-cppjars/opencv-2.4.8/modules/flann/include\
:../javacv-cppjars/opencv-2.4.8/modules/imgproc/include\
:../javacv-cppjars/opencv-2.4.8/modules/highgui/include\
:../javacv-cppjars/opencv-2.4.8/modules/features2d/include\
:../javacv-cppjars/opencv-2.4.8/modules/calib3d/include\
:../javacv-cppjars/opencv-2.4.8/modules/ml/include\
:../javacv-cppjars/opencv-2.4.8/modules/video/include\
:../javacv-cppjars/opencv-2.4.8/modules/legacy/include\
:../javacv-cppjars/opencv-2.4.8/modules/objdetect/include\
:../javacv-cppjars/opencv-2.4.8/modules/photo/include\
:../javacv-cppjars/opencv-2.4.8/modules/gpu/include\
:../javacv-cppjars/opencv-2.4.8/modules/nonfree/include\
:../javacv-cppjars/opencv-2.4.8/modules/contrib/include\
:../javacv-cppjars/opencv-2.4.8/modules/stitching/include\
:../javacv-cppjars/opencv-2.4.8/modules/ts/include\
:../javacv-cppjars/opencv-2.4.8/modules/videostab/include\
:../javacv-cppjars/ffmpeg-2.1.1-android-x86 \
-Dcompiler.linkpath=$ANDROID_NDK/sources/cxx-stl/gnu-libstdc++/4.6/libs/x86\
:../javacv-cppjars/opencv-2.4.8/build_android-x86/lib/x86\
:../javacv-cppjars/ffmpeg-2.1.1-android-x86/libswscale\
:../javacv-cppjars/ffmpeg-2.1.1-android-x86/libavcodec\
:../javacv-cppjars/ffmpeg-2.1.1-android-x86/libswresample\
:../javacv-cppjars/ffmpeg-2.1.1-android-x86/libpostproc\
:../javacv-cppjars/ffmpeg-2.1.1-android-x86/libavfilter\
:../javacv-cppjars/ffmpeg-2.1.1-android-x86/libavformat\
:../javacv-cppjars/ffmpeg-2.1.1-android-x86/libavutil\
:../javacv-cppjars/ffmpeg-2.1.1-android-x86/libavdevice"

Cela produira dans target/ :

2.7M Jan 15 19:09 javacv-android-x86.jar
3.6M Jan 15 19:09 javacv-bin.zip
747K Jan 15 19:09 javacv-src.zip
734K Jan 15 19:09 javacv.jar

III - Ajouter cette version x86 à votre application

En utilisant les paquets que vous venez de générer (ou télécharger), vous pouvez maintenant copier tous les fichiers.so générés, qui sont dans javacv-android-x86.jar , ffmpeg-2.1.1-android-x86.jar et opencv-2.4.8-android-x86.jar dans le répertoire /libs/x86/ de votre projet d'application Android, de la même manière que la version arm dans /libs/armeabi-v7a/ .

Pour obtenir plus d'informations sur comment gérer les différents fichiers.so dans les APKs, vous pouvez vous référer à ces deux précédents articles :

https://intel.developpez.com/tutoriels/android/integration-fichier-so-ndk-android-studio-gradle/ ;

https://intel.developpez.com/tutoriels/android/apprendre-ameliorer-support-application-librairie-x86/ .

IV - Remerciements

Merci à Intel Developer Zoneet à Xavier Hallade pour la rédaction de ce tutoriel.
Retrouvez le Blog de Xavier Hallade Software Engineer chez Intel. Pour toute question, merci de contacter Slim Soussi, EMEA Program Manager chez Intel.