01.视频播放器框架介绍

视频播放器介绍文档

目录介绍

  • 01.该视频播放器介绍
  • 02.视频播放器功能
  • 03.视频播放器架构说明
  • 04.视频播放器如何使用
  • 05.播放器详细Api文档
  • 06.播放器封装思路
  • 07.播放器示例展现图
  • 08.添加自定义视图
  • 09.视频播放器优化处理
  • 10.播放器问题记录说明
  • 11.性能优化和库大小
  • 12.视频缓存原理介绍
  • 13.查看视频播放器日志
  • 14.该库异常code说明
  • 15.该库系列wiki文档
  • 16.版本更新文档记录

00.视频播放器通用框架

  • 基础封装视频播放器player,能够在ExoPlayer、MediaPlayer,声网RTC视频播放器内核,原生MediaPlayer能够自由切换
  • 对于视图状态切换和后期维护拓展,避免功能和业务出现耦合。好比须要支持播放器UI高度定制,而不是该lib库中UI代码
  • 针对视频播放,音频播放,播放回放,以及视频直播的功能。使用简单,代码拓展性强,封装性好,主要是和业务完全解耦,暴露接口监听给开发者处理业务具体逻辑
  • 该播放器总体架构:播放器内核(自由切换) + 视频播放器 + 边播边缓存 + 高度定制播放器UI视图层

01.该视频播放器介绍

1.1 该库说明

播放器功能 MediaPlayer ExoPlayer IjkPlayer RTC TXPlayer
UI/Player/业务解耦 支持 支持 支持
切换视频播放模式 支持 支持 支持
视频无缝切换 支持 支持 支持
调节播放进度 支持 支持 支持
网络环境监听 支持 支持 支持
滑动改变亮度/声音 支持 支持 支持
设置视频播放比例 支持 支持 支持
自由切换视频内核 支持 支持 支持
记录播放位置 支持 支持 支持
清晰度模式切换 支持 支持 支持
重力感应自动进入 支持 支持 支持
锁定屏幕功能 支持 支持 支持
倍速播放 不支持 支持 支持
视频小窗口播放 支持 支持 支持
列表小窗口播放 支持 支持 支持
边播边缓存 支持 支持 支持
同时播放多个视频 支持 支持 支持
仿快手预加载 支持 支持 支持
基于内核无UI 支持 支持 支持
添加弹幕 支持 支持 支持
全屏显示电量 支持 支持 支持

1.2 该库功能说明

类型 功能说明
项目结构 VideoCache缓存lib,VideoKernel视频内核lib,VideoPlayer视频UIlib
内核 MediaPlayer、ExoPlayer、IjkPlayer,后期接入Rtc和TXPlayer
协议/格式 http/https、concat、rtsp、hls、rtmp、file、m3u八、mkv、webm、mp三、mp4等
画面 调整显示比例:默认、16:九、4:三、填充;播放时旋转画面角度(0,90,180,270);镜像旋转
布局 内核和UI分离,和市面GitHub上大多数播放器不同,方便定制,经过addView添加
播放 正常播放,小窗播放,列表播放,仿抖音播放
自定义 能够自定义添加视频UI层,能够说UI和Player高度分离,支持自定义渲染层SurfaceView

