公司要实现在手机app上查看到摄像头的拍摄视频,使用了第三方的服务,但第三方最终只会底层透传一个视频的字节数组,并没有视频播放的功能,此功能需要自己实现。
由于第三方服务是基于native的,所以之前写的h5app不能用了,得重新用native实现,而我本人也是不懂安卓的,但没办法,还是得去琢磨。
一开始只知道我现在能拿到视频的字节数组,但压根不知道怎么把数组变成视频显示在手机上。后来有人告诉我,这个字节数组是H264码,可以查查H264,看有没有突破口。我查了一下,确实有,android有一个叫MediaCodec的东西,它可以形成一个解码器,然后就在网上摸索了一番,大致思路有了。
(1)android播放的控件叫SurfaceView,是可以在布局文件中定义的
(2)通过SurfaceView可以拿到SurfaceHolder,继而拿到Surface
(3)可以把Surface配置在MediaCodec中,从而页面和解码器就关联起来了
(4)然后用这么一个解码器去处理那个字节数组,就能显示视频了
下来记录一下遇到的问题以及解决方法
(1)MediaCodec的定义
(2)MediaCodec.configure()的4个参数
第一个参数MediaFormat,自己单独定义即可
第二个参数Surface,这个就坑了,看了许多博客,上边直接就是一个变量的名字。。。鬼知道这个变量是怎么定义的,反正找呀找,终于找到个看上去能试的,就试了试,可以。SurfaceView.getSurfaceHolder().getSurface()
第三个参数crypto,本身就没学过安卓,也就不想深究了,能实现就行,博客上都写的null,我也就写null了
第四个参数flags,也是博客上都是0,我也就写0了
(3)MediaCodec的使用
如果想深究的话,可以看看其完整概念和源码。我是直接从网上copy了一个方法,发现可以直接用,就直接用了。。。
没想太多,直接用了,尝试性改了些不痛不痒的东西。然后播放视频的线程叫VideoThread,里边有个while(true)的循环,这个循环每次都能拿到一个字节数组,然后我就在拿到之后调用了这个onFrame()方法,就把视频显示出来了。
接下来说一下坑。。。
视频是能播放了,但是他播放的形式是在主Activity里边启动一个线程,这个线程又会让播放视频的线程join进来
(1)MediaCodec的Configure()和Start()必须写在SurfaceHolder的回掉函数中,否则会出现surface还没create出来的时候mediaCodec就要去配置它,从而出错的问题
(2)线程。。。
在视频播放的时候,用户点击back键或者类似任务管理器的那个键的时候,主页面都没了,那我启动的线程该咋弄呢。。。
线程是可以停的,让他自己停,即便是while(true),遇到break不就结束了么
只要用户执行上述行为,onFrame()绝对会出现问题,catch一下break一下就完了嘛
(3)终极大问题,我可以点击back再进来视频可以重新开始,但如果点击类似任务管理器的那个键,再在那里边点这个app,程序就直接崩了
查了很多,也试了很多,比如最终我把MediaCodec,MediaFormat等这些变量全定义在线程里边,改写SurfaceHolder回调函数中的surfaceDestroyed()方法(MediaCodec的release stop reset什么的,试了试,唉。。。关他鸟事)以及其他记不起来的尝试,都不行,都会出现上图中的FATAL EXCEPTION(致命错误),我不理解为啥back再进来正常,通过任务管理器就不行了呢,最后我发现back再进来是从onCreate开始的,而后者,onRestart,呵呵。。。可能是View的问题,我就想着,原来那个View不能用了?尝试了一下finish,挺笨的。。确实不好,再点回来是上个界面。。。
我也尝试改写整个Activity的onResume方法,其实这里已经靠近行得通的解决方案了,设个flag,执行完onCreate就是false,执行过onResume,就最后设为true,每次onResume都先看看是不是true,其实也就第一次不是,进行差别处理,在if里边我重新执行线程,看了看,还是不行,还是上图那个错误,就是这个surfaceView的问题,老的不能用,新的是啥啊。。。等等,新的?我尝试性的setContentView了一下,居然,终于好了,不崩也不报错了,视频也有显示了。(这里边少一行都不行的)
还是没学过android,现在也没工夫从下到上去学了,我得出一个结论,貌似setContentView就相当于全部刷新了,之前的可能就全删除了,正好符合我的要求。就这个问题,困扰了我两天半,虽说最终解决方案看似如此简单,可要找到这个解决方案的过程可是不轻松,虽说很多尝试过的方案都没行得通,但也对相关知识了解的差不多了。
应该也不会有什么人看,暂且记录一下心路历程,问题解决额一瞬间其实很多东西都记不清了,所以写的也就乱了,也就少了点内容。思路是清晰,并且看上去也是可行的,但跟过程,绝对不是一个等级的。至于相关的MediaPlayer,FFmpeg什么的,以后有机会接触到再去主动碰吧。