視頻播放器框架已經(jīng)非常成熟了,但是由于項(xiàng)目需求各種各樣,第三方庫(kù)使用起來(lái)需要大量修改定制,并且還會(huì)出現(xiàn)各種問(wèn)題,因此把之前項(xiàng)目中開(kāi)發(fā)的模塊提取出來(lái)進(jìn)行完善擴(kuò)展,寫(xiě)了一套自研的播放框架,并且引入Jetpack,通過(guò)Lifecycle和LiveData,大大簡(jiǎn)化了資源監(jiān)控和UI事件交互方式。目前框架已經(jīng)穩(wěn)定應(yīng)用,所以接下來(lái)的時(shí)間計(jì)劃整理出一系列文章,記錄從零開(kāi)始設(shè)計(jì)開(kāi)發(fā)一個(gè)視頻播放框架需要哪些知識(shí)點(diǎn),開(kāi)發(fā)過(guò)程中個(gè)人的一些見(jiàn)解,以及踩過(guò)的坑和注意事項(xiàng)。
目前規(guī)劃本系列文章分12節(jié):
- LitePlayer框架介紹
- 一款播放器框架的結(jié)構(gòu)組成(編寫(xiě)...)
- 播放核心邏輯設(shè)計(jì)(待編寫(xiě))
- 播放管理者與內(nèi)核選擇設(shè)計(jì)(待編寫(xiě))
- 播放狀態(tài)監(jiān)聽(tīng)與UI事件響應(yīng)(待編寫(xiě))
- 視頻渲染容器設(shè)計(jì)(待編寫(xiě))
- 視頻比例模式原理和設(shè)計(jì)(待編寫(xiě))
- 播放控制界面設(shè)計(jì)(待編寫(xiě))
- 手勢(shì)控制設(shè)計(jì)(待編寫(xiě))
- 全屏播放設(shè)計(jì)(待編寫(xiě))
- 小窗播放設(shè)計(jì)(待編寫(xiě))
- 列表播放設(shè)計(jì)(待編寫(xiě))
LitePlayer框架簡(jiǎn)介:
- LitePlayer是一款Kotlin編寫(xiě)的,輕量簡(jiǎn)潔,接入簡(jiǎn)單的視頻播放框架。
- 播放層和頁(yè)面層之間使用LiveData 進(jìn)行事件通信,頁(yè)面銷(xiāo)毀會(huì)自動(dòng)釋放事件。
- 內(nèi)部通過(guò)Lifecycle監(jiān)聽(tīng)頁(yè)面生命周期,自動(dòng)進(jìn)行暫停,恢復(fù),釋放播放動(dòng)作。
- 列表播放使用attachView方式綁定item視圖,減少每個(gè)item視圖的復(fù)雜度,提高列表渲染性能。
- 用戶視圖層使用組件添加方式,不同的視圖層可以進(jìn)行復(fù)用和搭配組裝。
- 庫(kù)編譯產(chǎn)物大小200k左右,減少依賴引入成本。
LitePlayer基本使用,代碼非常簡(jiǎn)潔:
// 基礎(chǔ)播放場(chǎng)景,和原生VideoView使用方式基本一致:
val litePlayerView = findViewById(R.id.lite_player_view)
litePlayerView.setPlayerType(PlayerType.TYPE_EXO_PLAYER)
litePlayerView.setRenderType(RenderType.TYPE_SURFACE_VIEW)
litePlayerView.setDataSource(DataSource(url))
litePlayerView.start()
// 一些定制化設(shè)置:
litePlayerView.attachMediaController(LiteMediaController(context))// 添加一個(gè)播放控制器
litePlayerView.attachGestureController(LiteGestureController(this).apply {// 添加一個(gè)手勢(shì)控制器
supportSeek = true// 支持手勢(shì)seek操作
supportBrightness = true// 支持手勢(shì)設(shè)置屏幕亮度
supportVolume = true// 支持手勢(shì)設(shè)置音量大小
})
litePlayerView.attachFloatWindow(LiteFloatWindow(context))// 添加一個(gè)懸浮窗控制器
litePlayerView.setRepeatMode(true)// 設(shè)置循環(huán)播放
litePlayerView.setVolume(5)// 設(shè)置音量
litePlayerView.setPlaySpeed(1.5f)// 設(shè)置播放倍速
litePlayerView.setFullScreenMode(true)// 全屏播放
litePlayerView.setFloatWindowMode(true)// 懸浮小窗播放
litePlayerView.setAspectRatio(AspectRatio.W_21_9)// 設(shè)置畫(huà)面比例
// 列表播放場(chǎng)景(基于RecyclerView):
val listPlayer = ListPlayer(LitePlayerView(context))
val videoScrollListener = object : ListPlayer.VideoListScrollListener {
override fun getVideoContainer(position: Int): ViewGroup? {
// 僅需返回position對(duì)應(yīng)ItemView中的視頻容器
val holder = recyclerView.findViewHolderForAdapterPosition(position)
return if (holder != null && holder is VideoHolder) {
holder.videoContainer // 一個(gè)空的FrameLayout作為attach目標(biāo)
} else {
null
}
}
override fun getVideoDataSource(position: Int): DataSource? {
// 返回position對(duì)應(yīng)的媒體數(shù)據(jù)
val data = adapter.getData(position)
return if (data is Video) {
DataSource(VideoCacheHelper.url(data.videoUrl))
} else {
null
}
}
}
listPlayer.attachToRecyclerView(recyclerView, true, videoScrollListener)
LitePlayer結(jié)構(gòu)概述:
- 基于面向接口設(shè)計(jì),大部分核心模塊都提供頂層接口供用戶自定義實(shí)現(xiàn),框架核心接口和實(shí)現(xiàn)類(lèi):
// 數(shù)據(jù)層:用戶可自定義數(shù)據(jù)結(jié)構(gòu)
IDataSource
|----DataSource
// 播放層:用戶可自定義播放IPlayer內(nèi)核
IPlayerCore
|----IPlayer
| |----LitePlayerCore // 播放管理類(lèi)
| |----ExoPlayerImpl // exoplayer實(shí)現(xiàn)
| |----IjkPlayerImpl // ijkplayer實(shí)現(xiàn)
| |----MediaPlayerImpl // mediaplayer實(shí)現(xiàn)
|
|----IPlayerView
|----LitePlayerView // 唯一播放器控件
|----ListPlayer // RecyclerView列表播放輔助類(lèi)
|----ListPlayer2 // ListView列表播放輔助類(lèi)
// 渲染層:提供SurfaceView和TextureView渲染方式
IRender
|----RenderSurfaceView // surfaceview渲染容器
|----RenderTextureView // textureview渲染容器
// 用戶圖層:用戶可自定義和組裝播放器UI界面
IOverlay
|----IController
| |----LiteMediaController // 媒體播放控制面板
|----ITopbar
| |----LiteMediaTopbar //媒體信息展示面板
|----IGesture
|----LiteGestureController // 媒體播放手勢(shì)控制面板
// 懸浮窗:用戶可自定義懸浮窗UI界面
IFloatWindow
|----LiteFloatWindow // 懸浮窗播放輔助類(lèi)
- 下面是一些demo示例:
![]() |
![]() |
![]() |
![]() |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |







