視訊播放器介紹文檔
目錄介紹
- 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視圖層
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 |
- 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 鎖定螢幕功能,這個參考大部分播放器,隻有在全屏模式下才會有
- 視訊常見的布局視圖
- 視訊底圖(用于顯示初始化視訊時的封面圖),視訊狀态視圖【加載loading,播放異常,加載視訊失敗,播放完成等】
- 改變亮度和聲音【改變聲音視圖,改變亮度視圖】,改變視訊快進和快退,左右滑動快進和快退視圖(手勢滑動的快進快退提示框)
- 頂部控制區視圖(包含傳回健,title等),底部控制區視圖(包含進度條,播放暫停,時間,切換全屏等)
- 鎖屏布局視圖(全屏時展示,其他隐藏),底部播放進度條視圖(很多點傳播放器都有這個),清晰度清單視圖(切換清晰度彈窗)
- 後期可能涉及的布局視圖
- 手勢指導頁面(有些播放器有新手指導功能),離線下載下傳的界面(該界面中包含下載下傳清單, 清單的item編輯(全選, 删除))
- 使用者從wifi切換到4g網絡,提示網絡切換彈窗界面(當網絡由wifi變為4g的時候會顯示)
- 圖檔廣告視圖(帶有倒計時消失),開始視訊廣告視圖,非會員試看視圖
- 彈幕視圖(這個很重要),水印顯示視圖,倍速播放界面(用于控制倍速),底部視訊清單縮略圖視圖
- 投屏視訊視圖界面,視訊直播間刷禮物界面,老師開課界面,展示更多視圖(下載下傳,分享,切換音頻等)
- 視訊播放器的痛點
- 播放器核心難以切換
- 不同的視訊播放器核心,由于api不一樣,是以難以切換操作。要是想相容核心切換,就必須自己制定一個視訊接口+實作類的播放器
- 播放器核心和UI層耦合
- 也就是說視訊player和ui操作柔和到了一起,尤其是兩者之間的互動。比如播放中需要更新UI進度條,播放異常需要顯示異常UI,都比較難處理播放器狀态變化更新UI操作
- UI難以自定義或者修改麻煩
- 比如常見的視訊播放器,會把視訊各種視圖寫到xml中,這種方式在後期代碼會很大,而且改動一個小的布局,則會影響大。這樣到後期往往隻敢加代碼,而不敢删除代碼……
- 有時候難以适應新的場景,比如添加一個播放廣告,老師開課,或者視訊引導業務需求,則需要到播放器中寫一堆業務代碼。疊代到後期,違背了開閉原則,視訊播放器需要做到和業務分離
- 視訊播放器結構不清晰
- 這個是指該視訊播放器能否看了文檔後快速上手,知道封裝的大概流程。友善後期他人修改和維護,是以需要将視訊播放器功能分離。比如切換核心+視訊播放器(player+controller+view)
- 播放器核心難以切換
- 需要達到的目的和效果
- 針對視訊播放,視訊投屏,音頻播放,播放回放,以及視訊直播的功能
- 通用視訊架構特點
- 一定要解耦合
- 播放器核心與播放器解耦: 支援更多的播放場景、以及新的播放業務快速接入,并且不影響其他播放業務,比如後期添加阿裡雲播放器核心,或者騰訊播放器核心
- 播放器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接口)實作
- 播放器核心
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);
- 代碼如下所示,注意避免直接start(),因為有可能視訊還沒有初始化完成……
- 01.最簡單的播放
- 02.如何切換視訊核心
- 03.切換視訊模式
- 04.切換視訊清晰度
- 05.視訊播放監聽
- 06.清單中播放處理
- 07.懸浮視窗播放
- 08.其他重要功能Api
- 09.播放多個視訊
- 10.VideoPlayer相關Api
- 11.Controller相關Api
- 12.仿快手播放視訊
- 具體看這篇文檔:[視訊播放器Api說明]()
6.1視訊層級示例圖

6.2 視訊播放器流程圖
- 待完善
6.3 視訊播放器lib庫
6.4 視訊核心lib庫介紹
6.5視訊播放器UI庫介紹
- 比如,現在有個業務需求,需要在視訊播放器剛開始添加一個廣告視圖,等待廣告倒計時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();
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抽取封裝優化
- 發展中遇到的問題
- 播放器可支援多種場景下的播放,多個産品會用到同一個播放器,這樣就會帶來一個問題,一個播放業務播放器狀态發生變化,其他播放業務必須同步更新播放狀态,各個播放業務之間互相交叉,随着播放業務的增多,開發和維護成本會急劇增加, 導緻後續開發不可持續。
-
- 視訊播放器結構需要清晰
- 一定要解耦合,播放器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(); } }
- 網絡上比較好的項目: 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緩沖子產品
- 統一管理視訊播放器封裝庫日志,友善後期排查問題
- 比如,視訊核心,日志過濾則是:aaa
- 比如,視訊player,日志過濾則是:bbb
- 比如,緩存子產品,日志過濾則是:VideoCache
- 針對視訊封裝庫,統一處理抛出的異常,為了友善開發者快速知道異常的來由,則可以查詢約定的code碼。
- 這個在sdk中特别常見,是以該庫一定程度是借鑒騰訊播放器……