1.文章介绍
最近在业务扩展方面需要接触FFMPEG,借此机会学习点FFMPEG知识,由于大部分工作时间和Android应用层,Framework层和芯片SDK层打交道,自然而然看到JavaCpp这种能提高工作效率的框架,两眼发亮并想可以做些什么,这就是写本篇文章的缘由。
另外,了解JavaCpp的同学应该也有不少,但我自己搜在Android上使用的相关教程却很少很少,于是就自己从零开始记录下实战作为参考。
如网上说的做FFMPEG的人分为两种:一种是懂些皮毛,指令,却没有很好的入门学习方法的开发者;一种是熟悉FFMPEG各个模块,并且可以按照业务需求优化和扩展的大神。我只是第一种,甚至还算不上第一种。
2.干货
1.编译准备过程
1.环境搭建
Ubuntu16.04
Ubuntu的搭建这里就不作介绍了,主要是需要配置好网络环境,Maven编译过程中会根据pom.xml中的依赖去中央仓库下载对应的依赖库,本文使用的是ubuntu-16.04-desktop-amd64.iso
JDK环境配置
下载如 jdk-7u45-linux-x64.tar.gz
解压后jdk库文件后,配置jdk环境:
vim /etc/environment
添加以下代码:
update-alternatives --install /usr/bin/java java /usr/lib/jvm/java/jdk1.7.0_45/bin/java 300
update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/java/jdk1.7.0_45/bin/javac 300
update-alternatives --install /usr/bin/jar jar /usr/lib/jvm/java/jdk1.7.0_45/bin/jar 300
update-alternatives --config java
update-alternatives --config javac
update-alternatives --config jar
或通过配置环境变量命令:
$sudo gedit ~/.bashrc
添加以下代码:
export JAVA_HOME=/usr/lib/jvm/java/jdk1.7.0_45
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH
通过以下指令校验jdk信息:
java -version
maven 3.0 or laster
sudo apt-get install maven
安装完后查看版本是否达到要求,如果版本比较低建议去官网下载对应版本后手动配置安装
mvn -v
maven版本信息
cmake 2.8.8 or laster
sudo apt-get install cmake
安装完后查看版本是否达到要求,如果版本比较低建议去官网下载对应版本后手动配置安装
cmake --version
cmake版本信息
svn安装
sudo apt-get install subversion
2.javacpp的下载和编译:
1.我选择了tag版本,tag版本应该稳定些
在github上找到对应tag版本地址:
复制项目地址,然后下载对应源码:
个人习惯问题,我使用的是svn,先去Repository svn地址:
然后选择tag的svn地址checkout:
svn checkout https://github.com/bytedeco/javacpp.git/tags/1.3.3 /home/yang/share/javacpp-133
源码下载成功后,就可以通过Maven编译了(前提是安装了Maven,未安装的可以根据提示sudo apt-get install maven安装),在下载代码的根目录下执行编译:
mvn install
编译成功后的target目录:
其中:
javacpp.jar是javacpp核心文件,可以说是java-cpp联系的桥梁,处理jar到so的接口实现
javacpp-javadoc.jar是javacpp api doc文件
javacpp-source.jar是对src目录的编译文件暂时不清楚用途
3.javacpp-ffmpeg的下载和编译:
javacpp-ffmpeg的源码在javacpp-presets下:
https://github.com/bytedeco/javacpp-presets
同样的也是选择了tag版本,使用svn下载代码:
svn checkout https://github.com/bytedeco/javacpp-presets.git/tags/1.3 /home/yang/share/javacpp-presets-13
如果选择的是Android版本的编译,需要先准备NDK环境,否则编译过程中会因为找不到NDK配置而导致中断:
从javacpp_presets根目录的cppbuild.sh中可以看到以下源码
if [[ -z ${OPERATION:-} ]]; then
echo "Usage: ANDROID_NDK=/path/to/android-ndk/ bash cppbuild.sh [-platform <name>] <install | clean> [projects]"
echo "where possible platform names are: android-arm, android-x86, linux-x86, linux-x86_64, macosx-x86_64, windows-x86, windows-x86_64, etc."
exit 1
fi
if [[ -z ${ANDROID_NDK:-} ]]; then
ANDROID_NDK=~/Android/android-ndk/
fi
export ANDROID_NDK
export ANDROID_CPP="$ANDROID_NDK/sources/cxx-stl/gnu-libstdc++/4.9/"
case $PLATFORM in
android-x86)
export ANDROID_BIN="$ANDROID_NDK/toolchains/x86-4.9/prebuilt/$KERNEL-$ARCH/bin/i686-linux-android"
export ANDROID_ROOT="$ANDROID_NDK/platforms/android-14/arch-x86/"
;;
*)
export ANDROID_BIN="$ANDROID_NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/$KERNEL-$ARCH/bin/arm-linux-androideabi"
export ANDROID_ROOT="$ANDROID_NDK/platforms/android-14/arch-arm/"
;;
esac
而从javacpp_presets根目录的pom.xml中可以看到这样的源码:
<profile>
<id>android-arm-default</id>
<activation>
<property>
<name>javacpp.platform</name>
<value>android-arm</value>
</property>
</activation>
<properties>
<javacpp.platform>android-arm</javacpp.platform>
<javacpp.platform.root>${user.home}/Android/android-ndk/</javacpp.platform.root>
<javacpp.platform.compiler>toolchains/arm-linux-androideabi-4.9/prebuilt/${os.name}-${os.arch}/bin/arm-linux-androideabi-g++</javacpp.platform.compiler>
</properties>
</profile>
因此,可以下载android-ndk-r14b-linux-x86_64.zip,并且配置NDK环境为/root/Android/android-ndk:
ndk配置路径
编译环境准备好后,即可在javacpp_presets根目录用以下指令开始编译:
mvn install -Pandroid-arm-default --projects ffmpeg -X
编译过程中某些依赖库找不到的原因可能是SSL或被墙了,需要手动下载对应的库,放置到cppbuild目录:
Maven编译通过后会在ffmpeg目录下生成一个target文件夹:
target目录结构
其中:
ffmpeg.jar是JavaCpp编译出的java api
ffmpeg-android-arm.jar是打包了所有ffmepg so及其jni库的jar包,参考下图:
ffmpeg-android-arm库
ffmpeg-javadoc.jar是JavaCpp根据注解编译的java api doc
ffmpeg-sources.jar是ffmpeg\src目录的编译,具体有什么作用有待查证
编译成功后,必须要做点什么,否则没有任何意义:
1.创建一个Android工程
其中把编译出的ffmpeg.jar和target\classes\lib\armeabi目录下的所有so拷贝到工程的libs目录下(不能直接使用ffmpeg-android-arm.jar是因为Android对so的校验机制,目前没有尝试去解决这种问题,如果有办法解决可以留言告诉我)
直接使用ffmpeg-android-arm.jar
target/classes/lib/armeabi目录下的所有库文件
2.创建测试类
通过一个最简单的测试类,测试JavaCpp FFMPEG的可用性:
package com.example.ffmepgtest;
import org.bytedeco.javacpp.avcodec;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
public class MainActivity extends Activity {
public static final String TAG = MainActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
onTest();
}
public void onTest(){
Log.d(TAG, " "+avcodec.avcodec_configuration().getString());
}
}
程序运行最终结果
可以看到,程序运行后可以调用libavcodec打印出FFmpeg的配置信息。说明通过JAVACPP技术在应用层调用FFMPEG(非指令途径调用FFMPEG)省去了JNI代码的编写,这对应用开发者来说是个多么好的消息。
3.结束语
使用JavaCpp FFMPEG这种框架方式,就好像打开了某道门,让应用开发省去了JNI开发成本,比如Tensorflow,Videoinput等开源库,在应用需要使用这些框架时,使用javacpp就能极大的减少应用开发周期。
本文中讲述的JavaCpp例如 OpenCV、FFMpeg 等热门的开源项目是以开源贡献者已经完成JavaCpp代码转换文件的定义为前提的,关于自己的项目代码如何使用JavaCpp实现转换待我分析后再写一篇文章,感谢关注!
网友评论