02.视频播放器功能

  • A基础功能java

    • A.1.1 可以自定义视频加载loading类型,设置视频标题,设置视频底部图片,设置播放时长等基础功能
    • A.1.2 能够切换播放器的视频播放状态,播放错误,播放未开始,播放开始,播放准备中,正在播放,暂停播放,正在缓冲等等状态
    • A.1.3 能够自由设置播放器的播放模式,好比,正常播放,全屏播放,和小屏幕播放。其中全屏播放支持旋转屏幕。
    • A.1.4 能够支持多种视频播放类型,好比,原生封装视频播放器,还有基于ijkPlayer封装的播放器。
    • A.1.5 能够设置是否隐藏播放音量,播放进度,播放亮度等,能够经过拖动seekBar改变视频进度。还支持设置n秒后不操做则隐藏头部和顶部布局功能
    • A.1.6 能够设置竖屏模式下全屏模式和横屏模式下的全屏模式,方便多种使用场景
    • A.1.7 top和bottom面版消失和显示:点击视频画面会显示、隐藏操做面板;显示后不操做会5秒后自动消失【也能够设置n秒消失时间】
  • B高级功能android

    • B.1.1 支持一遍播放一遍缓冲的功能,其中缓冲包括两部分,第一种是播放过程当中缓冲,第二种是暂停过程当中缓冲
    • B.1.2 基于ijkPlayer,ExoPlayer,Rtc,原生MediaPlayer等的封装播放器,支持多种格式视频播放
    • B.1.3 能够设置是否记录播放位置,设置播放速度,设置屏幕比例
    • B.1.4 支持滑动改变音量【屏幕右边】,改变屏幕亮度【屏幕左边】,屏幕底测左右滑动调节进度
    • B.1.5 支持list页面中视频播放,滚动后暂停播放,播放能够自由设置是否记录状态。而且还支持删除视频播放位置状态。
    • B.1.6 切换横竖屏:切换全屏时,隐藏状态栏,显示自定义top(显示电量);竖屏时恢复原有状态
    • B.1.7 支持切换视频清晰度模式
    • B.1.8 添加锁屏功能,竖屏不提供锁屏按钮,横屏全屏时显示,而且锁屏时,屏蔽手势处理
  • C拓展功能【这块根据实际状况选择是否须要使用,通常视频付费App会有这个工鞥】git

    • C1产品需求:相似优酷,爱奇艺视频播放器部分逻辑。好比若是用户没有登陆也没有看视频权限,则提示试看视频[自定义布局];若是用户没有登陆可是有看视频权限,则正常观看;若是用户登陆,可是没有充值会员,部分须要权限视频则进入试看模式,试看结束后弹出充值会员界面;若是用户余额不足,好比余额只有99元,可是视频观看要199元,则又有其余提示。
    • C2自身需求:好比封装好了视频播放库,那么点击视频上登陆按钮则跳到登陆页面;点击充值会员页面也跳到充值页面。这个经过定义接口,可让使用者经过方法调用,灵活处理点击事件。
    • C.1.1 能够设置试看模式,设置试看时长。试看结束后就提示登陆或者充值……
    • C.1.2 对于设置视频的宽高,建议设置成4:3或者16:9或者经常使用比例,若是不是经常使用比例,则可能会有黑边。其中黑边的背景能够设置
    • C.1.3 能够设置播放有权限的视频时的各类文字描述,而没有把它写在封装库中,使用者本身设定
    • C.1.4 锁定屏幕功能,这个参考大部分播放器,只有在全屏模式下才会有

