背景:
Android开发需要播放视频的情况的时候,在不接入外部sdk仅考虑原生的Android sdk下,常规情况下会使用到videoView来进行播放。直接传入一个path或者url可以直接实现播放功能,通过callback回调可以对播放的一些时机加入业务逻辑的控制,通常这也确实能处理绝大部分视频播放的情景需求,不过一旦需求需要超出原生videoView承载的功能上时,就需要对底层有进一步的理解。此处作为技术储备学习,记录对surfaceView和mediaPlayer的初步探索认知
基础知识了解
SurfaceView:区别于普通的view,有独立的线程执行渲染,支持音视频等高性能要求的页面数据更新视图
MediaPlayer:对音频和视频的文件和数据流进行控制和管理的类
思路
用MediaPlayer进行控制对应的视频文件加载到surfaceView完成对应的效果
实践过程
首先看一眼SurfaceView的代码找一找如何把surfaceView跟对应MediaPlayer关联起来,很快就会发现,这二者不需要关联。。
实际上SurfaceView只囊括了跟view相关的东西,对于广义上的"输入的数据"(个人理解,不一定准确)是通过SurfaceHolder来接收处理的,SurfaceHolder是一个接口,它还有一个内部接口SurfaceHolder.Callback来接收处理surface的回调
那么实践过程就可以变为一个经典的中间关系,即通过SurfaceHolder与MediaPlayer进行关联,根据surfaceCreate的回调来让MediaPlayer执行start(实际是先调用一个setDisplay。后续要等dataSource执行完prepare才start),surfaceDestroyed回调来执行release释放,SurfaceView本身就做个无情的展示工具就完了,甚至不需要我们对他调用啥(可能本质也是为了代码的高内聚低耦合的大思路)
考虑到搞了个view一定想点一点的想法,对surfaceView也要进行一个经典setOnClickListerner,那么加上本来就要实现的SurfaceHolder.Callback接口,直接进行懒鬼式匿名内部类代码就很难看了,所以我们可以写一个新类实现继承SurfaceView顺便把这两个接口一起继承了,这样重写多个方法都可以留在这个类里面代码工整很多,记得初始化的时候把接口都set一下就是了,于是代码就成了这样
关于view的关联工作做完了,然后来处理数据进入的情况,MediaPlayer的api是setDataSource,传入一个String的路径或者一个url路径,那么给这个我们自己的VideoView暴露一个对外的setPath,把对应的参数传进来调用setDataSource,根据搜索资料大概给这个东西配了一些前后逻辑最后变成
后面使用就再搞一个VideoActivity来用一下。对应xml放置以后我们仅需要setPath真就完事了
真机编译后实践可行,后续对于可以根据各种情景来控制展示时机,使用时通过不同的回调把videoView.setDataPath进行调用即可,包括对于视频播放时的点击暂停/开始,进度条控制播放进度都是根据mediaPlayer的api进行处理就可以方便的实现,实际上,把这些做完的话,就基本接近VideoView本身的实现了😂
问题记录
1. 处理setPath路径的时候播放不了
本人处理的时候也是一直有这个问题,踩出了几个点
1.花里胡哨的格式别搞,常规使用mp4,avi这些。
本人一开始用了个mkv,事实证明原生的这个MediaPlayer对于外界封装的花里胡哨的格式也是无能为力的,日志里给的那个报错码也不知道怎么查,完全傻眼
2.确认app的读写权限
这个好排查,日志会直接显示permission相关的内容
3.文件的位置
这个属于本人一个思路上的错误,甚至是浪费最多时间的地方。因为demo思维很重,测试的视频直接放到工程目录了,直接给了工程目录的路径,甚至失败后还根据setDataSource的api说明把工程目录的绝对路径传入了也不对,后来权且放到asset目录里,失败后偶然看到setDataSource的api有对应asset的调用,通过一个fileDescriptor对象来传入,终于可以成功展示视频。后来又想了想,setPath作为一个对外暴露的api,不可能让你传的是工程目录的路径啊,肯定是让你传手机内的文件路径才对,工程目录的文件打包进去的肯定不会是你这个路径,不打包进去的你甚至没有这个资源,于是乎重新传了测试机的一个视频文件,成功播放。这个故事告诉我们还是要讲点道理,虽然是写demo但是还是要摆脱demo思维,不然容易产生一些特殊的bug
2.视频暂停后偶先会回跳到几秒前
这个有点抽象,也不是必现,不是很好排查,直接搜了一下有一篇博客谈及,不知道是不是同样的原由,权且做记录吧