使用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方法。增加trycatch是为了当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监听的NSNotificationKVO,并且切换playercurrentItemnil,之后将playerLayerplayerItem置为空。

[_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遇到的那些坑相关推荐

  1. 细数AVPlayer的那些坑

    http://ivanyuan.farbox.com/post/shi-pin-bo-fang-de-na-xie-keng 最近一直在做视频动态挂件以及一个视频播放的功能,在开始做之前,先学习了苹果 ...

  2. AVPlayer那些坑

    AVPlayer是iOS上常用的视频播放器组件,支持常见的音视频格式.对于一般应用而言,使用AVPlayer和一套自定义UI基本可以满足需求.目前手Q.微信(公众号).腾讯视频.新浪微博等app都在广 ...

  3. [iOS]调和 pop 手势导致 AVPlayer 播放卡顿

    作者 NewPan 关注 2017.07.15 14:24* 字数 3110 阅读 749评论 8喜欢 17 声明:我为这个框架写了四篇文章: 第一篇:[iOS]UINavigationControl ...

  4. iOS播放器 - AVPlayer

    之前有说到在播放器中一点点小技巧,现在正式记录一下AVPlayer. 这里主要是说明用AVPlayer做音乐播放器的功能实现,所以不介绍AVPlayer中那个图层类. 首先我们要声明一下播放器,这里有 ...

  5. iOS音视频播放-AVPlayer简单使用

    按公司需求需要对音频文件进行后台播放,借此机会对音频播放做了个总结.主要针对 AVPlayer 进行详细说明. iOS 各播放器比较 名称 使用环境 优点 确点 System Sound Servic ...

  6. 这算通过审核了么?接下来还有没有什么坑,求大神指点!--酷课堂iOS交流群问答精华整理(201808期)

    酷课堂iOS交流群 我们是一个什么样的组织: 酷课堂iOS交流群,聚集了一群热爱技术.有趣.有料,平均Q龄在10年以上的"老司机",他们遍布在全国/球各地,有知名企业iOS工程师. ...

  7. AVplayer断网播放出错时player的duration、playableDuration、totalTime

    使用系统的AVplayer做点播播放器,断网播放出错后player的duration和playableDuration获取不到,写了get方法获取不到时返回0,然后就掉坑里了. 获取播放时长的get方 ...

  8. android ios av tv,iOS AVPlayer 实现后台连续播放视频

    最近接到一个需求,需要做一个在后台播放视频的功能.折腾了一下,最后总算完成了.因此写一篇文章,介绍下具体的实现步骤,也说说自己遇到的坑,算是总结和记录. 前言 当 App 退到后台时,会进入 susp ...

  9. AVPlayer详解系列(一)参数设置

    思维导图 先来一张思维导图,作为这篇文章的目录索引: AVPlayer.png 为什么使用AVPlayer: 首先在iOS平台使用播放视频,可用的选项一般有这四个,他们各自的作用和功能如下:   使用 ...

最新文章

  1. 网页如何与mysql服务器建立连接不上,html与mysql建立连接数据库
  2. 深度学习多框架多平台推理引擎工具
  3. 自动化部署之jenkins
  4. 小学计算机课知识点总结,小学计算机教学总结3篇
  5. 腾讯云发布专有云TCE矩阵,让企业用上金融级合规专有云
  6. css degrees_带有Python示例的math.degrees()方法
  7. 蚌埠学院计算机科学技术校区,蚌埠学院计算机科学与关键技术(6页)-原创力文档...
  8. 中国电信叫停不限量套餐 套外资费3元/GB
  9. Shiro报异常org.apache.shiro.authz.AuthorizationException: Not authorized to invoke method:
  10. IDEA中解决Edit Configurations中没有tomcat Server选项的问题(附配置Tomcat)
  11. python清空list_python怎么清空list
  12. Linux6新建分区,centos6中添加一块新的硬盘并分区的方法介绍
  13. 阿里云Web播放器使用
  14. java 牙位图插件_牙医的骄傲-智能牙位图中文医疗应用app全球排名No.1
  15. STM8停产,新唐的N76E003 pin对pin替换STM8S003F3P6
  16. 清除html中table标签显示的数据,jquery – 数据清除tbody
  17. java类的使用方法小结_JavaPoet的使用指南小结
  18. 我们手指触碰屏幕都做了什么?
  19. 【A Unified Model for Multi-class Anomaly Detection, NeurIPS 2022】
  20. python读取excel汉字转成拼音_python 批量将中文名转换为拼音

热门文章

  1. Android Framework 电源子系统(04)核心方法updatePowerStateLocked分析-2 循环处理  更新显示设备状态
  2. 浪潮服务器开机没有信号输出,PLC输出指示灯已经点亮但是输出没有信号-工业支持中心-西门子中国...
  3. 使用Excel打造一款个人日志系统
  4. Xcode自带的超好用的诊断工具
  5. macOS分发app打包+签名+公证+添加票据+生成dmg文件
  6. ccd坏点测试软件,如何测试CCD坏点(ZT)
  7. STM32F407VET6 / BLACK_F407VE开发板间隔0.5秒不断重启
  8. android 键盘 定义,自定义全键盘-[Android_YangKe]
  9. XiaomiRouter自学之路(13-U-boot支持web更新firmware功能)
  10. 兄弟Brother MFC-T800W 驱动