03.视频播放器架构说明

  • 视频常见的布局视图github

    • 视频底图(用于显示初始化视频时的封面图),视频状态视图【加载loading,播放异常,加载视频失败,播放完成等】
    • 改变亮度和声音【改变声音视图,改变亮度视图】,改变视频快进和快退,左右滑动快进和快退视图(手势滑动的快进快退提示框)
    • 顶部控制区视图(包含返回健,title等),底部控制区视图(包含进度条,播放暂停,时间,切换全屏等)
    • 锁屏布局视图(全屏时展现,其余隐藏),底部播放进度条视图(不少播放器都有这个),清晰度列表视图(切换清晰度弹窗)
  • 后期可能涉及的布局视图web

    • 手势指导页面(有些播放器有新手指导功能),离线下载的界面(该界面中包含下载列表, 列表的item编辑(全选, 删除))
    • 用户从wifi切换到4g网络,提示网络切换弹窗界面(当网络由wifi变为4g的时候会显示)
    • 图片广告视图(带有倒计时消失),开始视频广告视图,非会员试看视图
    • 弹幕视图(这个很重要),水印显示视图,倍速播放界面(用于控制倍速),底部视频列表缩略图视图
    • 投屏视频视图界面,视频直播间刷礼物界面,老师开课界面,展现更多视图(下载,分享,切换音频等)
  • 视频播放器的痛点算法

    • 播放器内核难以切换api

      • 不一样的视频播放器内核,因为api不同,因此难以切换操做。要是想兼容内核切换,就必须本身制定一个视频接口+实现类的播放器
    • 播放器内核和UI层耦合缓存

      • 也就是说视频player和ui操做柔和到了一块儿,尤为是二者之间的交互。好比播放中须要更新UI进度条,播放异常须要显示异常UI,都比较难处理播放器状态变化更新UI操做
    • UI难以自定义或者修改麻烦性能优化

      • 好比常见的视频播放器,会把视频各类视图写到xml中,这种方式在后期代码会很大,并且改动一个小的布局,则会影响大。这样到后期每每只敢加代码,而不敢删除代码……
      • 有时候难以适应新的场景,好比添加一个播放广告,老师开课,或者视频引导业务需求,则须要到播放器中写一堆业务代码。迭代到后期,违背了开闭原则,视频播放器须要作到和业务分离
    • 视频播放器结构不清晰服务器

      • 这个是指该视频播放器可否看了文档后快速上手,知道封装的大概流程。方便后期他人修改和维护,所以须要将视频播放器功能分离。好比切换内核+视频播放器(player+controller+view)
  • 须要达到的目的和效果

    • 基础封装视频播放器player,能够在ExoPlayer、MediaPlayer,声网RTC视频播放器内核,原生MediaPlayer能够自由切换
    • 对于视图状态切换和后期维护拓展,避免功能和业务出现耦合。好比须要支持播放器UI高度定制,而不是该lib库中UI代码
    • 针对视频播放,视频投屏,音频播放,播放回放,以及视频直播的功能
  • 通用视频框架特色

    • 必定要解耦合

      • 播放器内核与播放器解耦: 支持更多的播放场景、以及新的播放业务快速接入,而且不影响其余播放业务,好比后期添加阿里云播放器内核,或者腾讯播放器内核
      • 播放器player与视频UI解耦:支持添加自定义视频视图,好比支持添加自定义广告,新手引导,或者视频播放异常等视图,这个须要较强的拓展性
    • 适合多种业务场景

      • 好比适合播放单个视频,多个视频,以及列表视频,或者相似抖音那种一个页面一个视频,还有小窗口播放视频。也就是适合大多数业务场景
  • 视频分层

    • 播放器内核

      • 能够切换ExoPlayer、MediaPlayer,IjkPlayer,声网视频播放器,这里使用工厂模式Factory + AbstractVideoPlayer + 各个实现AbstractVideoPlayer抽象类的播放器类
      • 定义抽象的播放器,主要包含视频初始化,设置,状态设置,以及播放监听。因为每一个内核播放器api可能不同,因此这里须要实现AbstractVideoPlayer抽象类的播放器类,方便后期统一调用
      • 为了方便建立不一样内核player,因此须要建立一个PlayerFactory,定义一个createPlayer建立播放器的抽象方法,而后各个内核都实现它,各自建立本身的播放器
    • VideoPlayer播放器

      • 能够自由切换视频内核,Player+Controller。player负责播放的逻辑,Controller负责视图相关的逻辑,二者之间用接口进行通讯
      • 针对Controller,须要定义一个接口,主要负责视图UI处理逻辑,支持添加各类自定义视图View【统一实现自定义接口Control】,每一个view尽可能保证功能单一性,最后经过addView形式添加进来
      • 针对Player,须要定义一个接口,主要负责视频播放处理逻辑,好比视频播放,暂停,设置播放进度,设置视频连接,切换播放模式等操做。须要注意把Controller设置到Player里面,二者之间经过接口交互
    • UI控制器视图

      • 定义一个BaseVideoController类,这个主要是集成各类事件的处理逻辑,好比播放器状态改变,控制视图隐藏和显示,播放进度改变,锁定状态改变,设备方向监听等等操做
      • 定义一个view的接口InterControlView,在这里类里定义绑定视图,视图隐藏和显示,播放状态,播放模式,播放进度,锁屏等操做。这个每一个实现类则均可以拿到这些属性呢
      • 在BaseVideoController中使用LinkedHashMap保存每一个自定义view视图,添加则put进来后而后经过addView将视图添加到该控制器中,这样很是方便添加自定义视图
      • 播放器切换状态须要改变Controller视图,好比视频异常则须要显示异常视图view,则它们之间的交互是经过ControlWrapper(同时实现Controller接口和Player接口)实现

04.视频播放器如何使用

4.1 关于gradle引用说明

  • 以下所示

    //视频UI层,必需要有
    implementation 'cn.yc:VideoPlayer:3.0.1'
    //视频缓存,若是不须要则能够不依赖
    implementation 'cn.yc:VideoCache:3.0.0'
    //视频内核层,必须有
    implementation 'cn.yc:VideoKernel:3.0.1'

