# 前言
之前学习了 Swift 一直想做一个项目,这次下定决心花了近1个月的空闲时间基于 AVPlayer 封装了一个视频播放器。
# 源代码
- GitHub地址:VGPlayer
- 有什么意见建议可以提 issues,在博文下留言,如果觉得不错,欢迎点star。
# 更新列表
- 2017-6-13 v0.0.1
- 2017-6-17 v0.0.2 支持外挂字幕 格式 srt & ass 两种都支持
- 2017-7-1 边播边缓存 v0.1.0
- 2017-7-11 修复所有编译⚠️. v0.1.2
- 2017-7-16 修复缓存视频时URL解析错误导致的crash. v0.1.3
- 2017-8-10 修复退出全屏后的播放视图frame error问题,修复iOS9播放卡住问题,增加example 嵌入在cell中的播放模式. v0.1.4
- 2017-9-6 v0.1.5 修复URL 解析问题 修复暂停播放问题
- 2017-9-21 v0.2.0 整理代码、转换成Swift 4
# 演示
# 功能
- 集成了视频播放器常有的手势,包括单击显示控制视图,双击暂停,水平滑动快进、后退,竖直滑动亮度和音量调节。
- 全屏播放,自适应手机屏幕旋转方向。
- 自定义控制视图
# 实现思路
VGPlayer
VGPlayer是一个对AVPlayer封装提供播放功能,displayView为播放器画面绘制。
主要是使用了以下几个类:
- AVURLAsset是 AVAsset的子类,用来本地或者网络视频地址的初始化网络请求,也可以用来获取视频每一帧的画面来实现滑动提前预览图的功能(后续应该会版本迭代加上此功能)
- AVPlayerItem 是对AVPlayer播放的视频数据管理,对播放的Asset资源进行记录,提供或者视频的时间,播放状态等。
- AVPlayer 调控数据和视图
- AVPlayerLayer 进行视频视图绘制
VGPlayer封装AVPlayer提供给调用者可选代理方法
// player delegate
// play state
func vgPlayer(_ player: VGPlayer, stateDidChange state: VGPlayerState)
// playe Duration
func vgPlayer(_ player: VGPlayer, playerDurationDidChange currentDuration: TimeInterval, totalDuration: TimeInterval)
// buffer state
func vgPlayer(_ player: VGPlayer, bufferStateDidChange state: VGPlayerBufferstate)
// buffered Duration
func vgPlayer(_ player: VGPlayer, bufferedDidChange bufferedDuration: TimeInterval, totalDuration: TimeInterval)
// play error
func vgPlayer(_ player: VGPlayer, playerFailed error: VGPlayerError)
VGPlayerView
- VGPlayerView负责画面的展示,,只作为展示,而绘制层则是AVPlayerLayer提供,可继承此类进行控制视图的自定义
- VGPlayerView封装AVPlayerLayer提供可选代理方法
// player view delegate
/// fullscreen
func vgPlayerView(_ playerView: VGPlayerView, willFullscreen fullscreen: Bool)
/// close play view
func vgPlayerView(didTappedClose playerView: VGPlayerView)
/// displaye control
func vgPlayerView(didDisplayControl playerView: VGPlayerView)
VGPlayerError
- VGPlayerError一个 struct 用来播放出现Error时返回
# 细节调整
- 后台播放的实现
设置工程
// AppDelegate settings
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
do
{
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
}
catch let error as NSError
{
print(error)
}
return true
}
设置VGPlayer的Background mode
self.player.backgroundMode = .proceed
- VGPlayerUtils 提供判断视频类型方法和一些通用的方法
- UIButton+VGPlayer 扩展按钮点击范围
- Timer+VGPlayer 解决Timer的 retain cycle问题
边播边缓存 (参考: VIMediaCache)
使用AVAssetResourceLoader 来控制视频缓存
使用Range请求数据,可取消下载,分段缓存
-
在 Simulator debugging, 可以看到缓存的文件
使用:
// Settings maxCacheSize
VGPlayerCacheManager.shared.cacheConfig.maxCacheSize = 160000000
// Setting maxCacheAge default one weak
VGPlayerCacheManager.shared.cacheConfig.maxCacheAge = 60 * 60 * 24 * 7
// clean all cache
VGPlayerCacheManager.shared.cleanAllCache()
// clean old disk cache.
// This is an async operation.
VGPlayerCacheManager.shared.cleanOldFiles { }
# 参考
- https://techblog.toutiao.com/2017/03/28/fullscreen/
- https://developer.apple.com/library/content/qa/qa1668/_index.html
- https://developer.apple.com/documentation/avfoundation
- https://stackoverflow.com/questions/808503/uibutton-making-the-hit-area-larger-than-the-default-hit-area/13977921
- https://gist.github.com/onevcat/2d1ceff1c657591eebde
- Media Cache VIMediaCache
- https://mp.weixin.qq.com/s/v1sw_Sb8oKeZ8sWyjBUXGA
# 总结
- 了解了AVPlayer的整体结构,对播放过程完整的思路和一些遇到的问题。
- 踩了屏幕旋转细节、按钮点击范围调整的一些交互细节的坑