Android视頻播发最齐小结:MediaPlayer+TextureView封裝一个极致完成全屏幕、小窗视頻播发器,附新项目源代码

原题目:Android视頻播发最齐小结:MediaPlayer+TextureView封裝一个极致完成全屏幕、小窗视頻播发器,附新项目源代码

创作者:xiaoyanger

来源于:http://jianshu/u/25c3b13f87ce

新项目已加上IjkPlayer适用,新项目详细地址见文末或点一下“阅读文章全文”

为何应用TextureView

在Android总播发视頻能够立即应用VideoView,VideoView是根据承继自SurfaceView来完成的。SurfaceView的大约基本原理便是在目前View的部位上建立一个新的Window,內容的显示信息和3D渲染都会新的Window中。
这促使SurfaceView的绘图和更新能够在独立的进程中开展,进而大大的提升高效率。
虎门企业网站建设可是呢,因为SurfaceView的內容沒有显示信息在View中只是显示信息在在建的Window中, 促使SurfaceView的显示信息不会受到View的特性操纵,不可以开展平移,放缩等转换,都不能放到其他RecyclerView或ScrollView中,一些View中的特点也没法应用。

TextureView是在4.0(API level 14)引进的,与SurfaceView对比,它不容易建立新的对话框来显示信息內容。它是将內容流立即推广到View中,而且能够和其他一般View一样开展移动,转动,放缩,动漫等转变。TextureView务必在硬件配置加快的对话框中应用。

TextureView被建立后不可以立即应用,务必要在它被它加上到ViewGroup后,待SurfaceTexture提前准备准备就绪才可以起功效(看TextureView的源代码,TextureView是在绘图的情况下建立的內部SurfaceTexture)。一般必须给TextureView设定监视器SurfaceTextuListener:

SurfaceTexture的提前准备准备就绪、尺寸转变、消毁、升级等情况转变时都是回调函数相对性应的方式。当TextureView內部建立好SurfaceTexture后,在监视器的onSurfaceTextureAvailable方式中,用SurfaceTexture来关系MediaPlayer,做为播发视頻的图象数据信息来源于。

SurfaceTexture做为数据信息安全通道,把从数据信息源(MediaPlayer)中获得到的图象帧数据信息变为GL外界纹路,交到TextureVeiw做为View heirachy中的一个硬件配置加快层来显示信息,进而完成视頻播发作用。

MediaPlayer详细介绍

MediaPlayer是Android原生态的多媒体系统播发器,能够用它来完成当地或是线上音频视频的播发,同时它适用https和rtsp。

MediaPlayer界定了各种各样情况,能够了解为是它的性命周期时间。

MediaPlayer情况图(性命周期时间)

这一情况图叙述了MediaPlayer的各种各样情况,及其关键方式启用后的情况转变。

MediaPlayer的有关方式及监视插口:

MediaPlayer在立即new出去以后就进到了Idle情况,这时能够启用好几个轻载的setDataSource()方式从idle情况进到Initialized情况(假如启用setDataSource()方式的情况下,MediaPlayer目标并不是出自于Idle情况,会抛出现异常,能够启用reset()方式返回Idle情况)。

启用prepared()方式和preparedAsync()方式进到Prepared情况,prepared()方式立即进到Parpared情况,preparedAsync()方式会优秀入PreParing情况,播发模块提前准备结束之后根据OnPreparedListener.onPrepared()回调函数方式通告Prepared情况。

在Prepared情况下便可以启用start()方式开展播发了,这时进到started()情况,假如播发的是互联网資源,Started情况下也会全自动启用顾客端申请注册的OnBufferingUpdateListener.OnBufferingUpdate()回调函数方式,对流播发缓存的情况开展跟踪。

pause()方式和start()方式是相匹配的,启用pause()方式会进到Paused情况,启用start()方式再次进到Started情况,再次播发。

stop()方式会使MdiaPlayer从Started、Paused、Prepared、PlaybackCompleted等情况进到到Stoped情况,播发终止。

当資源播发结束时,假如启用了setLooping(boolean)方式,会全自动进到Started情况再次播发,假如沒有启用则会全自动启用顾客端播发器申请注册的OnCompletionListener.OnCompletion()方式,这时MediaPlayer进到PlaybackCompleted情况,在此情况里能够启用start()方式再次进到Started情况。

封裝考虑到

MediaPlayer的方式和插口较为多,不一样的情况启用每个方式后情况转变状况也较为繁杂。播发有关的逻辑性只与MediaPlayer的播发情况和启用方式有关,而页面展现和UI实际操作许多情况下都必须依据自身新项目而定制。参照原生态的VideoView,以便解耦和便捷订制,把MediaPlayer的播发逻辑性和UI页面展现及实际操作有关的逻辑性分离出来。我是把MediaPlayer立即封裝到NiceVideoPlayer中,各种各样UI情况和实际操作意见反馈都封裝到NiceVideoPlayerController里边。假如必须依据不一样的新项目要求来改动播发器的作用,就只重新写过NiceVideoPlayerController便可以了。

NiceVideoPlayer

最先,必须一个FrameLayout器皿mContainer,里边有双层內容,第一层便是展现播发视頻內容的TextureView,第二层便是播发器操纵器mController。那麼自定一个NiceVideoPlayer承继自FrameLayout,将mContainer加上到当今控制:

加上setUp方式来配备播发的视頻資源相对路径(当地/互联网資源):

客户要在mController中实际操作才可以播发,因而必须在播发以前设定好mController:

客户在自定好自身的操纵器后根据setController这一方式设定给播发器开展关系。

开启播发时,NiceVideoPlayer将展现视頻图象內容的mTextureView加上到mContainer中(在mController的下一层),同时原始化mMediaPlayer,待mTextureView的数据信息安全通道SurfaceTexture提前准备准备就绪后便可以开启播发器:

开启播发器启用prepareAsync()方式后,mMediaPlayer进到提前准备情况,提前准备准备就绪后便可以刚开始:

NiceVideoPlayer的这种逻辑性早已完成视頻播发了,实际操作有关及其UI展现的逻辑性必须在操纵器NiceVideoPlayerController中来完成。可是呢,UI的展现和意见反馈都必须根据播发器当今的播发情况,因此必须给播发器界定一些变量定义来表明它的播发情况:

播发视頻时,mMediaPlayer提前准备准备就绪(Prepared)后沒有立刻进到播发情况,正中间有一个時间延迟时间時间段,随后刚开始3D渲染图象。因此将Prepared—— “刚开始3D渲染”正中间这一時间段界定为STATE_PREPARED。

假如是播发互联网视頻,在播发全过程中,缓存区数据信息不够时mMediaPlayer內部会滞留在某一帧界面以开展缓存。已经缓存时,mMediaPlayer将会是在已经播发也将会是中止情况,由于在缓存时假如客户积极点一下了中止,便是处在STATE_BUFFERING_PAUSED,因此缓存有STATE_BUFFERING_PLAYING和STATE_BUFFERING_PAUSED二种情况,缓存完毕后,修复播发或中止。

mController.setControllerState(mPlayerState, mCurrentState),mCurrentState表明当今播发情况,mPlayerState表明播发器的全屏幕、小对话框,一切正常三种情况。

界定好播发情况后,刚开始中止等实际操作逻辑性也必须依据播发情况调节:

reStart()方式是中止时再次播发启用。

全屏幕、小对话框播发的完成

将会最能想起完成全屏幕的方法便是把当今播发器的宽高给变大到显示屏尺寸,同时掩藏除播发器之外的别的全部UI,并设定成全屏方式。可是这类方法有许多难题,例如在目录(ListView或RecyclerView)中,除开变大掩藏外,还必须去测算拖动是多少间距才恰好让播发器与显示屏边沿重叠,撤出全屏幕的情况下还必须拖动到以前的部位,那样完成逻辑性不仅繁杂,并且和外界UI耦合比较严重,后边修改维护保养起來十分艰难(曾经的我就用这类方法被坑了成千上万道)。

剖析能否有别的更强的完成方法呢?

全部播发器由mMediaPalyer+mTexutureView+mController构成,要完成全屏幕或小对话框播发,大家只必须移动播发器的展现页面mTexutureView和操纵页面mController就可以。而且呢大家在上边界定播发器时,早已把mTexutureView和mController一起加上到mContainer中了,因此只必须将mContainer从当今主视图中清除,并加上到全屏幕和小对话框的总体目标主视图中就可以。

那麼如何明确全屏幕和小对话框的总体目标主视图呢?

大家了解每一个Activity里边都是有一个android.R.content,它是一个FrameLayout,里边包括了大家setContentView的全部控制。即然它是一个FrameLayout,大家便可以将它做为全屏幕和小对话框的总体目标主视图。

大家把从当今主视图清除的mContainer再次加上到android.R.content中,而且设定成全屏。这一情况下还必须留意android.R.content不是包含ActionBar和情况栏的,因此要将Activity设定满足屏方式,同时掩藏ActionBar。

撤出全屏幕也就非常简单了,将mContainer从android.R.content中清除,再次加上到当今主视图,并修复ActionBar、消除全屏幕方式就可以了了。