4.2 在xml中添加布局

  • 注意,在实际开发中,因为Android手机碎片化比较严重,分辨率太多了,建议灵活设置布局的宽高比为4:3或者16:9或者你认为合适的,能够用代码设置。
  • 若是宽高比变形,则会有黑边

    <org.yczbj.ycvideoplayerlib.player.VideoPlayer
        android:id="@+id/video_player"
        android:layout_width="match_parent"
        android:layout_height="240dp"/>

4.3 最简单的视频播放器参数设定

  • 以下所示

    //建立基础视频播放器,通常播放器的功能
    BasisVideoController controller = new BasisVideoController(this);
    //设置控制器
    mVideoPlayer.setVideoController(controller);
    //设置视频播放连接地址
    mVideoPlayer.setUrl(url);
    //开始播放
    mVideoPlayer.start();

4.4 注意问题

  • 若是是全屏播放,则须要在清单文件中设置当前activity的属性值

    • android:configChanges 保证了在全屏的时候横竖屏切换不会执行Activity的相关生命周期,打断视频的播放
    • android:screenOrientation 固定了屏幕的初始方向
    • 这两个变量控制全屏后和退出全屏的屏幕方向

      <activity android:name=".VideoActivity"
              android:configChanges="orientation|keyboardHidden|screenSize"
              android:screenOrientation="portrait"/>
  • 如何一进入页面就开始播放视频,稍微延时一下便可

    • 代码以下所示,注意避免直接start(),由于有可能视频尚未初始化完成……

      mVideoPlayer.postDelayed(new Runnable() {
          @Override
          public void run() {
              mVideoPlayer.start();
          }
      },300);

05.播放器详细Api文档

  • 01.最简单的播放
  • 02.如何切换视频内核
  • 03.切换视频模式
  • 04.切换视频清晰度
  • 05.视频播放监听
  • 06.列表中播放处理
  • 07.悬浮窗口播放
  • 08.其余重要功能Api
  • 09.播放多个视频
  • 10.VideoPlayer相关Api
  • 11.Controller相关Api
  • 12.仿快手播放视频
  • 具体看这篇文档:[视频播放器Api说明]()

06.播放器封装思路

6.1视频层级示例图

image

6.2 视频播放器流程图

  • 待完善

6.3 视频播放器lib库

image

6.4 视频内核lib库介绍

image
image

6.5视频播放器UI库介绍

image

07.播放器示例展现图

image
image
image
image
image
image
image
image
image
image

