Browse Source

更新demo案例

杨充 4 years ago
parent
commit
39f84708c8
3 changed files with 57 additions and 268 deletions
  1. 55 268
      README.md
  2. BIN
      image/播放器框架总图.jpg
  3. 2 0
      read/04.视频播放器封装思路.md

+ 55 - 268
README.md

@@ -11,7 +11,6 @@
 - 09.视频播放器优化处理
 - 10.播放器问题记录说明
 - 11.性能优化和库大小
-- 12.视频缓存原理介绍
 - 13.查看视频播放器日志
 - 14.该库异常code说明
 - 15.该库系列wiki文档
@@ -19,8 +18,15 @@
 
 
 
+### 00.视频播放器通用框架
+- 基础封装视频播放器player,可以在ExoPlayer、MediaPlayer,声网RTC视频播放器内核,原生MediaPlayer可以自由切换
+- 对于视图状态切换和后期维护拓展,避免功能和业务出现耦合。比如需要支持播放器UI高度定制,而不是该lib库中UI代码
+- 针对视频播放,音频播放,播放回放,音视频切换的功能。使用简单,代码拓展性强,封装性好,主要是和业务彻底解耦,暴露接口监听给开发者处理业务具体逻辑
+- 该播放器整体架构:播放器内核(自由切换) +  视频播放器 + 边播边缓存 + 高度定制播放器UI视图层
+
+
+
 ### 01.该视频播放器介绍
-#### 1.1 该库说明
 |**播放器功能** | MediaPlayer | ExoPlayer | IjkPlayer | RTC | TXPlayer |
 |--------   |-----        |---        |---        |---  |---     |
 |**UI/Player/业务解耦**| 支持  |支持   |支持   |   |   |
@@ -47,7 +53,7 @@
 
 
 
-#### 1.2 该库功能说明
+### 02.视频播放器功能
 |**类型** | 功能说明 |
 |--------   |-----        |
 |**项目结构** | VideoCache缓存lib,VideoKernel视频内核lib,VideoPlayer视频UIlib |
@@ -61,38 +67,12 @@
 
 
 
