文章来自:http://blog.youkuaiyun.com/intbird 转载请说明出处
五一第一天在家休息(后续休息有空会进行升级)
看了一下视频播放的相关东西
写了一个简单的触摸视频播放器
(使用 MediaPlayer 和 ExoPlayer )
我喜欢从自己的使用感受做些调整
所以在里面有一个 触摸平滑进度 的实现
还有就是代码面向抽象,方便后续一些功能替换
有空的话我就会继续写写它
Github源码地址: https://github.com/intbird/VideoPlayerLib
GitHub issues(持续维护,待开发):
https://github.com/intbird/VideoPlayerLib/issues/2
基础功能:
播放不同的 分辨率/字幕/倍速/初始进度 等
在屏幕中间双击: 切换播放/暂停
在屏幕中间滑动: 拖动进度
在屏幕左侧滑动: 控制亮度
在屏幕右侧滑动: 控制声音
点击锁定按钮: 锁定当前所有操作
点击上一个/下一个/播放/暂定/停止: 执行对应动作
横竖屏方向自动切换
有时间的话会继续开发......
完成效果:

- 部分截图:




Github源码地址: https://github.com/intbird/VideoPlayerLib
文章来自:http://blog.youkuaiyun.com/intbird 转载请说明出处
结构解析:
0.权限检查: 读取媒体权限
1.播放器层: 播放器的接口 + 实现
2.触控层: 触摸区域识别 + 手势识别 + 触摸灵敏度和进度反馈
3.控制面板层: 可视UI按钮(上一个,下一个,播放/暂停/停止)
4.锁定层: 锁(锁播放器+ 锁触控 + 锁面板+ 锁屏幕方向等)
代码结构:
用mvc简单实现一下,有空了可以把view这层在做层封装,方便后续更换UI的最小代价
1.项目结构
1.api: 使用Fragment(推荐此方式)
VideoPlayerFragment.newInstance(array, index, style, autoPlay)

2.api: 使用Activity(模块解耦实现)
ServicesLoader.load(IVideoPlayer::class.java)?.startActivity(this,array, index, autoPlay)
显示声明外部api和实现默认的api


3.总体结构
逐步升级, 代码结构有些许调整

4.资源前缀

5.播放实现

- MediaPlayerImpl
intbird.soft.lib.video.player.main.player.player.MediaPlayerImpl
- ExoPlayerImpl(有空会继续实现)
intbird.soft.lib.video.player.main.player.player.ExoPlayerImpl
6.自动旋屏
自动旋转视频和抖动恢复屏幕方向 : https://blog.youkuaiyun.com/intbird/article/details/109077762
2. 大体思路
1. 不同播放器不同布局, 统一接口多个回调
1.面向接口, 抽象代码
private var playerCall: PlayerCallbacks? = null
private var playerView: MediaViewInfo<out View, out View>? = null
private var player: IPlayer? = null
private fun instanceMediaPlayer(mediaPlayerType: MediaPlayerType?) {
when(mediaPlayerType) {
MediaPlayerType.PLAYER_STYLE_1, MediaPlayerType.PLAYER_STYLE_2 -> {
playerCall = PlayerCallbacks(playerCallback, videoPlayerCallback)
playerView = MediaViewProvider(view).by(mediaPlayerType)
player = MediaPlayerImpl(getInternalActivity(), playerView?.display as? TextureView, subtitleText, intentHelper, playerCall)
}
MediaPlayerType.PLAYER_STYLE_3 -> {
playerCall = PlayerCallbacks(playerCallback, videoPlayerCallback)
playerView = MediaViewProvider(view).by(mediaPlayerType)
player = ExoPlayerImpl(getInternalActivity(), playerView?.display as? TextureView, playerCall)
}
}
}
2.面向复杂, 抽象配置
通过一个UI的配置项,强制让不同类型的播放自己选择如何和界面关联
enum class MediaPlayerType(
open val layoutDisplay: Int,
open val viewDisplay: Int,
open val layoutControl: Int,
open val viewControl: Int
) {
PLAYER_STYLE_1(
R.layout.lib_media_player_diaplay_texture,
R.id.textureView,
R.layout.lib_media_player_control_style_1,
R.id.mediaRootControl
),
PLAYER_STYLE_2(
R.layout.lib_media_player_diaplay_texture,
R.id.textureView,
R.layout.lib_media_player_control_style_2,
R.id.mediaRootControl
),
PLAYER_STYLE_3(
R.layout.lib_media_player_diaplay_ijkplayer
R.id.ijkplayer,
R.layout.lib_media_player_control_style_2,
R.id.mediaRootControl
)
}
2. 动态修改播放参数,回传到播放器/界面等外部
1. IntentHelper
IntentHelper: 获取外部传入的Intent列表 的 某个Index
进而进行组装当前播放的数据
但:我想如果一个player实现类,他的数据不是外部传入的
那么:他也可以替换掉这个IntentHelper,在少量修改后要
能将 切换播放/上一首/下一首 等改为自己的内部方法
始终根据index获取数据

2. 实现代理方法

3. 参数更新
MediaItemInfoRecord: 通过它来保存播放状态,
以便在切换分辨率,字幕等需要强行进行状态改变后
继续操作前的进度进行播放
onReceivePlayFile: 这个在收到播放参数变更时会通知到播放器/控制层等等

4. 处理更新
override fun onReceivePlayFile(reload: Boolean, mediaFileInfo: MediaFileInfo?) {
if (null == mediaFileInfo) return
if (reload) {
player?.prepare(mediaFileInfo)
} else {
player?.onParamsChange(mediaFileInfo)
}
videoControlController?.onParamsChange(mediaFileInfo)
}
3.将显示拆分为 视频显示 和 字幕显示等
1. 视频显示
MediaPlayer用surface作为显示器
但: 如果用第三方播放器,显示可能为其他控件,比如一个webview播放器
所以: 则要预留出接口, 方便替换

该博客介绍了如何使用Android的MediaPlayer和ExoPlayer实现一个支持手势滑动控制播放进度、亮度、音量,并可调节分辨率、字幕和倍速的视频播放器。通过面向接口编程和代理方法动态修改播放参数,实现了界面与播放器的解耦。同时,还提供了自动旋屏功能和自定义UI组件。
最低0.47元/天 解锁文章
798

被折叠的 条评论
为什么被折叠?



