大數據

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、m3u8、mkv、webm、mp3、mp4等
畫面 調整顯示比例:默認、16:9、4:3、填充;播放時旋轉畫面角度(0,90,180,270);鏡像旋轉
佈局 內核和UI分離,和市面GitHub上大多數播放器不一樣,方便定製,通過addView添加
播放 正常播放,小窗播放,列表播放,仿抖音播放
自定義 可以自定義添加視頻UI層,可以說UI和Player高度分離,支持自定義渲染層SurfaceView

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.視頻播放器架構說明

  • 視頻常見的佈局視圖

    • 視頻底圖(用於顯示初始化視頻時的封面圖),視頻狀態視圖【加載loading,播放異常,加載視頻失敗,播放完成等】
    • 改變亮度和聲音【改變聲音視圖,改變亮度視圖】,改變視頻快進和快退,左右滑動快進和快退視圖(手勢滑動的快進快退提示框)
    • 頂部控制區視圖(包含返回健,title等),底部控制區視圖(包含進度條,播放暫停,時間,切換全屏等)
    • 鎖屏佈局視圖(全屏時展示,其他隱藏),底部播放進度條視圖(很多播放器都有這個),清晰度列表視圖(切換清晰度彈窗)
  • 後期可能涉及的佈局視圖

    • 手勢指導頁面(有些播放器有新手指導功能),離線下載的界面(該界面中包含下載列表, 列表的item編輯(全選, 刪除))
    • 用戶從wifi切換到4g網絡,提示網絡切換彈窗界面(當網絡由wifi變為4g的時候會顯示)
    • 圖片廣告視圖(帶有倒計時消失),開始視頻廣告視圖,非會員試看視圖
    • 彈幕視圖(這個很重要),水印顯示視圖,倍速播放界面(用於控制倍速),底部視頻列表縮略圖視圖
    • 投屏視頻視圖界面,視頻直播間刷禮物界面,老師開課界面,展示更多視圖(下載,分享,切換音頻等)
  • 視頻播放器的痛點

    • 播放器內核難以切換

      • 不同的視頻播放器內核,由於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                開始播放中止
         * @param playState                     播放狀態,主要是指播放器的各種狀態
         */
        @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/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.查看視頻播放器日誌

  • 統一管理視頻播放器封裝庫日誌,方便後期排查問題

    • 比如,視頻內核,日誌過濾則是:aaa
    • 比如,視頻player,日誌過濾則是:bbb
    • 比如,緩存模塊,日誌過濾則是:VideoCache

14.該庫異常code說明

  • 針對視頻封裝庫,統一處理拋出的異常,為了方便開發者快速知道異常的來由,則可以查詢約定的code碼。

    • 這個在sdk中特別常見,因此該庫一定程度是借鑑騰訊播放器……

視頻框架:https://github.com/yangchong211/YCVideoPlayer

Leave a Reply

Your email address will not be published. Required fields are marked *