+### 03.视频播放器结构说明
+#### 3.1 视频播放器架构图
+![image](https://img-blog.csdnimg.cn/20201016173604612.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NzAwMjc1,size_16,color_FFFFFF,t_70#pic_center)
 
 
-### 02.视频播放器功能
-- A基础功能
-    - 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高级功能
-    - 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会有这个工鞥】
-    - C1产品需求:类似优酷,爱奇艺视频播放器部分逻辑。比如如果用户没有登录也没有看视频权限,则提示试看视频[自定义布局];如果用户没有登录但是有看视频权限,则正常观看;如果用户登录,但是没有充值会员,部分需要权限视频则进入试看模式,试看结束后弹出充值会员界面;如果用户余额不足,比如余额只有99元,但是视频观看要199元,则又有其他提示。
-    - C2自身需求:比如封装好了视频播放库,那么点击视频上登录按钮则跳到登录页面;点击充值会员页面也跳到充值页面。这个通过定义接口,可以让使用者通过方法调用,灵活处理点击事件。
-    - C.1.1 可以设置试看模式,设置试看时长。试看结束后就提示登录或者充值……
-    - C.1.2 对于设置视频的宽高,建议设置成4:3或者16:9或者常用比例,如果不是常用比例,则可能会有黑边。其中黑边的背景可以设置
-    - C.1.3 可以设置播放有权限的视频时的各种文字描述,而没有把它写在封装库中,使用者自己设定
-    - C.1.4 锁定屏幕功能,这个参考大部分播放器,只有在全屏模式下才会有
-
-
-
-
-### 03.视频播放器结构说明
+#### 3.2 播放器视图分类
 - 视频常见的布局视图
     - 视频底图(用于显示初始化视频时的封面图),视频状态视图【加载loading,播放异常,加载视频失败,播放完成等】
     - 改变亮度和声音【改变声音视图,改变亮度视图】,改变视频快进和快退,左右滑动快进和快退视图(手势滑动的快进快退提示框)
@@ -104,33 +84,38 @@
     - 图片广告视图(带有倒计时消失),开始视频广告视图,非会员试看视图
     - 弹幕视图(这个很重要),水印显示视图,倍速播放界面(用于控制倍速),底部视频列表缩略图视图
     - 投屏视频视图界面,视频直播间刷礼物界面,老师开课界面,展示更多视图(下载,分享,切换音频等)
-- 视频播放器的痛点
-    - 播放器内核难以切换
-        - 不同的视频播放器内核,由于api不一样,所以难以切换操作。要是想兼容内核切换,就必须自己制定一个视频接口+实现类的播放器
-    - 播放器内核和UI层耦合
-        - 也就是说视频player和ui操作柔和到了一起,尤其是两者之间的交互。比如播放中需要更新UI进度条,播放异常需要显示异常UI,都比较难处理播放器状态变化更新UI操作
-    - UI难以自定义或者修改麻烦
-        - 比如常见的视频播放器,会把视频各种视图写到xml中,这种方式在后期代码会很大,而且改动一个小的布局,则会影响大。这样到后期往往只敢加代码,而不敢删除代码……
-        - 有时候难以适应新的场景,比如添加一个播放广告,老师开课,或者视频引导业务需求,则需要到播放器中写一堆业务代码。迭代到后期,违背了开闭原则,视频播放器需要做到和业务分离
-    - 视频播放器结构不清晰
-        - 这个是指该视频播放器能否看了文档后快速上手,知道封装的大概流程。方便后期他人修改和维护,因此需要将视频播放器功能分离。比如切换内核+视频播放器(player+controller+view)
+
+
+#### 3.3 播放器痛点
+- 播放器内核难以切换
+    - 不同的视频播放器内核,由于api不一样,所以难以切换操作。要是想兼容内核切换,就必须自己制定一个视频接口+实现类的播放器
+- 播放器内核和UI层耦合
+    - 也就是说视频player和ui操作柔和到了一起,尤其是两者之间的交互。比如播放中需要更新UI进度条,播放异常需要显示异常UI,都比较难处理播放器状态变化更新UI操作
+- UI难以自定义或者修改麻烦
+    - 比如常见的视频播放器,会把视频各种视图写到xml中,这种方式在后期代码会很大,而且改动一个小的布局,则会影响大。这样到后期往往只敢加代码,而不敢删除代码……
+    - 有时候难以适应新的场景,比如添加一个播放广告,老师开课,或者视频引导业务需求,则需要到播放器中写一堆业务代码。迭代到后期,违背了开闭原则,视频播放器需要做到和业务分离
+- 视频播放器结构不清晰
+    - 这个是指该视频播放器能否看了文档后快速上手,知道封装的大概流程。方便后期他人修改和维护,因此需要将视频播放器功能分离。比如切换内核+视频播放器(player+controller+view)
+
+
+
+#### 3.4 播放器达到的目的
 - 需要达到的目的和效果
     - 基础封装视频播放器player,可以在ExoPlayer、MediaPlayer,声网RTC视频播放器内核,原生MediaPlayer可以自由切换
     - 对于视图状态切换和后期维护拓展,避免功能和业务出现耦合。比如需要支持播放器UI高度定制,而不是该lib库中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将视图添加到该控制器中,这样非常方便添加自定义视图
+- 播放器内核
+    - 可以切换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接口)实现
 
 
@@ -250,179 +235,23 @@
 
 
 ### 08.添加自定义视图
