随着快手,抖音,西瓜视频等视频APP的崛起,视频播放已经成为主流,此时做为Android研发的你,想要提升本身的能力还不知道怎么开发视频播放器怎么行?因此今天就带着你们一块儿开发一个简易播放器:SmallVideoPlayerbash
咱们观察一个视频播放器,能够看到视频播放器除了正在播放的视频还有不少控件,好比播放按钮,暂停按钮,播放进度条,播放计时器等。 这么多控件显然没法播放视频,可是他们都在控制视频的播放。因而可知视频播放器能够分为两层,一层为视频播放器控制层,一层为真正的视频播放层。ide
因此实现视频播放器的时候就能够分为上层控制层,和底层播放层两层来实现。动画
咱们知道本身开发视频播放器内核确定是不现实的,这须要必定的技术成本,单我的很难达到,因此咱们就选择一个最受欢迎的开源的内核便可:bilibili开源的视频播放器:ijkplayerui
视频播放这块须要给你们普及两个知识点:编码
先来介绍一下大部分软件如何解析一段视频流。首先它须要先肯定视频的格式,这个和解码相关,不一样的格式视频编码不一样,不是这里的重点。知道了视频的编码格式后,再经过编码格式进行解码,最后获得一帧一帧的图像,并把这些图像快速的显示在界面上,即为播放一段视频。SurfaceView在Android中就是完成这个功能的。spa
既然SurfaceView是配合MediaPlayer使用的,MediaPlayer也提供了相应的方法设置SurfaceView显示图片,只须要为MediaPlayer指定SurfaceView显示图像便可。它的完整API以下:线程
void setDisplay(SurfaceHolder sh);
复制代码
它须要传递一个SurfaceHolder对象,SurfaceHolder能够理解为SurfaceView装载须要显示的一帧帧图像的容器,它能够经过SurfaceHolder.getHolder()方法得到。设计
使用MediaPlayer配合SurfaceView播放视频的步骤与播放使用MediaPlayer播放MP3大致一致,只须要额外设置显示的SurfaceView便可。code
上面有提到,SurfaceView和大部分视频应用同样,把视频流解析成一帧帧的图像进行显示,可是若是把这个解析的过程放到一个线程中完成,可能在上一帧图像已经显示事后,下一帧图像尚未来得及解析,这样会致使画面的不流畅或者声音和视频不一样步的问题。因此SurfaceView和大部分视频应用同样,经过双缓冲的机制来显示帧图像。那么什么是双缓冲呢?双缓冲能够理解为有两个线程轮番去解析视频流的帧图像,当一个线程解析完帧图像后,把图像渲染到界面中,同时另外一线程开始解析下一帧图像,使得两个线程轮番配合去解析视频流,以达到流畅播放的效果。cdn
下图为演示了双缓冲的过程,线程A和线程B配合解析渲染视频流的帧图像:
SurfaceView内部实现了双缓冲的机制,可是实现这个功能是很是消耗系统内存的。由于移动设备的局限性,Android在设计的时候规定,SurfaceView若是为用户可见的时候,建立SurfaceView的SurfaceHolder用于显示视频流解析的帧图片,若是发现SurfaceView变为用户不可见的时候,则当即销毁SurfaceView的SurfaceHolder,以达到节约系统资源的目的。
若是开发人员不对SurfaceHolder进行维护,会出现最小化程序后,再打开应用的时候,视频的声音在继续播放,可是不显示画面了的状况,这就是由于当SurfaceView不被用户可见的时候,以前的SurfaceHolder已经被销毁了,再次进入的时候,界面上的SurfaceHolder已是新的SurfaceHolder了。因此SurfaceHolder须要咱们开发人员去编码维护,维护SurfaceHolder须要用到它的一个回调,SurfaceHolder.Callback(),它须要实现三个以下三个方法:
void surfaceDestroyed(SurfaceHolder holder)
:当SurfaceHolder被销毁的时候回调。void surfaceCreated(SurfaceHolder holder)
:当SurfaceHolder被建立的时候回调。void surfaceChange(SurfaceHolder holder)
:当SurfaceHolder的尺寸发生变化的时候被回调。在应用中分别为SurfaceHolder实现了这三个方法,先进入应用,SurfaceHolder被建立,建立好以后会改变SurfaceHolder的大小,而后按Home键回退到桌面销毁SurfaceHolder,最后再进入应用,从新建立SurfaceHolder并改变其大小。\
如上面所说,SurfaceView能够在一个独立的线程中进行绘制,不会影响主线程,而且使用双缓冲机制,播放视频时画面更流畅。
由于这个Surface不在View hierachy中,它的显示也不受View的属性控制,因此不能进行平移,缩放等变换,也不能放在其它ViewGroup中,一些View中的特性也没法使用。
与SurfaceView同样继承View,它能够将内容流直接投影到View中,能够用于实现Live preview等功能。
和SurfaceView不一样的是,它不会在WMS中单首创建窗口,而是做为View hierachy中的一个普通View,所以能够和其它普通View同样进行移动,旋转,缩放,动画等变化。
值得注意的是TextureView必须在硬件加速的窗口中。它显示的内容流数据能够来自App进程或是远端进程。从类图中能够看到,TextureView继承自View,它与其它的View同样在View hierachy中管理与绘制。
TextureView重载了draw()方法,其中主要SurfaceTexture中收到的图像数据做为纹理更新到对应的HardwareLayer中。SurfaceTexture.OnFrameAvailableListener用于通知TextureView内容流有新图像到来。SurfaceTextureListener接口用于让TextureView的使用者知道SurfaceTexture已准备好,这样就能够把SurfaceTexture交给相应的内容源。
Surface为BufferQueue的Producer接口实现类,使生产者能够经过它的软件或硬件渲染接口为SurfaceTexture内部的BufferQueue提供graphic buffer。
支持移动、旋转、缩放等动画,支持截图
必须在硬件加速的窗口中使用,占用内存比SurfaceView高,在5.0之前在主线程渲染,5.0之后有单独的渲染线程。