2019独角兽企业重金招聘Python工程师标准>>>

引言
本文主要针对ZFPlayer的功能实现来剖析,以及总结一下大家遇到的问题和解决方案
首先ZFPlayer现在拥有的功能:支持横、竖屏切换,在全屏播放模式下还可以锁定屏幕方向
支持本地视频、网络视频播放
支持在TableviewCell播放视频
左侧1/2位置上下滑动调节屏幕亮度(模拟器调不了亮度,请在真机调试)
右侧1/2位置上下滑动调节音量(模拟器调不了音量,请在真机调试)
左右滑动调节播放进度
全屏状态下拖动slider控制进度,显示视频的预览图
断点下载功能
切换视频分辨率、
ZFPlayer是对AVPlayer的封装,有人会问它支持什么格式的视频播放,问这个问题的可以自行搜索AVPlayer支持的格式。跟AVPlayer联系密切的名词:Asset:AVAsset是抽象类,不能直接使用,其子类AVURLAsset可以根据URL生成包含媒体信息的Asset对象。
AVPlayerItem:和媒体资源存在对应关系,管理媒体资源的信息和状态。
AVPlayerLayer: CALayer的subclass,它主要用来在iOS中播放视频内容
具体功能实现
1、通过一个网络链接播放视频
AVURLAsset *urlAsset = [AVURLAsset assetWithURL:videoURL];
// 初始化playerItem
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:urlAsset];
// 也可以使用来初始化playerItem
// AVPlayerItem * playerItem = [AVPlayerItem playerItemWithURL:videoURL];// 初始化Player
AVPlayer *player = [AVPlayer playerWithPlayerItem:self.playerItem];
// 初始化playerLayer
AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
// 添加playerLayer到self.layer
[self.layer insertSublayer:self.playerLayer atIndex:0];
2、播放器的常用操作
播放:
[player play];
需要注意的是初始化完player之后不一定会马上开始播放,需要等待player的状态变为ReadyToPlay才会进行播放。
暂停:
[player pause];
3、播放多个items
这里我们有两种方式可以实现,一种是由你自行控制下一首歌曲的item,将其替换到当前播放的item[player replaceCurrentItemWithPlayerItem:playerItem];
在iOS9后,AVPlayer的replaceCurrentItemWithPlayerItem方法在切换视频时底层会调用信号量等待然后导致当前线程卡顿,如果在UITableViewCell中切换视频播放使用这个方法,会导致当前线程冻结几秒钟。遇到这个坑还真不好在系统层面对它做什么,后来找到的解决方法是在每次需要切换视频时,需重新创建AVPlayer和AVPlayerItem。另一种可以使用AVQueuePlayer播放多个items,AVQueuePlayer是AVPlayer的子类,可以用一个数组来初始化一个AVQueuePlayer对象。代码如下:NSArray *items = <#An array of player items#>;
AVQueuePlayer *queuePlayer = [[AVQueuePlayer alloc] initWithItems:items];
和AVPlayer一样,直接调用play方法来播放,queue player顺序播放队列中的item,如果想要跳过一个item,播放下一个item,可以调用方法advanceToNextItem。可以对队列进行插入和删除操作,调用方法insertItem:afterItem:, removeItem:, 和 removeAllItems。正常情况下当插入一个item之前,应该检查是否可以插入,通过使用canInsertItem:afterItem:方法,第二个参数传nil,代码如下:AVPlayerItem *anItem = <#Get a player item#>;
if ([queuePlayer canInsertItem:anItem afterItem:nil]) {[queuePlayer insertItem:anItem afterItem:nil];
}
4、seekToTime指定从某一秒开始播放
可以使用seekToTime:定位播放头到指定的时间,如下代码:CMTime fiveSecondsIn = CMTimeMake(5, 1);
[player seekToTime:fiveSecondsIn];
seekTime:不能精确定位,如果需要精确定位,可以使用seekToTime:toleranceBefore:toleranceAfter:,代码如下:CMTime fiveSecondsIn = CMTimeMake(5, 1);
[player seekToTime:fiveSecondsIn toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
当tolerance=0的时候,framework需要进行大量解码工作,比较耗性能,所以,只有当你必须使用的时候才用这个方法,比如开发一个复杂的多媒体编辑应用,这需要精确的控制。关于重播什么的就不用我多说了吧,点击重播seekToTime:kCMTimeZero。还有关于下次播放的时候从上次离开的那个时间开始播放,大家都有思路啦吧,当离开当前视频时候记录播放到哪一秒了,下次点开直接seekToTime到那一秒开始播放就好了嘛。5、监听播放进度
使用addPeriodicTimeObserverForInterval:queue:usingBlock:来监听播放器的进度
(1)方法传入一个CMTime结构体,每到一定时间都会回调一次,包括开始和结束播放
(2)如果block里面的操作耗时太长,下次不一定会收到回调,所以尽量减少block的操作耗时
(3)方法会返回一个观察者对象,当播放完毕时需要移除这个观察者
添加观察者:id timeObserve = [player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {float current = CMTimeGetSeconds(time);float total = CMTimeGetSeconds(songItem.duration);if (current) {weakSelf.progress = current / total;weakSelf.playTime = [NSString stringWithFormat:@"%.f",current];weakSelf.playDuration = [NSString stringWithFormat:@"%.2f",total];       }
}];
移除观察者:if (timeObserve) {[player removeTimeObserver:_timeObserve];timeObserve = nil;}
6、监听改播放器状态
[playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
播放器的三种状态,当playerItem的状态变为AVPlayerItemStatusReadyToPlay才会进行播放。typedef NS_ENUM(NSInteger, AVPlayerItemStatus) {AVPlayerItemStatusUnknown,AVPlayerItemStatusReadyToPlay,AVPlayerItemStatusFailed
};
播放完了需要移除观察者[playerItem removeObserver:self forKeyPath:@"status"];
7、监听缓冲进度
[playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
播放完了需要移除观察者[playerItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
8、监听网络缓冲状态
// 缓冲区空了,需要等待数据
[playerItem addObserver:self forKeyPath:@"playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:nil];
// 缓冲区有足够数据可以播放了
[playerItem addObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];
播放完了需要移除观察者[playerItem removeObserver:self forKeyPath:@"playbackBufferEmpty"];
[playerItem removeObserver:self forKeyPath:@"playbackLikelyToKeepUp"];
9、监听AVPlayer播放完成通知
监听通知AVPlayerItemDidPlayToEndTimeNotification,来处理一些播放完的事情[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemDidReachEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
10、 系统音量相关
/***  获取系统音量*/
- (void)configureVolume
{MPVolumeView *volumeView = [[MPVolumeView alloc] init];_volumeViewSlider = nil;for (UIView *view in [volumeView subviews]){if ([view.class.description isEqualToString:@"MPVolumeSlider"]){_volumeViewSlider = (UISlider *)view;break;}}// 使用这个category的应用不会随着手机静音键打开而静音,可在手机静音下播放声音NSError *setCategoryError = nil;BOOL success = [[AVAudioSession sharedInstance]setCategory: AVAudioSessionCategoryPlaybackerror: &setCategoryError];if (!success) { /* handle the error in setCategoryError */ }// 监听耳机插入和拔掉通知[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioRouteChangeListenerCallback:) name:AVAudioSessionRouteChangeNotification object:nil];
}/***  耳机插入、拔出事件*/
- (void)audioRouteChangeListenerCallback:(NSNotification*)notification
{NSDictionary *interuptionDict = notification.userInfo;NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue];switch (routeChangeReason) {case AVAudioSessionRouteChangeReasonNewDeviceAvailable:// 耳机插入break;case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:{// 耳机拔掉// 拔掉耳机继续播放[self play];}break;case AVAudioSessionRouteChangeReasonCategoryChange:// called at start - also when other audio wants to playNSLog(@"AVAudioSessionRouteChangeReasonCategoryChange");break;}
}
设置系统音量// 0 ... 1.0的数值, 1.0是最大的声音.
self.volumeViewSlider.value = ...
11、屏幕亮度相关
// 0 ... 1.0的数值, 1.0是最大的亮度.
[UIScreen mainScreen].brightness -= ...
12、屏幕旋转相关
苹果手机除iPhone 4s(320*480)屏幕宽高比不是16:9外,其他都为16:9,所以横竖屏可以这样实现,这里必须使用autolayout,这里提供两种方法实现:使用Xib或者Storyboard的话,必须把播放器view的宽高比设置成16:9,4s的话可以单独适配加约束(使用sizeClasses)
使用masonry,具体代码如下:
[self.playerView mas_makeConstraints:^(MASConstraintMaker *make) {make.top.equalTo(self.view).offset(20);make.left.right.equalTo(self.view);// 注意此处,宽高比16:9优先级比1000低就行,在因为iPhone 4S宽高比不是16:9make.height.equalTo(self.playerView.mas_width).multipliedBy(9.0f/16.0f).with.priority(750);}];
关于屏幕旋转可以这样强制让屏幕转屏,有人会问了,在我demo中为啥能转屏,而集成到自己项目中不能转屏,我可以明确的告诉你,是你们项目的横屏给禁止掉了,你可以看一下这里是否打钩啦:设备方向
有人又会问了,我们想实现这么个需求,只有在播放器页面支持横屏,其他页面不支持横屏。好了,那下边我来告诉怎么实现,首先上图中的横屏必须勾选,其次在你项目window的rootViewController中来实现两个方法:// 哪些页面支持自动转屏
- (BOOL)shouldAutorotate;
// viewcontroller支持哪些转屏方向
- (UIInterfaceOrientationMask)supportedInterfaceOrientations;
这两个方法看我注释你就知道什么意思啦,这两个方法会不停的调用,不信你可以打断点试试,具体实现你去demo看看吧,在MainViewcontroller中。下边来说说强制屏幕旋转,即使用户的手机锁定啦屏幕方法,调用这个方法照样可以旋转:/***  强制屏幕转屏**  @param orientation 屏幕方向*/
- (void)interfaceOrientation:(UIInterfaceOrientation)orientation
{// arc下if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {SEL selector             = NSSelectorFromString(@"setOrientation:");NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];[invocation setSelector:selector];[invocation setTarget:[UIDevice currentDevice]];int val                  = orientation;// 从2开始是因为0 1 两个参数已经被selector和target占用[invocation setArgument:&val atIndex:2];[invocation invoke];}/*// 非arc下if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {[[UIDevice currentDevice] performSelector:@selector(setOrientation:)withObject:@(orientation)];}// 直接调用这个方法通不过apple上架审核[[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:UIInterfaceOrientationLandscapeRight] forKey:@"orientation"];*/
}
监听设备旋转通知,来处理一些UI显示问题[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(onDeviceOrientationChange)name:UIDeviceOrientationDidChangeNotificationobject:nil
];文/renzifeng(简书作者)
原文链接:http://www.jianshu.com/p/5566077bb25f
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

转载于:https://my.oschina.net/u/2562364/blog/733005

iOS视频播放器之ZFPlayer剖析相关推荐

  1. 从零开始学习音视频编程技术(七) FFMPEG Qt视频播放器之SDL的使用

    从零开始学习音视频编程技术(七) FFMPEG Qt视频播放器之SDL的使用 原文地址:http://blog.yundiantech.com/?log=blog&id=10 前面介绍了使用F ...

  2. iOS 视频播放器开发

    需求设计 做一个小学生教育辅导视频播放器. 参考小猿搜题视频播放器 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L0GsyFSt-1675164972791)(htt ...

  3. iOS: ios视频播放(MPMediaPlayerController,AVPlayer,AVPlayerViewcontroller、ffmpeg-AVPlayer)...

    介绍: 和音频播放一样,ios也提供个很多的API.如mediaPlayer.framework下的MPMediaPlayerController.AVFounditon.framework下的AVP ...

  4. golang 关闭gc 并手动gc_Golang 大杀器之跟踪剖析 trace

    Go语言中文网,致力于每日分享编码.开源等知识,欢迎关注我,会有意想不到的收获! 在 Go 中有许许多多的分析工具,在之前我有写过一篇 Golang 大杀器之性能剖析 PProf 来介绍 PProf, ...

  5. Golang 大杀器之跟踪剖析 trace(转载)

    转载地址:https://mp.weixin.qq.com/s/iXkbF018fxgTWtMqxZfo6g 以下文章来源于不会写Go的煎鱼 ,作者陈煎鱼 不会写Go的煎鱼 知其然,知其所以然. 在 ...

  6. 从零开始学习音视频编程技术(六) FFMPEG Qt视频播放器之显示图像

    从零开始学习音视频编程技术(六) FFMPEG Qt视频播放器之显示图像 原文地址:http://blog.yundiantech.com/?log=blog&id=9 前面讲解了如何用FFM ...

  7. iOS视频播放的基本方法

    本文总结了iOS中最常见的视频播放方法,不同的方法都各具特点,我希望能够总结它们的不同,方便在开发中选择合适的技术方案. Apple为我们提供了多种方法来实现视频播放,包括MPMoviePlayerC ...

  8. 基于libVLC的视频播放器之二:使用VLC-Qt播放RTSP流

    此篇是 使用VLC浏览器插件播放RTSP流的姊妹篇. 一.直接使用libVLC libVLC是VLC media player多媒体框架的核心引擎和接口,开发者使用它能轻松的创建大量具有VLC特性的应 ...

  9. FFmpeg开发(五)——Qt视频播放器之封装FFmpeg类(参考了暴风影音、迅雷影音)

    FFmpeg开发(五)--Qt视频播放器之封装FFmpeg类(参考了暴风影音.迅雷影音) 上一篇介绍了,使用Qt和FFmpeg写的播放器.页面大家可以点进去查看和下载. FFmpeg开发(四)--Qt ...

最新文章

  1. LINQ中的Let关键字
  2. MySQL的高级应用:视图,事务,索引,主从
  3. python菜谱发送到邮箱_Python菜谱5:发送带附件的邮件
  4. 如何优雅地实现判断一个值是否在一个集合中?
  5. random.next_Java Random next()方法与示例
  6. Doc2Vec训练相似文章识别模型
  7. 三大应用需求:5G信道编码技术取得突破
  8. 理解K8S的编排和网络
  9. mcgs组态软件中字体如果从左到右变化_MCGS全中文组态软件常见问题
  10. 探究Ptcms小说采集规则
  11. 常用连接服务器的ssh工具
  12. 用excel制作双层饼图_Excel 怎么用环形图制作双层饼图,excle饼状图图的制作
  13. oracle分区表和分区索引的概念
  14. Neo4j 学习笔记 1:属性图
  15. 脑机接口竞赛( BCI competition)数据集,其他数据集下载链接
  16. 华为手机设置信息服务器地址,华为手机如何设置云服务器地址
  17. PyTorch学习系列教程:构建一个深度学习模型需要哪几步?
  18. 上号神器,和平精英扫码登录教程
  19. Mine Goose Duck 0.4版本发布
  20. 面试时该如何反问面试官问题?

热门文章

  1. 2019年上半年收集到的人工智能AutoML干货文章
  2. 「AI白身境」究竟谁是paper之王,全球前10的计算机科学家
  3. 人工智能不是单纯的经验和总结
  4. 自然语言处理NLP国内研究方向机构导师
  5. 困扰爱因斯坦的「幽灵般的超距作用」,是如何被贝尔定理证明确实存在的?...
  6. 理解与理论:人工智能基础问题的悲观与乐观
  7. 为什么数学是理解世界的最佳方式
  8. 没有精准定位,万物还能实现互联吗?
  9. Nature解析中国AI现状,2030年能引领全球吗?
  10. 量子计算机不会“秒杀”经典计算机