-- 比如,现在有个业务需求,需要在视频播放器刚开始添加一个广告视图,等待广告倒计时120秒后,直接进入播放视频逻辑。相信这个业务场景很常见,大家都碰到过,使用该播放器就特别简单,代码如下所示:
-- 首先创建一个自定义view,需要实现InterControlView接口,重写该接口中所有抽象方法,这里省略了很多代码,具体看demo。
-    ``` java
-    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);
-        }
-       
-        @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;
-            }
-        }
-    
-        @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进来即可,代码如下所示
-    ``` java
-    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();
-    ```
+- 如何兼容不同内核播放器
+    - 具体看这篇文章:[06.播放器UI抽取封装](https://juejin.im/post/6884028627697500167#heading-9)
+
 
 
 ### 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.3 如何全局监控视频埋点
-- 传统一点的做法
-    - 比如用友盟或者百度统计,或者用其他的统计。之前的做法是,在每个有视频的页面比如说Activity,Fragment等开启时视频播放时埋点一次,页面退出时埋点一次。
-    - 如果app中有多个activity或者fragment页面,那么就每个页面都要进行埋点。比如如果你的app是付费视频,你想知道有多少人试看了,该怎么操作。那么你需要在每一个有视频的activity页面挨个添加埋点,那还有没有更好的办法?
-- 解决方案
-    - 举个例子:例如,你需要来让外部开发者手动去埋点,可是在类中怎么埋点又是由其他人来设计的,你只是需要对外暴露监听的方法。那么该如何做呢?采用接口 + 实现类方式即可实现。
-- 该案例中怎么操作
-    - 定义一个接口,规定其他人设计类,必须继承这个接口。在这个接口中,定义进入视频播放,退出视频播放器,记录播放进度,视频播放完成,播放异常,点击广告,点击试看等操作的抽象方法。具体可以看BuriedPointEvent类代码……
-- 外部开发者如何使用
-    - 定义一个类实现该视频埋点接口,重写里面方法。然后需要在初始化配置视频播放器的时候,将这个实现类的对象传递进来即可。通过这个配置类传进来的对象,播放器就可以处理监听设置逻辑呢。
-    - 这种操作最大的好处就是:在这个类中统一处理视频的埋点,修改快捷,而不用在每一个有视频播放器的页面埋点,方便维护。具体可以看代码案例。
-
-
-#### 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();
-        }
-    }
-    ```
+- 如何兼容不同内核播放器
+    - 具体看这篇文章:[05.视频播放器内核切换封装](https://juejin.im/post/6884023527473856520)
+- 播放器UI抽取封装优化
+    - 具体看这篇文章:[06.播放器UI抽取封装](https://juejin.im/post/6884028627697500167)
+- 视频缓存原理介绍
+    - 具体看这篇文章:[12.视频边播边缓存分析](https://github.com/yangchong211/YCVideoPlayer/blob/master/read/12.%E8%A7%86%E9%A2%91%E8%BE%B9%E6%92%AD%E8%BE%B9%E7%BC%93%E5%AD%98%E5%88%86%E6%9E%90.md)
+- 如何全局监控视频埋点
+    - 具体看这篇文章:[29.视频播放器埋点监听](https://github.com/yangchong211/YCVideoPlayer/blob/master/read/29.%E8%A7%86%E9%A2%91%E6%92%AD%E6%94%BE%E5%99%A8%E5%9F%8B%E7%82%B9%E7%9B%91%E5%90%AC.md)
+- 代码方面优化措施
+    - 具体看这篇文章:[08.视频播放器优化处理](https://github.com/yangchong211/YCVideoPlayer/blob/master/read/08.%E8%A7%86%E9%A2%91%E6%92%AD%E6%94%BE%E5%99%A8%E4%BC%98%E5%8C%96%E5%A4%84%E7%90%86.md)
+
 
 
 ### 10.播放器问题记录说明
@@ -435,51 +264,9 @@
 
 
 
-
 ### 11.性能优化和库大小
 
 
-### 12.视频缓存原理介绍
-- 网络上比较好的项目:https://github.com/danikula/AndroidVideoCache
-    - 网络用的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.查看视频播放器日志
 - 统一管理视频播放器封装库日志,方便后期排查问题

BIN
image/播放器框架总图.jpg


+ 2 - 0
read/04.视频播放器封装思路.md

@@ -20,6 +20,8 @@
 - 对于视图状态切换和后期维护拓展,避免功能和业务出现耦合。比如需要支持播放器UI高度定制,而不是该lib库中UI代码
 - 针对视频播放,音频播放,播放回放,以及视频直播的功能。使用简单,代码拓展性强,封装性好,主要是和业务彻底解耦,暴露接口监听给开发者处理业务具体逻辑
 - 该播放器整体架构:播放器内核(自由切换) +  视频播放器 + 边播边缓存 + 高度定制播放器UI视图层
+- ![image](https://img-blog.csdnimg.cn/20201016173604612.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NzAwMjc1,size_16,color_FFFFFF,t_70#pic_center)
+
 
 
 ### 01.视频播放器的痛点