使用AVPlayer遇到的那些坑
使用AVPlayer遇到的那些坑
最近做了一个短视频相关的功,主要是列表页,页面里面都是mp4的视频,需求是同一时间内,只能有一个视频在播放,视频播放器内部的功能也很简单,包含展示播放时间和总时长、全屏功能、进度条拖拽、播放、暂停功能。想要自定义播放器,那肯定就是要用到AVPlayer了,简单的用法有太多教程可以看,这里就不再赘述,主要是来说说都遇到了哪些坑。
调用了[self.player play]时,就能保证视频正常播放么?
首先当status
变为了AVPlayerStatusReadyToPlay
后,我们就可以调用[self.player play]
方法来播放视频了。但并不是调用了play
方法之后就真的在播放了。在性能差的机器上表现的尤为明显,开始的时候会显示黑屏。原因是AVPlayer在进行播放的时候,会预先解码一些内容,但在这个时候系统就已经告诉我们可以播放了,其实并不是真正的在播放,可能黑屏之后一两秒之后,就会自动播放了。
如何精准的跳转到某一时刻?
在应用进入后台的时候,我们需要记录当前的播放进度,并且停止播放视频,等到用户回到我们的app之后,继续播放。这里就会遇到一个问题,在这种情况下,根据视频的总时长的不同,会有不同情况的不一致,差值在-5~5秒之间。也就是在回到应用继续播放时,不一定是在压入后台时候的那个时间点。同样在进度条拖拽到最右侧的时候,也会倒退回去几秒钟,如何处理呢?
其实主要的方法是使用系统API的问题,系统提供了定位到某一时刻的API如下:
[self.player seekToTime:self.lastPlayTime toleranceBefore: toleranceAfter: completionHandler:];
如果需要精准定位,那么把toleranceBefore:
和toleranceAfter:
的参数都设置为kCMTimeZero
即可。
所以在进入后台返回的时候就可以通过一下代码进行处理
@try{DEF_WEAKSELF;[self.playerseekToTime:self.lastPlayTimetoleranceBefore:kCMTimeZerotoleranceAfter:kCMTimeZerocompletionHandler:^(BOOL finished) {if (finished)[weakSelf.playerplay];}];}@catch (NSException * exception) {[self.playerplay];}
因为压入后台的时候已经暂停了,所以在seekToTime:
完成之后,调用play
方法。增加try
、catch
是为了当seekToTime:
出现异常时也不至于崩溃,可以让播放器继续播放。
判断当前的播放器的状态是播放、暂停、还是缓冲中?
我想你一定看过,通过rate
来判断视频是否在播放。rate
是表示视频播放的速度,当rate
为1.0时,也就是正常的播放速度,如果rate
是1.25、1.5、2.0时,播放就是分别的倍数,也就是像B站类似的效果。当暂停的时候rate
为0,但是并不代表rate为1是就是在播放。在iOS10的SDK
中提供了新的方法来判断是否处于播放状态,一个枚举类型的变量timeControlStatus
。
typedef NS_ENUM(NSInteger, AVPlayerTimeControlStatus) {AVPlayerTimeControlStatusPaused,AVPlayerTimeControlStatusWaitingToPlayAtSpecifiedRate,AVPlayerTimeControlStatusPlaying
} NS_ENUM_AVAILABLE(10_12, 10_0);
看到这个就知道了暂停,等待还是播放状态。
有时候我们如果想要在视频一播放的时候去做一些事情,例如设置一下播放器的背景色,如果我们仅仅是监听这个rate可能无法100%保证有效,而如果我们真的要监听这种情况的话,有一个取巧的方法
self.playTimeObserver = [self.playeraddPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {if ([[[UIDevicecurrentDevice] systemVersion] floatValue] >= 9.9){if (weakSelf.player.timeControlStatus == AVPlayerTimeControlStatusPlaying)// do something}else{if (weakSelf.player.rate == 1)// do something}
}];
这样通过增加监听来判断,并且判断了当前的状态是否是播放状态。
监听了isPlaybackBufferEmpty并且值为0,那么播放器就不会播放了么?
答案是否定的,在网络状态不太好的情况下,如果视频正在加载中,并且自动缓冲,此时不调用pause方法,播放器就可能在一段时间内收到多次isPlaybackBufferEmpty
改变的消息,并且有的时候为1,有的时候为0,这个时候进度条就会开始鬼畜。那如果要解决这个问题呢?
//isPlaybackBufferEmpty这个属性不准,所以检查缓冲的时间__blockBOOL isBufferEmpty = YES;NSArray * timeRangeArray = self.playerItem.loadedTimeRanges;CMTime currentTime = self.playerItem.currentTime;[timeRangeArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {CMTimeRange aTimeRange = [[timeRangeArray objectAtIndex:0] CMTimeRangeValue];if(CMTimeRangeContainsTime(aTimeRange, currentTime) && CMTimeGetSeconds(aTimeRange.duration) > 0.1)*stop = YES, isBufferEmpty = NO;}];
像上面写的,可以通过判断当前的播放时间是否在缓冲的区域之内来判断,如果不在,那肯定说明,还没有缓冲到。
其它App播放声音打断问题
如果用户当时在后台听音乐,如QQ音乐,或者喜马拉雅这些App,这个时候播放视频后,其会被我们打断,当我们不再播放视频的时候,自然需要继续这些后台声音的播放。
首先,我们需要先向设备注册激活声音打断AudioSessionSetActive(YES);
,当然我们也可以通过[AVAudioSession sharedInstance].otherAudioPlaying;
这个方法来判断还有没有其它业务的声音在播放。
当我们播放完视频后,需要恢复其它业务或App的声音,这时我们可以调用如下方法:
OSStatus ret = AudioSessionSetActiveWithFlags(NO, kAudioSessionSetActiveFlag_NotifyOthersOnDeactivation);
App不支持横屏,如何让播放器支持全屏模式?
这个问题其实很头疼,但是也不是没有解决方法。首先全屏的时候,播放器肯定会从列表中移除,并且加载到当前window上的某一个view中来展示。这样我们就可以旋转这个view,达到横屏的效果。
//播放器所在控制器不支持旋转,采用旋转view的方式实现if (direction == UIInterfaceOrientationLandscapeLeft){[UIViewanimateWithDuration:0.25animations:^{self.transform = CGAffineTransformMakeRotation(M_PI / 2);}];[[UIApplicationsharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRightanimated:NO];}elseif (direction == UIInterfaceOrientationLandscapeRight){[UIViewanimateWithDuration:0.25animations:^{self.transform = CGAffineTransformMakeRotation(-M_PI / 2);}];[[UIApplicationsharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeftanimated:NO];}self.frame = CGRectMake(0, 0, kAppHeight, kAPPWidth);
当要恢复时,把播放器view移除,并且加入到之前的那个cell中,再旋转回来,并且设置frame。
//还原
[UIViewanimateWithDuration:0.25animations:^{self.transform = CGAffineTransformMakeRotation(0);
}];
self.frame = _originFrame;
//还原到原有父类上
[_fatherViewaddSubview:self];
这里还有一个需要注意的问题,如果要在这个时候弹框,也就是UIAlertController
。会发现alert还是竖屏的,这个时候就需要把UIAlertController的view同样旋转。以为这样就完事了么?不,在点击按钮的时候,会发现UIAlertController会旋转回竖屏之后才消失。这个时候需要swizzle一下UIAlertController的viewWillDisappear函数,在函数中先将UIAlertController的view隐藏。
播放完毕之后,如何释放AVPlayer?
释放AVPlayer之前需要remote监听的NSNotification
和KVO
,并且切换player
的currentItem
到nil
,之后将playerLayer
和playerItem
置为空。
[_playerreplaceCurrentItemWithPlayerItem:nil];
[_playerItemremoveObserver:selfforKeyPath:status];
[_playerItemremoveObserver:selfforKeyPath:loadedTimeRanges];
[_playerItemremoveObserver:selfforKeyPath:playbackBufferEmpty];
[_playerItemremoveObserver:selfforKeyPath:playbackLikelyToKeepUp];
[_playerremoveTimeObserver:self.playTimeObserver];
[[NSNotificationCenterdefaultCenter] removeObserver:self];
self.playTimeObserver = nil;
_playerLayer = nil;
_playerItem = nil;
以上就是目前遇到的并且解决的问题,系统挖的坑很多,所以我们必须要自己填坑才能让播放器做的很完美。很多时候没必要把思路局限在某些demo中,很多东西还是需要自己尝试之后,才能得到自己最想要的答案。所以不要怕麻烦,你会学到很多东西。这篇文章也给那些准备做视频播放的同学们,少踩一些坑。
使用AVPlayer遇到的那些坑相关推荐
- 细数AVPlayer的那些坑
http://ivanyuan.farbox.com/post/shi-pin-bo-fang-de-na-xie-keng 最近一直在做视频动态挂件以及一个视频播放的功能,在开始做之前,先学习了苹果 ...
- AVPlayer那些坑
AVPlayer是iOS上常用的视频播放器组件,支持常见的音视频格式.对于一般应用而言,使用AVPlayer和一套自定义UI基本可以满足需求.目前手Q.微信(公众号).腾讯视频.新浪微博等app都在广 ...
- [iOS]调和 pop 手势导致 AVPlayer 播放卡顿
作者 NewPan 关注 2017.07.15 14:24* 字数 3110 阅读 749评论 8喜欢 17 声明:我为这个框架写了四篇文章: 第一篇:[iOS]UINavigationControl ...
- iOS播放器 - AVPlayer
之前有说到在播放器中一点点小技巧,现在正式记录一下AVPlayer. 这里主要是说明用AVPlayer做音乐播放器的功能实现,所以不介绍AVPlayer中那个图层类. 首先我们要声明一下播放器,这里有 ...
- iOS音视频播放-AVPlayer简单使用
按公司需求需要对音频文件进行后台播放,借此机会对音频播放做了个总结.主要针对 AVPlayer 进行详细说明. iOS 各播放器比较 名称 使用环境 优点 确点 System Sound Servic ...
- 这算通过审核了么?接下来还有没有什么坑,求大神指点!--酷课堂iOS交流群问答精华整理(201808期)
酷课堂iOS交流群 我们是一个什么样的组织: 酷课堂iOS交流群,聚集了一群热爱技术.有趣.有料,平均Q龄在10年以上的"老司机",他们遍布在全国/球各地,有知名企业iOS工程师. ...
- AVplayer断网播放出错时player的duration、playableDuration、totalTime
使用系统的AVplayer做点播播放器,断网播放出错后player的duration和playableDuration获取不到,写了get方法获取不到时返回0,然后就掉坑里了. 获取播放时长的get方 ...
- android ios av tv,iOS AVPlayer 实现后台连续播放视频
最近接到一个需求,需要做一个在后台播放视频的功能.折腾了一下,最后总算完成了.因此写一篇文章,介绍下具体的实现步骤,也说说自己遇到的坑,算是总结和记录. 前言 当 App 退到后台时,会进入 susp ...
- AVPlayer详解系列(一)参数设置
思维导图 先来一张思维导图,作为这篇文章的目录索引: AVPlayer.png 为什么使用AVPlayer: 首先在iOS平台使用播放视频,可用的选项一般有这四个,他们各自的作用和功能如下: 使用 ...
最新文章
- 网页如何与mysql服务器建立连接不上,html与mysql建立连接数据库
- 深度学习多框架多平台推理引擎工具
- 自动化部署之jenkins
- 小学计算机课知识点总结,小学计算机教学总结3篇
- 腾讯云发布专有云TCE矩阵,让企业用上金融级合规专有云
- css degrees_带有Python示例的math.degrees()方法
- 蚌埠学院计算机科学技术校区,蚌埠学院计算机科学与关键技术(6页)-原创力文档...
- 中国电信叫停不限量套餐 套外资费3元/GB
- Shiro报异常org.apache.shiro.authz.AuthorizationException: Not authorized to invoke method:
- IDEA中解决Edit Configurations中没有tomcat Server选项的问题(附配置Tomcat)
- python清空list_python怎么清空list
- Linux6新建分区,centos6中添加一块新的硬盘并分区的方法介绍
- 阿里云Web播放器使用
- java 牙位图插件_牙医的骄傲-智能牙位图中文医疗应用app全球排名No.1
- STM8停产,新唐的N76E003 pin对pin替换STM8S003F3P6
- 清除html中table标签显示的数据,jquery – 数据清除tbody
- java类的使用方法小结_JavaPoet的使用指南小结
- 我们手指触碰屏幕都做了什么?
- 【A Unified Model for Multi-class Anomaly Detection, NeurIPS 2022】
- python读取excel汉字转成拼音_python 批量将中文名转换为拼音
热门文章
- Android Framework 电源子系统(04)核心方法updatePowerStateLocked分析-2 循环处理 更新显示设备状态
- 浪潮服务器开机没有信号输出,PLC输出指示灯已经点亮但是输出没有信号-工业支持中心-西门子中国...
- 使用Excel打造一款个人日志系统
- Xcode自带的超好用的诊断工具
- macOS分发app打包+签名+公证+添加票据+生成dmg文件
- ccd坏点测试软件,如何测试CCD坏点(ZT)
- STM32F407VET6 / BLACK_F407VE开发板间隔0.5秒不断重启
- android 键盘 定义,自定义全键盘-[Android_YangKe]
- XiaomiRouter自学之路(13-U-boot支持web更新firmware功能)
- 兄弟Brother MFC-T800W 驱动