一、项目简介:
最近利用闲暇时间来重构一下之前的播放器,这次的主要升级功能如下:
- 支持动态切换内核
- 支持音/视频播放,midi文件播放
- 支持在线播放/本地播放
- 支持后台播放,音频提取播放
- 支持视频边下边播,分片下载播放存储
- 支持断点续载续播,下次直接优先从缓冲读取播放
- 支持缓存管理,清除时间段缓存
- 支持试看,自动跳过片头
- 支持记录上次播放时间
- 支持自动播放,自动连续播放
- 支持随机/重复/顺序播放
- 支持重力感应,全屏/半屏切换
- 支持基本手势操作,进度音量等
- 支持切换不同分辨率视频
- 支持直播流媒体播放
视频支持格式:mp4、m3u8、wav、avi
音频支持格式:midi、mp3、
二、项目背景:
在很早之前写个一个播放器架子,但是这个架子只是当初简单的实现播放处理,那么这段时间事情不多,所以就利用闲暇时间来升级重构一下,其实网上关于播放器的轮子也非常多ZFPlayer、KRVideoPlayer、SJVideoPlayer
这些轮子都很优秀,所以在制作的时候有借鉴参考
然后慢慢完善实现一款可以高度自定义并且支持动态切换内核的播放器壳子,支持边下边播边存,续播续传功能,基本手势播放等等功能
至于流媒体暂时网上也没发现有什么可以实现边下边播边存的方案,我其实这里有这样一个思路,可以利用搭建本地服务器来处理,先将分片数据下载到本地,然后播放这样也就只需要用户一次网络数据下载,等空闲时间我再来慢慢实现
目前已初步实现KJAVPlyaer、KJIJKPlayer、KJMIDIPlayer三种内核,
KJAVPlyaer基于AVPlayer封装使用
KJIJKPlayer基于b站IJKMediaFramework封装使用
KJMIDIPlayer基于AudioToolBox封装使用
三、实践过程:
技术选型:项目目前主要还是基于AVPlayer的灵活封装使用,然后也有对Bilibili开源IJKMediaFramework的使用处理
基于AVPlayer实现边下边播边存功能,目前很多网上资料基本都是基于唱吧KTVHTTPCache来实现,而本文则是采用NSURLSession
封装的下载器,在结合文件写入NSFileHandle
来实现,然后将信息存储在数据库
四、模块介绍
主要就是分为以下几大模块,
KJBaseFunctionPlayer播放器协议
所有播放器壳子都是基于该基础做处理,提取公共部分
API & Property | 类型 | 功能 |
delegate | Property | 委托代理 |
requestHeader | Property | 视频请求头 |
roregroundResume | Property | 返回前台继续播放 |
backgroundPause | Property | 进入后台暂停播放 |
autoPlay | Property | 是否开启自动播放 |
speed | Property | 播放速度 |
volume | Property | 播放音量 |
cacheTime | Property | 缓存达到多少秒才能播放 |
skipHeadTime | Property | 跳过片头 |
timeSpace | Property | 时间刻度 |
kVideoTotalTime | Property | 获取视频总时长 |
kVideoURLFromat | Property | 获取视频格式 |
kVideoTryLookTime | Property | 免费试看时间和试看结束回调 |
videoURL | Property | 视频地址 |
localityData | Property | 是否为本地资源 |
isPlaying | Property | 是否正在播放 |
currentTime | Property | 当前播放时间 |
ecode | Property | 播放失败 |
kVideoAdvanceAndReverse | Property | 快进或快退 |
shared | Property | 单例属性 |
kj_sharedInstance | Instance | 创建单例 |
kj_attempDealloc | Instance | 销毁单例 |
kj_play | Instance | 准备播放 |
kj_replay | Instance | 重播 |
kj_resume | Instance | 继续 |
kj_pause | Instance | 暂停 |
kj_stop | Instance | 停止 |
KJPlayerDelegate委托代理
/* 当前播放器状态 */ - (void)kj_player:(KJBasePlayer*)player state:(KJPlayerState)state; /* 播放进度 */ - (void)kj_player:(KJBasePlayer*)player currentTime:(NSTimeInterval)time; /* 缓存进度 */ - (void)kj_player:(KJBasePlayer*)player loadProgress:(CGFloat)progress; /* 播放错误 */ - (void)kj_player:(KJBasePlayer*)player playFailed:(NSError*)failed;
KJBaseUIPlayer播放器协议
播放器UI相关协议
API & Property | 类型 | 功能 |
playerView | Property | 播放器载体 |
background | Property | 背景颜色 |
placeholder | Property | 占位图 |
videoGravity | Property | 视频显示模式 |
kVideoSize | Property | 获取视频尺寸大小 |
kVideoTimeScreenshots | Property | 获取当前截屏 |
kVideoPlaceholderImage | Property | 子线程获取封面图,图片会存储在磁盘 |
kj_startAnimation | Instance | 圆圈加载动画 |
kj_stopAnimation | Instance | 停止动画 |
kj_displayHintText: | Instance | 支持富文本提示的文本框,零秒表示不自动消失 |
kj_displayHintText:time:max:position: | Instance | 支持富文本提示的文本框,零秒表示不自动消失 |
kj_hideHintText | Instance | 隐藏提示文字 |
KJBasePlayerView播放器视图基类,播放器控件父类
只要子控件没有涉及到手势交互,我均采用Layer的方式来处理,然后根据zPosition
来区分控件的上下层级关系
/* 控件位置和大小发生改变信息通知 */ extern NSString *kPlayerBaseViewChangeNotification; /* 控件位置和大小发生改变key */ extern NSString *kPlayerBaseViewChangeKey; @protocol KJPlayerBaseViewDelegate; @interface KJBasePlayerView : UIImageView /* 委托代理 */ @property (nonatomic,weak) id <KJPlayerBaseViewDelegate> delegate; /* 主色调,默认白色 */ @property (nonatomic,strong) UIColor *mainColor; /* 副色调,默认红色 */ @property (nonatomic,strong) UIColor *viceColor; /* 支持手势,支持多枚举 */ @property (nonatomic,assign) KJPlayerGestureType gestureType; /* 长按执行时间,默认1秒 */ @property (nonatomic,assign) NSTimeInterval longPressTime; /* 操作面板自动隐藏时间,默认2秒然后为零表示不隐藏 */ @property (nonatomic,assign) NSTimeInterval autoHideTime; /* 操作面板高度,默认60px */ @property (nonatomic,assign) CGFloat operationViewHeight; /* 当前操作面板状态 */ @property (nonatomic,assign,readonly) BOOL displayOperation; /* 隐藏操作面板时是否隐藏返回按钮,默认yes */ @property (nonatomic,assign) BOOL isHiddenBackButton; /* 小屏状态下是否显示返回按钮,默认yes */ @property (nonatomic,assign) BOOL smallScreenHiddenBackButton; /* 全屏状态下是否显示返回按钮,默认no */ @property (nonatomic,assign) BOOL fullScreenHiddenBackButton; /* 是否开启自动旋转,默认yes */ @property (nonatomic,assign) BOOL autoRotate; /* 是否为全屏,名字别乱改后面kvc有使用 */ @property (nonatomic,assign) BOOL isFullScreen; /* 当前屏幕状态,名字别乱改后面kvc有使用 */ @property (nonatomic,assign,readonly) KJPlayerVideoScreenState screenState; /* 当前屏幕状态发生改变 */ @property (nonatomic,copy,readwrite) void (^kVideoChangeScreenState)(KJPlayerVideoScreenState state); /* 返回回调 */ @property (nonatomic,copy,readwrite) void (^kVideoClickButtonBack)(KJBasePlayerView *view); /* 提示文字面板属性,默认最大宽度250px */ @property (nonatomic,copy,readonly) void (^kVideoHintTextInfo)(void(^)(KJPlayerHintInfo *info)); #pragma mark - 控件 /* 快进快退进度控件 */ @property (nonatomic,strong) KJPlayerFastLayer *fastLayer; /* 音量亮度控件 */ @property (nonatomic,strong) KJPlayerSystemLayer *vbLayer; /* 加载动画层 */ @property (nonatomic,strong) KJPlayerLoadingLayer *loadingLayer; /* 文本提示框 */ @property (nonatomic,strong) KJPlayerHintTextLayer *hintTextLayer; /* 顶部操作面板 */ @property (nonatomic,strong) KJPlayerOperationView *topView; /* 底部操作面板 */ @property (nonatomic,strong) KJPlayerOperationView *bottomView; /* 返回按钮 */ @property (nonatomic,strong) KJPlayerButton *backButton; /* 锁屏按钮 */ @property (nonatomic,strong) KJPlayerButton *lockButton; /* 播放按钮 */ @property (nonatomic,strong) KJPlayerButton *centerPlayButton; #pragma mark - method /* 隐藏操作面板,是否隐藏返回按钮 */ - (void)kj_hiddenOperationView; /* 显示操作面板 */ - (void)kj_displayOperationView; /* 取消收起操作面板,可用于滑动滑杆时刻不自动隐藏 */ - (void)kj_cancelHiddenOperationView;