Vitamio的踩坑+填坑
vitamio这个视频框架已经有快两年没有没有使用过了,今天想写个demo再复习下。
- 首先肯定是下载官方的demo跑一下了,他们的demo放在github上,所以我就直接上github搜索并下载VitamioBundle,我个人比较喜欢用新的api,所以手动将targetSdkVersion改为了27,重新编译运行,app打开了,没问题,点击VideoView条目跳转播放页面播放,居然崩溃了。
07-19 07:44:09.764 5133-5133/io.vov.vitamio.demo E/linker: "/data/data/io.vov.vitamio.demo/libs/libffmpeg.so" has text relocations (https://android.googlesource.com/platform/bionic/+/master/android-changes-for-ndk-developers.md#Text-Relocations-Enforced-for-API-level-23)
07-19 07:44:09.765 5133-5133/io.vov.vitamio.demo E/Vitamio[4.2.1][Player]: LOAD FFMPEG ERROR: dlopen failed: "/data/data/io.vov.vitamio.demo/libs/libffmpeg.so" has text relocations (https://android.googlesource.com/platform/bionic/+/master/android-changes-for-ndk-developers.md#Text-Relocations-Enforced-for-API-level-23)
07-19 07:44:09.766 5133-5133/io.vov.vitamio.demo E/Vitamio[4.2.1][Player]: FIND_NAME_SYM vvo, render_yuv
07-19 07:44:09.768 5133-5133/io.vov.vitamio.demo A/libc: Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 5133 (ov.vitamio.demo), pid 5133 (ov.vitamio.demo)
07-19 07:44:09.792 5170-5170/? A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'google/sdk_gphone_x86/generic_x86:8.1.0/OSM1.180201.021/4741582:userdebug/dev-keys'
Revision: '0'
ABI: 'x86'
pid: 5133, tid: 5133, name: ov.vitamio.demo >>> io.vov.vitamio.demo <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
Cause: null pointer dereference
eax ca5b5ac0 ebx ca5aded8 ecx e49a91e4 edx e3b10860
07-19 07:44:09.792 5170-5170/? A/DEBUG: esi e3b10860 edi 00000075
xcs 00000023 xds 0000002b xes 0000002b xfs 0000006b xss 0000002b
eip 00000000 ebp ca598f98 esp ff832c2c flags 00010246
backtrace:
#00 pc 00000000 <unknown>
#01 pc 5b6f696c <unknown>
说实话这日志看的我一脸懵逼,但还是得找解决方案google一下。
Vitamio Crash In Android 6.0(Marshmallow) Devices when android targetSdkVersion set to 23
在这里我找到了暂时解决得方案,把targetSdkVersion改到22,再次运行,视频正常播放。
- demo跑起来了,接下来当然是自己写个demo玩玩了。(具体的导入过程我就不多说了,百度一下有很多)编译运行,what?黑屏~。查看日志:
07-19 08:03:08.076 5822-5822/io.vov.vitamio.demo E/Vitamio[Player]: Native libs libffmpeg.so not exists!
打开Vitamio.java,找到输出错误日志的地方:
/*** Check if Vitamio is initialized at this device** @param ctx Android Context* @return true if the Vitamio has been initialized.*/public static boolean isInitialized(Context ctx) {vitamioPackage = ctx.getPackageName();vitamioLibraryPath = ContextUtils.getDataDir(ctx) + "libs/";File dir = new File(getLibraryPath());if (dir.exists() && dir.isDirectory()) {String[] libs = dir.list();if (libs != null) {Arrays.sort(libs);for (String L : getRequiredLibs()) {if (Arrays.binarySearch(libs, L) < 0) {Log.e("Native libs %s not exists!", L);return false;}}File lock = new File(getLibraryPath() + LIBS_LOCK);BufferedReader buffer = null; try {buffer = new BufferedReader(new FileReader(lock)); int appVersion = ContextUtils.getVersionCode(ctx);int libVersion = Integer.valueOf(buffer.readLine()); Log.i("isNativeLibsInited, APP VERSION: %d, Vitamio Library version: %d", appVersion, libVersion);if (libVersion == appVersion)return true;} catch (IOException e) {Log.e("isNativeLibsInited", e);} catch (NumberFormatException e) {Log.e("isNativeLibsInited", e);} finally {IOUtils.closeSilently(buffer);}}}return false;}
原来是没有初始化成功,先看看我们加载布局之前做了什么。
//检查初始化
if (!LibsChecker.checkVitamioLibs(this))return;
那我们再看一下LibsChecker这个类做了什么
public final class LibsChecker {public static final String FROM_ME = "fromVitamioInitActivity";public static final boolean checkVitamioLibs(Activity ctx) {if (!Vitamio.isInitialized(ctx) && !ctx.getIntent().getBooleanExtra(FROM_ME, false)) {Intent i = new Intent();i.setClassName(Vitamio.getVitamioPackage(), "io.vov.vitamio.activity.InitActivity");i.putExtras(ctx.getIntent());i.setData(ctx.getIntent().getData());i.putExtra("package", ctx.getPackageName());i.putExtra("className", ctx.getClass().getName());ctx.startActivity(i);ctx.finish();return false;}return true;}
}
由此我们发现,它的作用主要是将当前Activity的信息传递给InitActivity,并把当前页面finish掉。再看一下InitActivity
public class InitActivity extends Activity {public static final String FROM_ME = "fromVitamioInitActivity";private ProgressDialog mPD;private UIHandler uiHandler;protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);uiHandler = new UIHandler(this);new AsyncTask<Object, Object, Boolean>() {@Overrideprotected void onPreExecute() {mPD = new ProgressDialog(InitActivity.this);mPD.setCancelable(false);mPD.setMessage(InitActivity.this.getString(getResources().getIdentifier("vitamio_init_decoders", "string", getPackageName())));mPD.show();}@Overrideprotected Boolean doInBackground(Object... params) {//进行初始化操作return Vitamio.initialize(InitActivity.this, getResources().getIdentifier("libarm", "raw", getPackageName()));}@Overrideprotected void onPostExecute(Boolean inited) {if (inited) {uiHandler.sendEmptyMessage(0);}}}.execute();}private static class UIHandler extends Handler {private WeakReference<Context> mContext;public UIHandler(Context c) {mContext = new WeakReference<Context>(c);}public void handleMessage(Message msg) {InitActivity ctx = (InitActivity) mContext.get();switch (msg.what) {case 0:ctx.mPD.dismiss();Intent src = ctx.getIntent();Intent i = new Intent();i.setClassName(src.getStringExtra("package"), src.getStringExtra("className"));i.setData(src.getData());i.putExtras(src);i.putExtra(FROM_ME, true);ctx.startActivity(i);ctx.finish();break;}}}
}
原来初始化的操作放在了这里,开启了一个异步任务进行初始化操作,初始化成功后通过handler发送一个空消息,然后执行操作,跳转到之前的那个页面(信息都传过来了),并关闭InitActivity。这里有两个地方比较疑惑
- 为什么要加一个handler呢,onPostExecute里面的就是执行在UI线程的吧
- Vitamio.initialize(Context ctx, int rawId)方法里面,两个条件问什么是或的关系,明明其中一个失败就能导致初始化失败
/*** Same as {@link #initialize(Context)}** @param ctx Android Context* @param rawId R.raw.libarm* @return true if the Vitamio initialized successfully.*/public static boolean initialize(Context ctx, int rawId) {return isInitialized(ctx) || extractLibs(ctx, rawId);}
补充:如果不是通过定义静态内部类的方法使用handler,是有可能造成内存泄漏的。
回归正题,通过以上我们发现了一个参数rawId,默认值是R.raw.libarm。但是我创建项目的时候res下并没有创建raw文件夹。对比了一下demo,发现别人的确实有这么个文件夹,里面放了libarm.so文件。(vitamio库里面也有这个,不太清楚为什么自己module里面也要加上) 重新编译运行,可以正常播放视频。
重新回到最初的问题,我总不能为了使用vitamio而放弃使用高版本的api吧。搜寻一番无果后,我打开了vitamio的官网,看到了新版本5.2.3,并且已经说明支持Android6.0。(这时我想拍死自己),既然有新的了,那么重新集成,这次我把targetSdkVersion设为了27,编译运行,成功。
补充:我将两个版本的demo做了下对比。新的demo中不在需要res/raw文件夹了,并且删除了LibsChecker,同时InitActivity里面不再执行初始化操作了。(感觉这个类也失去了存在的意义,不过没删除而已)
我们做初始化操作,由
if (!LibsChecker.checkVitamioLibs(this))return;
变成了
Vitamio.isInitialized(this);
activity由以前的启动2次变成了1次。
4.2.1版本:VideoViewActivity(start)->LibsChecker.checkVitamioLibs(this)->InitActivity(start),VideoViewActivity(finish)->Vitamio.initialize(this)->VideoViewActivity(start),InitActivity(finish)->setContentView()
5.2.3版本:VideoViewActivity(start)->Vitamio.isInitialized(this)->setContentView()
Vitamio的踩坑+填坑相关推荐
- Spark踩坑填坑-聚合函数-序列化异常
Spark踩坑填坑-聚合函数-序列化异常 一.Spark聚合函数特殊场景 二.spark sql group by 三.Spark Caused by: java.io.NotSerializable ...
- [iOS]贝聊 IAP 实战之见坑填坑
大家好,我是**贝聊科技** 的 iOS 工程师 @NewPan. 这次为大家带来我司 IAP 的实现过程详解,鉴于支付功能的重要性以及复杂性,文章会很长,而且支付验证的细节也关系重大,所以这个主题会 ...
- weex css单位,Weex系列(7) ——踩坑填坑的总总
目录 使用weex已经一年半了,踩了很多坑,也流了很多泪填上,总结一波,希望对大家有所帮助. LaunchImage 这是今年来的第一个调整,需要把 iOS8.0 and Later勾上,不然iPho ...
- Springboot中使用Mybatis框架对数据库进行联表查询,踩坑填坑
因为mybatis使用的基本是原生sql语句 所以首先从数据库开始说 以mysql数据库为例,对表的连接查询分为四种 内连接,外连接,交叉连接,和联合连接 内连接使用比较运算符根据每个表共有的列的值匹 ...
- js promises 踩坑 填坑 We have a problem with promises
We have a problem with promises promise 填坑 对于 promise return 与否,结果真的不一样哦. By: Nolan Lawson Published ...
- Cobalt Strike折腾踩坑填坑记录
文章目录 0X00 背景 0x01 基础原理 0x02 关于破戒 Exit暗桩 0x03 CDN+反代隐藏Teamserver Domain Fronting Proxy 0x04 DNS上线 一个未 ...
- Pyinstaller 详解多种打包过程(去坑,填坑)。
前言 本篇文章,详细介绍pyinstaller多种打包过程.去坑,填坑. 一.安装Pyinstaller 1)使用下面的命令即可安装(win10) pip install pyinstaller 二. ...
- 微信小程序--多视频滑动播放(踩坑,填坑)
最近在做一个关于短视频的小程序,类似于微视和快手的小程序,但是在做的过程当中碰到了好多坑,于是得一步一步的去填这个坑.先来看看最后的实现效果 在做的过程中,想要实现多个视频无限滑动播放,并且在视频原生 ...
- 踩坑-填坑之 : vue打包上线,页面无法显示
出现了什么问题,什么现象? 根据从网上down下来的iview-admin框架进行后台管理系统开发,开发过程顺利,在部署到测试服务器时,打开页面一片空白;或是打开页面时只显示首页跳转到其他页面时显示空 ...
最新文章
- 招聘:兼职ASP 高级工程师
- python自动化测试视频百度云-python接口自动化测试视频教程全集
- Tutorial on Variational AutoEncoders
- 【Unity3D技巧】一个简单的Unity-UI框架的实现
- 如何找到SAP ABAP odata服务实现的具体backend 系统
- visual c++ build tools的安装与使用
- MFC的程序,不想显示窗口,任务栏里也不显示
- [ES6] 细化ES6之 -- 变量的解构赋值
- mqa插件_为什么专有的MQA音乐编码系统比DRM更好,但仍然不好
- STM8单片机通过PWM触发ADC同步采样
- Netty工作笔记0035---Reactor模式图剖析
- TypeScript与React中如何使用ref
- 51Nod-1091 线段的重叠【排序】
- 新浪微博从 Kafka 到 Pulsar 的演变
- 机会是留给有准备的人的
- 联想计算机怎样分区,电脑硬盘怎么分区才合理?看完秒懂
- 子豪兄教你在树莓派上安装OpenCV
- 网络原理实验4 路由协议的配置
- 【LOJ】#3086. 「GXOI / GZOI2019」逼死强迫症
- UUUUUUUUUUnity
热门文章
- 鸿蒙和ios流畅对比,鸿蒙OS对比iOS,华为再次“超越”,流畅度大幅领先苹果!...
- 数据分析案例(口罩亏损)--数据处理
- 23种设计模式——建造者模式
- LinuX 硬盘分区细节详谈
- Nico的刷题日记(一)
- 更新文件服务器,文件更新服务器
- 1984年高考数学试题。
- 出现这个错误的解决方法No enclosing instance of type 类名 is accessible. Must qualify the allocation with
- 喊苦喊累的程序员们,看看日本人是怎么加班的。
- sja1000 中断_[转载]SJA1000的错误中断处理