08.添加自定义视图

  • 好比,如今有个业务需求,须要在视频播放器刚开始添加一个广告视图,等待广告倒计时120秒后,直接进入播放视频逻辑。相信这个业务场景很常见,你们都碰到过,使用该播放器就特别简单,代码以下所示:
  • 首先建立一个自定义view,须要实现InterControlView接口,重写该接口中全部抽象方法,这里省略了不少代码,具体看demo。

    public class AdControlView extends FrameLayout implements InterControlView, View.OnClickListener {
    
        private ControlWrapper mControlWrapper;
        public AdControlView(@NonNull Context context) {
            super(context);
            init(context);
        }
    
        private void init(Context context){
            LayoutInflater.from(getContext()).inflate(R.layout.layout_ad_control_view, this, true);
        }
       
        /**
         * 播放状态
         * -1               播放错误
         * 0                播放未开始
         * 1                播放准备中
         * 2                播放准备就绪
         * 3                正在播放
         * 4                暂停播放
         * 5                正在缓冲(播放器正在播放时,缓冲区数据不足,进行缓冲,缓冲区数据足够后恢复播放)
         * 6                暂停缓冲(播放器正在播放时,缓冲区数据不足,进行缓冲,此时暂停播放器,继续缓冲,缓冲区数据足够后恢复暂停
         * 7                播放完成
         * 8                开始播放停止
*/
    @Override
    public void onPlayStateChanged(int playState) {
        switch (playState) {
            case ConstantKeys.CurrentState.STATE_PLAYING:
                mControlWrapper.startProgress();
                mPlayButton.setSelected(true);
                break;
            case ConstantKeys.CurrentState.STATE_PAUSED:
                mPlayButton.setSelected(false);
                break;
        }
    }

    /**
     * 播放模式
     * 普通模式,小窗口模式,正常模式三种其中一种
     * MODE_NORMAL              普通模式
     * MODE_FULL_SCREEN         全屏模式
     * MODE_TINY_WINDOW         小屏模式
     * @param playerState                   播放模式
     */
    @Override
    public void onPlayerStateChanged(int playerState) {
        switch (playerState) {
            case ConstantKeys.PlayMode.MODE_NORMAL:
                mBack.setVisibility(GONE);
                mFullScreen.setSelected(false);
                break;
            case ConstantKeys.PlayMode.MODE_FULL_SCREEN:
                mBack.setVisibility(VISIBLE);
                mFullScreen.setSelected(true);
                break;
        }
        //暂未实现全面屏适配逻辑,须要你本身补全
    }
}
```
  • 而后该怎么使用这个自定义view呢?很简单,在以前基础上,经过控制器对象add进来便可,代码以下所示

    controller = new BasisVideoController(this);
    AdControlView adControlView = new AdControlView(this);
    adControlView.setListener(new AdControlView.AdControlListener() {
        @Override
        public void onAdClick() {
            BaseToast.showRoundRectToast( "广告点击跳转");
        }
    
        @Override
        public void onSkipAd() {
            playVideo();
        }
    });
    controller.addControlComponent(adControlView);
    //设置控制器
    mVideoPlayer.setController(controller);
    mVideoPlayer.setUrl(proxyUrl);
    mVideoPlayer.start();

09.视频播放器优化处理

9.1 如何兼容不一样内核播放器

  • 提问:针对不一样内核播放器,好比谷歌的ExoPlayer,B站的IjkPlayer,还有原生的MediaPlayer,有些api不同,那使用的时候如何统一api呢?

    • 好比说,ijk和exo的视频播放listener监听api就彻底不一样,这个时候须要作兼容处理
    • 定义接口,而后各个不一样内核播放器实现接口,重写抽象方法。调用的时候,获取接口对象调用api,这样就能够统一Api
  • 定义一个接口,这个接口有什么呢?这个接口定义通用视频播放器方法,好比常见的有:视频初始化,设置url,加载,以及播放状态,简单来讲能够分为三个部分。

    • 第一部分:视频初始化实例对象方法,主要包括:initPlayer初始化视频,setDataSource设置视频播放器地址,setSurface设置视频播放器渲染view,prepareAsync开始准备播放操做
    • 第二部分:视频播放器状态方法,主要包括:播放,暂停,恢复,重制,设置进度,释放资源,获取进度,设置速度,设置音量
    • 第三部分:player绑定view后,须要监听播放状态,好比播放异常,播放完成,播放准备,播放size变化,还有播放准备
  • 首先定义一个工厂抽象类,而后不一样的内核播放器分别建立其具体的工厂实现具体类

    • PlayerFactory:抽象工厂,担任这个角色的是工厂方法模式的核心,任何在模式中建立对象的工厂类必须实现这个接口
    • ExoPlayerFactory:具体工厂,具体工厂角色含有与业务密切相关的逻辑,而且受到使用者的调用以建立具体产品对象。
  • 如何使用,分为三步,具体操做以下所示

    • 1.先调用具体工厂对象中的方法createPlayer方法;2.根据传入产品类型参数得到具体的产品对象;3.返回产品对象并使用。
    • 简而言之,建立对象的时候只须要传递类型type,而不须要对应的工厂,便可建立具体的产品对象
  • 这种建立对象最大优势

    • 工厂方法用来建立所须要的产品,同时隐藏了哪一种具体产品类将被实例化这一细节,用户只须要关心所需产品对应的工厂,无须关心建立细节,甚至无须知道具体产品类的类名。
    • 加入新的产品时,好比后期新加一个阿里播放器内核,这个时候就只须要添加一个具体工厂和具体产品就能够。系统的可扩展性也就变得很是好,彻底符合“开闭原则”

9.2 播放器UI抽取封装优化

  • 发展中遇到的问题

    • 播放器可支持多种场景下的播放,多个产品会用到同一个播放器,这样就会带来一个问题,一个播放业务播放器状态发生变化,其余播放业务必须同步更新播放状态,各个播放业务之间互相交叉,随着播放业务的增多,开发和维护成本会急剧增长, 致使后续开发不可持续。
  • UI难以自定义或者修改麻烦

    • 好比常见的视频播放器,会把视频各类视图写到xml中,这种方式在后期代码会很大,并且改动一个小的布局,则会影响大。这样到后期每每只敢加代码,而不敢删除代码……
    • 有时候难以适应新的场景,好比添加一个播放广告,老师开课,或者视频引导业务需求,则须要到播放器中写一堆业务代码。迭代到后期,违背了开闭原则,视频播放器须要作到和业务分离
  • 视频播放器结构须要清晰

    • 也就是说视频player和ui操做柔和到了一块儿,尤为是二者之间的交互。好比播放中须要更新UI进度条,播放异常须要显示异常UI,都比较难处理播放器状态变化更新UI操做
    • 这个是指该视频播放器可否看了文档后快速上手,知道封装的大概流程。方便后期他人修改和维护,所以须要将视频播放器功能分离。好比切换内核+视频播放器(player+controller+view)
    • 必定要解耦合,播放器player与视频UI解耦:支持添加自定义视频视图,好比支持添加自定义广告,新手引导,或者视频播放异常等视图,这个须要较强的拓展性
  • 适合多种业务场景

    • 好比适合播放单个视频,多个视频,以及列表视频,或者相似抖音那种一个页面一个视频,还有小窗口播放视频。也就是适合大多数业务场景
  • 方便播放业务发生变化

    • 播放状态变化是致使不一样播放业务场景之间交叉同步,解除播放业务对播放器的直接操控,采用接口监听进行解耦。好比:player+controller+interface
  • 关于视频播放器

    • 定义一个视频播放器InterVideoPlayer接口,操做视频播放,暂停,缓冲,进度设置,设置播放模式等多种操做。
    • 而后写一个播放器接口的具体实现类,在这个里面拿到内核播放器player,而后作相关的实现操做。
  • 关于视频视图View

    • 定义一个视图InterVideoController接口,主要负责视图显示/隐藏,播放进度,锁屏,状态栏等操做。
    • 而后写一个播放器视图接口的具体实现类,在这里里面inflate视图操做,而后接口方法实现,为了方便后期开发者自定义view,所以须要addView操做,将添加进来的视图用map集合装起来。
  • 播放器player和controller交互

    • 在player中建立BaseVideoController对象,这个时候须要把controller添加到播放器中,这个时候有两个要点特别重要,须要把播放器状态监听,和播放模式监听传递给控制器
    • setPlayState设置视频播放器播放逻辑状态,主要是播放缓冲,加载,播放中,暂停,错误,完成,异常,播放进度等多个状态,方便控制器作UI更新操做
    • setPlayerState设置视频播放切换模式状态,主要是普通模式,小窗口模式,正常模式三种其中一种,方便控制器作UI更新
  • 播放器player和view交互

    • 这块很是关键,举个例子,视频播放失败须要显示控制层的异常视图View;播放视频初始化须要显示loading,而后更新UI播放进度条等。都是播放器和视图层交互
    • 能够定义一个类,同时实现InterVideoPlayer接口和InterVideoController接口,这个时候会从新这两个接口全部的方法。此类的目的是为了在InterControlView接口实现类中既能调用VideoPlayer的api又能调用BaseVideoController的api
  • 如何添加自定义播放器视图

    • 添加了自定义播放器视图,好比添加视频广告,能够选择跳过,选择播放暂停。那这个视图view,确定是须要操做player或者获取player的状态的。这个时候就须要暴露监听视频播放的状态接口监听
    • 首先定义一个InterControlView接口,也就是说全部自定义视频视图view须要实现这个接口,该接口中的核心方法有:绑定视图到播放器,视图显示隐藏变化监听,播放状态监听,播放模式监听,进度监听,锁屏监听等
    • 在BaseVideoController中的状态监听中,经过InterControlView接口对象就能够把播放器的状态传递到子类中

9.4 代码方面优化措施

  • 若是是在Activity中的话,建议设置下面这段代码

    @Override
    protected void onResume() {
        super.onResume();
        if (mVideoPlayer != null) {
            //从后台切换到前台,当视频暂停时或者缓冲暂停时,调用该方法从新开启视频播放
            mVideoPlayer.resume();
        }
    }
@Override
protected void onPause() {
    super.onPause();
    if (mVideoPlayer != null) {
        //从前台切到后台,当视频正在播放或者正在缓冲时,调用该方法暂停视频
        mVideoPlayer.pause();
    }
}

@Override
protected void onDestroy() {
    super.onDestroy();
    if (mVideoPlayer != null) {
        //销毁页面,释放,内部的播放器被释放掉,同时若是在全屏、小窗口模式下都会退出
        mVideoPlayer.release();
    }
}

@Override
public void onBackPressed() {
    //处理返回键逻辑;若是是全屏,则退出全屏;若是是小窗口,则退出小窗口
    if (mVideoPlayer == null || !mVideoPlayer.onBackPressed()) {
        super.onBackPressed();
    }
}
```