转换横纵屏时以便防止Activity再次走性命周期时间,别忘记必须在Manifest.xml的activity标识下加上以下配备:

android:configChanges= "orientation|keyboardHidden|screenSize"

进到小对话框播发和撤出小对话框的完成基本原理就和全屏幕作用一样了,只必须改动它的宽高主要参数:

这儿有一个非常必须留意的一点:

当mContainer清除再次加上后,mContainer以及內部的mTextureView和mController都是重绘,mTextureView重绘后,会再次new一个SurfaceTexture,并举新回调函数onSurfaceTextureAvailable方式,那样mTextureView的数据信息安全通道SurfaceTexture产生了转变,可是mMediaPlayer還是拥有本来的mSurfaceTexut,因此在转换全屏幕以前要储存以前的mSufaceTexture,当转换到全屏幕后再次启用onSurfaceTextureAvailable时,将以前的mSufaceTexture再次设定给mTexutureView。那样就确保了转换时视頻播发的无缝拼接对接。

NiceVideoPlayerControl

以便消除NiceVideoPlayer和NiceVideoPlayerController的藕合,把NiceVideoPlayer的一些作用性和分辨性方式抽象性到NiceVideoPlayerControl插口中。

NiceVideoPlayer完成这一插口就可以。

NiceVideoPlayerManager

同一页面上面有好几个视頻,或是视頻放到ReclerView或是ListView的器皿中,要确保同一時刻仅有一个视頻在播发,别的的全是原始情况,因此必须一个NiceVideoPlayerManager来管理方法播发器,关键作用是储存当今早已刚开始了的播发器。

选用单例,同时,onBackPressed供Activity选用户按回到键时启用。

NiceVideoPlayer的start方式及其onCompleted必须改动一下,确保刚开始播发一个视頻时要先释放出来掉以前的播发器;同时自身播发结束,要将NiceVideoPlayerManager中的mNiceVideoPlayer案例置空,防止运行内存泄漏。

NiceVideoPlayerController

播发操纵页面上,播发、中止、播发进展、缓存动漫、全屏幕/小屏等开启全是立即启用播发器相匹配的实际操作的。必须留意的便是启用以前要分辨当今的播发情况,由于一些情况下降用播发器的实际操作将会造成不正确(例如播发器还没有提前准备准备就绪,就要获得当今的播发部位)。

播发器在开启相对作用的情况下都是启用NiceVideoPlayerController的setControllerState(int playerState, int playState)这一方式来让客户改动UI。

不一样新项目都可以能订制不一样的操纵器(播发实际操作页面),这儿我也不祥细分化析完成逻辑性了,大概作用就相近腾迅视頻的网络热点目录中的播发器。在其中横着拖动更改播发进展、左边左右拖动更改色度,右边左右拖动更改色度等作用在编码上都有完成。编码有点儿长,也不贴了,必须的立即免费下载源代码。

应用

在RecyclerView或是ListView中应用时,必须监视itemView的detached:

在ItemViewdetach对话框时,必须释放出来掉itemView內部的播发器。

实际效果图

最终

全部作用有参照节操播发器,可是自身那样封裝和节操播发器還是有非常大差别:一是分离出来了播发作用和操纵页面,订制只需改动操纵器就可以。二是全屏幕/小对话框沒有在建一个播发器,仅仅移动了播发页面和操纵器,无需每一个视頻都必须在建2个播发器,都不用同歩情况。

MediaPlayer有许多文件格式不兼容,新项目已加上IjkPlayer的拓展适用,能够转换IjkPlayer和原生态MediaPlayer,事后还会继续考虑到加上ExoPlayer,同时也会拓展大量作用。

假如有不正确和更强的提议都请明确提出,源代码已提交GitHub,热烈欢迎Star,感谢!。

源代码:https://github/xiaoyanger0825/NiceVieoPlayer

参照:

Android TextureView简单实例教程

视頻界面帧的展现控制SurfaceView及TextureView比照

Android 5.0(Lollipop)中的SurfaceTexture,TextureView, SurfaceView和GLSurfaceView

Android MediaPlayer性命周期时间详细说明

节操播发器 https://github/lipangit/JieCaoVideoPlayer

回到凡科,查询大量

义务编写:

Android视頻播发最齐小结:MediaPlayer+TextureView封裝

Android视頻播发最齐小结:MediaPlayer+TextureView封裝一个极致完成全屏幕、小窗视頻播发器,附新项目源代码 原题目:Android视頻播发最齐小结:MediaPlayer+TextureView封裝一个极致完成全屏幕、


预约挂号



扫描二维码分享到微信