标签:
1 .使用环境:
在实际开发过程中 有需要展示流媒体的模块 ,需求非常简单 :播放 和 暂停 ,其实这个时候有很多选择 ,可以选择 MPMoviePlayerController(MediaPlayer.framework), AVAudioPlayer(AVFunction.framework)
但是考虑到扩展性,高度自定义性 我选择使用 AVPlayer. 事实是对的 后来需求又增加了, 还需要展示播放进度,缓冲进度,变化时间,视频时长等,还有对UI有要求,甚至不为过的说 要苹果手机那个AVPlayer app的播放效果.
其实 我是拒绝的 基因里带的反抗心理 但是还得去做啊 一天天的 就被产品虐待
2.关键核心代码
2.1 三个监听
2.1.1监听视频状态 key : “status” 是不是一个可播放状态 还是正在缓冲 还是加载失败等错误
2.1.2监听视频播放完成 :endTime这个时候 根据需求 做触发响应 要重播 那就做重播处理的方法 或者需要弹框 或者其他什么的方法
2.1.3监听视频播放过程: timeObserver 用来实时更新播放状态,播放进度 缓冲进度等
重点:
视频从播放开始 timeObserver 创建 停止播放 一定要有 timeObserver 的移除 防止空监听
同理 “status”,endTime 在切换视频 或者 disappear 视频控制器页面 时候 都要取消监听
保证”observer first :创建或重新创建 需要先release旧的对象 再add 并且结束使用 移除对应监听 防止空监听”
判断是否取消 “status”,endTime条件,我是判断 当前player 和 AVPlayerItem是否存在 存在则 取消. 但是 有时候 一些视频流本身的意外错误 ,用枚举也没拦住的话 很有可能意外 中的意外执行 ,也许会取消一个空监听,这个时候 我特意给取消监听加上了 try catch 目的很简单 防止崩溃啊,并且它和上下文关联的程度并不大,不会出现一个小错误滚啊滚滚成大错误的意外发生.
2.2 几个重要类
AVAsset:主要用于获取多媒体信息,是一个抽象类,不能直接使用。
AVURLAsset:AVAsset的子类,可以根据一个URL路径创建一个包含媒体信息的AVURLAsset对象。
AVPlayerItem:一个媒体资源管理对象,管理者视频的一些基本信息和状态,一个AVPlayerItem对应着一个视频资源。
(1)- (void)loadValuesAsynchronouslyForKeys:(NSArray<NSString *> *)keys completionHandler:(nullable void (^)(void))handler NS_AVAILABLE(10_7, 4_2); 该方法使用 获取 到 AVKeyValueStatus keyStatus 状态 typedef NS_ENUM(NSInteger, AVKeyValueStatus) { AVKeyValueStatusUnknown, AVKeyValueStatusLoading, AVKeyValueStatusLoaded, AVKeyValueStatusFailed, AVKeyValueStatusCancelled }; 拦截错误failed 做提示 就不用再往下做多余执行了 如果 asset.playable 是真 则可以添加 status (先移除 上一次的响应监听 如果存在的话) (2)监听status -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context; typedef NS_ENUM(NSInteger, AVPlayerStatus) { AVPlayerStatusUnknown, AVPlayerStatusReadyToPlay, AVPlayerStatusFailed }; if([playerItem status] == AVPlayerStatusReadyToPlay) 是可以播放的状态,其他情况 按需求做提示 或者其他一些必要处理 (3)AVPlayerStatusReadyToPlay 可播放状态 如果 执行播放了 要添加timeObserver (先移除timeObserver 有必要的话), 然后处理UI 需要展示的相关视频信息 (4) 展示播放进度 用 UISlider 展示缓冲进度用UIProgressive. 然后 先 add slider 再add progressive 这里 特别要讲的是 如果 没有对视频触摸有特别要求 可以把他们都放在一个toolbarView上 方便集中处理 但是如果有特殊需求的话,还是建议 把他们直接add在视频存在的那个自定义View上. 我的处理 是add 在 视频的 那个View上 因为 还有一个 快进快退的功能 UISlider 高度 要通过 继承UISlider 的slider重写 (CGRect)trackRectForBounds:(CGRect)bounds 来设置 不然就是默认高度 (UIPorgressive 也是) 并且slider 原生的UI是圆角 现在要求是扁平化方角,处理办法 是用图片代替 设置进度颜色 就可以了 其次 是 拖动进度条的圆点 焦点区域过小不敏感,这个也是通过重写方法来扩大焦点区域的 //自定义 UISlider - Increase “hot spot(焦点区域)” size - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event { CGRect bounds = self.bounds; bounds = CGRectInset(bounds, -10, -15);//左右扩宽 10 像素 上下扩宽 15像素 return CGRectContainsPoint(bounds, point); } (4)快进与快退 关键有二 (1)触发时间点 ,我这里给sldier 添加了 两个方法 一个 touchDown 作为拖拽开始的响应方法 一个 touchUpinside 作为拖拽结束的响应 debug测过了 逻辑基本满足需求.如果 你想一直监听拖拽过程什么 也是可以的 这两个方法 保证了快进快退后 再恢复正常播放的业务逻辑,非常关键,此处你要考虑 timeObserver状态 展示进度时间的变化 拖拽slider的value变化 (2)在 touchUpinside 时候 要处理 视频的seekToTime问题 这个我的”CMTimeMake 和 CMTimeMakeWithSeconds”特地区分了 这两个创建一个CMTime的关键. 在拖拽结束后 seekToTime方法: -(void)seekToTime:(CMTime)time toleranceBefore:(CMTime)toleranceBefore toleranceAfter:(CMTime)toleranceAfter completionHandler:(void (^)(BOOL finished))completionHandler NS_AVAILABLE(10_7, 5_0); 还有其他的seekToTime方法 但是在我的工程项目里 这个 是精准度最高的 不论视频的长短,拖拽都不会出现拖动按钮跳动(实际的问题就是精准度或者时间误差很大造成的)的问题 我处理这个精准度的问题花了好久,网上资源 丰富 不代表没有错误啊,我才发现我在slack flow上还没有评论他人的功能,资历尚浅,只得在下边添加了我对问题的评论. 所以我对 一个 seekToTime的问题是这么回答的 (其实我楼上的楼上 写错了 但是仍然获得了五个赞)
至此 顺利结束开发任务 好开心
后记:
其实流媒体的水很深, 比如相关的问题 还有 录视频 直播视频什么的 涉及HTTP Live Streaming(HLS)技术 慢慢学吧 路很长. 其实 我特别讨厌一些面试官问你 什么会不会的时候 当你说 不会 然后 他像抓到你小把柄似的 嘲笑你.我觉得 这样的人道行一定不会很深,很深的人往往不会这么筛选技术伙伴.也许他比你强,但也只是暂时的问题了.我觉得,有可持续的学习能力很重要,并且能在有效的时间解决问题.这个才是重点:不会,但是在规定时间内,我可以通过各种途径把目标技能 get了.这也就好了啊.我也没听过哪个大牛 上来大而全 什么都会啊.
但是面试的时候 作为我们应聘者 还是吃亏的 因为要谈钱啊 所以我们得有自我学习的驱动力不断增加自己的砝码.
致敬所有 在奋斗的IT同行们, 今天 我看到一篇新闻说 一个IT 带病工作 然后肺部感染 都好多个洞洞了 .突然有点心疼 . 大家都 要好好爱自己 ,健康最重要. 哈哈
不错的一篇概要,至少能让你基本了解几种播放操作流媒体的使用场景
http://www.cnblogs.com/kenshincui/p/4186022.html
HLS
http://www.cnblogs.com/haibindev/archive/2013/01/30/2880764.html
标签:
原文地址:http://www.cnblogs.com/someonelikeyou/p/5453137.html