10.播放器问题记录说明

11.性能优化和库大小

12.视频缓存原理介绍

  • 网络上比较好的项目:https://github.com/danikula/A...

    • 网络用的HttpURLConnection,文件缓存处理,文件最大限度策略,回调监听处理,断点续传,代理服务等。
  • 可是存在一些问题,好比以下所示

    • 文件的缓存超过限制后没有按照lru算法删除,
    • 处理返回给播放器的http响应头消息,响应头消息的获取处理改成head请求(需服务器支持)
    • 替换网络库为okHttp(由于大部分的项目都是以okHttp为网络请求库的),可是这个改动性比较大
  • 而后看一下怎么使用,超级简单。传入视频url连接,返回一个代理连接,而后就能够呢

    HttpProxyCacheServer cacheServer = ProxyVideoCacheManager.getProxy(this);
    String proxyUrl = cacheServer.getProxyUrl(URL_AD);
    mVideoPlayer.setUrl(proxyUrl);
    
    
    public static HttpProxyCacheServer getProxy(Context context) {
        return sharedProxy == null ? (sharedProxy = newProxy(context)) : sharedProxy;
    }
    
    private static HttpProxyCacheServer newProxy(Context context) {
        return new HttpProxyCacheServer.Builder(context)
                .maxCacheSize(512 * 1024 * 1024)       // 512MB for cache
                //缓存路径,不设置默认在sd_card/Android/data/[app_package_name]/cache中
                //.cacheDirectory()
                .build();
    }
  • 大概的原理

    • 原始的方式是直接塞播放地址给播放器,它就能够直接播放。如今咱们要在中间加一层本地代理,播放器播放的时候(获取数据)是经过咱们的本地代理的地址来播放的,这样咱们就能够很好的在中间层(本地代理层)作一些处理,好比:文件缓存,预缓存(秒开处理),监控等。
  • 原理详细一点来讲

    • 1.采用了本地代理服务的方式,经过原始url给播放器返回一个本地代理的一个url ,代理URL相似:http://127.0.0.1:port/视频url;(port端口为系统随机分配的有效端口,真实url是为了真正的下载),而后播放器播放的时候请求到了你本地的代理上了。
    • 2.本地代理采用ServerSocket监听127.0.0.1的有效端口,这个时候手机就是一个服务器了,客户端就是socket,也就是播放器。
    • 3.读取客户端就是socket来读取数据(http协议请求)解析http协议。
    • 4.根据url检查视频文件是否存在,读取文件数据给播放器,也就是往socket里写入数据(socket通讯)。同时若是没有下载完成会进行断点下载,固然弱网的话数据须要生产消费同步处理。
  • 如何实现预加载

    • 其实预加载的思路很简单,在进行一个播放视频后,再返回接下来须要预加载的视频url,启用线程去请求下载数据
    • 开启一个线程去请求并预加载一部分的数据,可能须要预加载的数据大于>1,利用队列先进入的先进行加载,所以能够采用LinkedHashMap保存正在预加载的task。
    • 在开始预加载的时候,判断该播放地址是否已经预加载,若是不是那么建立一个线程task,而且把它放到map集合中。而后执行预加载逻辑,也就是执行HttpURLConnection请求
    • 提供取消对应url加载的任务,由于有可能该url不须要再进行预加载了,好比参考抖音,当用户瞬间下滑几个视频,那么不少视频就须要跳过了不须要再进行预加载
  • 具体直接看项目代码:VideoCache缓冲模块

13.查看视频播放器日志

  • 统一管理视频播放器封装库日志,方便后期排查问题

    • 好比,视频内核,日志过滤则是:aaa
    • 好比,视频player,日志过滤则是:bbb
    • 好比,缓存模块,日志过滤则是:VideoCache

14.该库异常code说明

  • 针对视频封装库,统一处理抛出的异常,为了方便开发者快速知道异常的来由,则能够查询约定的code码。

    • 这个在sdk中特别常见,所以该库必定程度是借鉴腾讯播放器……

视频框架:https://github.com/yangchong2...

相关文章
相关标签/搜索