AVPlayer的基本使用
2014-5-7 06:46| 发布者: admin| 查看: 437| 评论: 0
|
在ios开发中,播放视频通常有两种方式,一种是使用MPMoviePlayerController(需要导入MediaPlayer.Framework),还有一种是使用AVPlayer。关于这两个类的区别可以参考http://stackoverflow.com/questions/8146942/avplayer-and-mpmovieplayercontroller-differences,简而言之就是MPMoviePlayerController使用更简单,功能不如AVPlayer强大,而AVPlayer使用稍微麻烦点,不过功能更加强大。这篇博客主要介绍下AVPlayer的基本使用,由于博主也是刚刚接触,所以有问题大家直接指出~ 在开发中,单纯使用AVPlayer类是无法显示视频的,要将视频层添加至AVPlayerLayer中,这样才能将视频显示出来,所以先在ViewController的@interface中添加以下属性 @property (nonatomic ,strong) AVPlayer *player;@property (nonatomic ,strong) AVPlayerItem *playerItem; 其中playerView继承自UIView,不过重写了set和get方法,用于将player添加至playerView的AVPlayerLayer中,这样才能顺利将视频显示出来 在PlayerView.h中声明一个AVPlayer对象,由于默认的layer是CALayer,而AVPlayer只能添加至AVPlayerLayer中,所以我们改变一下layerClass,这样PlayerView的默认layer就变了,之后我们可以把在viewController中初始化的AVPlayer对象赋给AVPlayerLayer的player属性。 PlayerView.h @property (nonatomic ,strong) AVPlayer *player; PlayerView.m + (Class)layerClass { return [AVPlayerLayer class];}- (AVPlayer *)player { return [(AVPlayerLayer *)[self layer] player];}- (void)setPlayer:(AVPlayer *)player { [(AVPlayerLayer *)[self layer] setPlayer:player];}
然后在viewDidLoad中执行初始化: NSURL *videoUrl = [NSURL URLWithString:@"http://www.jxvdy.com/file/upload/201405/05/18-24-58-42-627.mp4"];self.playerItem = [AVPlayerItem playerItemWithURL:videoUrl];[self.playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];// 监听status属性[self.playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];// 监听loadedTimeRanges属性self.player = [AVPlayer playerWithPlayerItem:self.playerItem]; 先将在线视频链接存放在videoUrl中,然后初始化playerItem,playerItem是管理资源的对象(A player item manages the presentation state of an asset with which it is associated. A player item contains player item tracks—instances of
然后监听playerItem的status和loadedTimeRange属性,status有三种状态: AVPlayerStatusUnknown, AVPlayerStatusReadyToPlay, AVPlayerStatusFailed 当status等于AVPlayerStatusReadyToPlay时代表视频已经可以播放了,我们就可以调用play方法播放了。 loadedTimeRange属性代表已经缓冲的进度,监听此属性可以在UI中更新缓冲进度,也是很有用的一个属性。 最后添加一个通知,用于监听视频是否已经播放完毕,然后实现KVO的方法: - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { AVPlayerItem *playerItem = (AVPlayerItem *)object; if ([keyPath isEqualToString:@"status"]) { if ([playerItem status] == AVPlayerStatusReadyToPlay) { NSLog(@"AVPlayerStatusReadyToPlay"); self.stateButton.enabled = YES; CMTime duration = self.playerItem.duration;// 获取视频总长度 CGFloat totalSecond = playerItem.duration.value / playerItem.duration.timescale;// 转换成秒 _totalTime = [self convertTime:totalSecond];// 转换成播放时间 [self customVideoSlider:duration];// 自定义UISlider外观 NSLog(@"movie total duration:%f",CMTimeGetSeconds(duration)); [self monitoringPlayback:self.playerItem];// 监听播放状态 } else if ([playerItem status] == AVPlayerStatusFailed) { NSLog(@"AVPlayerStatusFailed"); } } else if ([keyPath isEqualToString:@"loadedTimeRanges"]) { NSTimeInterval timeInterval = [self availableDuration];// 计算缓冲进度 NSLog(@"Time Interval:%f",timeInterval); CMTime duration = self.playerItem.duration; CGFloat totalDuration = CMTimeGetSeconds(duration); [self.videoProgress setProgress:timeInterval / totalDuration animated:YES]; }}- (NSTimeInterval)availableDuration { NSArray *loadedTimeRanges = [[self.playerView.player currentItem] loadedTimeRanges]; CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];// 获取缓冲区域 float startSeconds = CMTimeGetSeconds(timeRange.start); float durationSeconds = CMTimeGetSeconds(timeRange.duration); NSTimeInterval result = startSeconds + durationSeconds;// 计算缓冲总进度 return result;}- (NSString *)convertTime:(CGFloat)second{ NSDate *d = [NSDate dateWithTimeIntervalSince1970:second]; NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; if (second/3600 >= 1) { [formatter setDateFormat:@"HH:mm:ss"]; } else { [formatter setDateFormat:@"mm:ss"]; } NSString *showtimeNew = [formatter stringFromDate:d]; return showtimeNew;}
此方法主要对status和loadedTimeRanges属性做出响应,status状态变为AVPlayerStatusReadyToPlay时,说明视频已经可以播放了,这时我们可以获取一些视频的信息,包含视频长度等,把播放按钮设备enabled,点击就可以调用play方法播放视频了。在AVPlayerStatusReadyToPlay的底部还有个monitoringPlayback方法: - (void)monitoringPlayback:(AVPlayerItem *)playerItem { self.playbackTimeObserver = [self.playerView.player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:NULL usingBlock:^(CMTime time) { CGFloat currentSecond = playerItem.currentTime.value/playerItem.currentTime.timescale;// 计算当前在第几秒 [self updateVideoSlider:currentSecond]; NSString *timeString = [self convertTime:currentSecond]; self.timeLabel.text = [NSString stringWithFormat:@"%@/%@",timeString,_totalTime]; }];}
monitoringPlayback用于监听每秒的状态,- (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(dispatch_queue_t)queue usingBlock:(void (^)(CMTime time))block;此方法就是关键,interval参数为响应的间隔时间,这里设为每秒都响应,queue是队列,传NULL代表在主线程执行。可以更新一个UI,比如进度条的当前时间等。 作为播放器,除了播放,暂停等功能外。还有一个必不可少的功能,那就是显示当前播放进度,还有缓冲的区域,我的思路是这样,用UIProgressView显示缓冲的可播放区域,用UISlider显示当前正在播放的进度,当然这里要对UISlider做一些自定义,代码如下: - (void)customVideoSlider:(CMTime)duration { self.videoSlider.maximumValue = CMTimeGetSeconds(duration); UIGraphicsBeginImageContextWithOptions((CGSize){ 1, 1 }, NO, 0.0f); UIImage *transparentImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); [self.videoSlider setMinimumTrackImage:transparentImage forState:UIControlStateNormal]; [self.videoSlider setMaximumTrackImage:transparentImage forState:UIControlStateNormal];}
这样UISlider就只有中间的ThumbImage了,而ThumbImage左右的颜色都变成透明的了,仅仅是用于显示当前的播放时间。UIProgressView则用于显示当前缓冲的区域,不做任何自定义的修改,在StoryBoard看起来是这样的:
把UISlider添加至UIProgressView上面,运行起来的效果就变成了这样:
这样基本的缓冲功能就做好了,当然还有一些功能没做,比如音量大小,滑动屏幕快进快退等,大家有时间可以自己做着玩儿下~ 最后的效果如下:
|
AVPlayer的基本使用的更多相关文章
- AVPlayer
AVPlayer AVPlayerLayer是CALayer的一个子类,由于AVPlayer这个播放器只能安置在AVPlayerLayer 这个图层之上,所以我们需要实例化一个UIView,并 ...
- 基于 AVPlayer 自定义播放器
如果我只是简单的播放一个视频,而不需要考虑播放器的界面.iOS9.0 之前使用 MPMoviePlayerController, 或者内部自带一个 view 的 MPMoviePlayerViewCo ...
- iOS播放器 - AVPlayer
之前有说到在播放器中一点点小技巧,现在正式记录一下AVPlayer. 这里主要是说明用AVPlayer做音乐播放器的功能实现,所以不介绍AVPlayer中那个图层类. 首先我们要声明一下播放器,这里有 ...
- An AVPlayerItem cannot be associated with more than one instance of AVPlayer错误
An AVPlayerItem cannot be associated with more than one instance of AVPlayer An AVPlayerItem cannot ...
- iOS:基于AVPlayer实现的视频播放器
最近在学习AVFoundation框架的相关知识,写了一个基于AVPlayer的视频播放器,相关功能如下图: 代码github:https://github.com/wzpziyi1/VideoPla ...
- iOS开发 - AVPlayer实现流音频边播边存
边播边下有三套左右实现思路,本文使用AVPlayer + AVURLAsset实现. 概述 1. AVPlayer简介 AVPlayer存在于AVFoundation中,可以播放视频和音频,可以理解为 ...
- AVPlayer的使用本地视频
1引入AVFoundation.framework框架 2引入头文件<AVFoundation/AVFoundation.h>,并拖入需要播放的视频文件 代码如下: 自定义播放的View, ...
- iOS - AVPlayer 音视频播放
前言 NS_CLASS_AVAILABLE(10_7, 4_0) @interface AVPlayer : NSObject @available(iOS 4.0, *) public class ...
- iOS在线音乐播放SZKAVPlayer(基于AVPlayer的封装)
由于最近闲着没事,想找有关在线音乐播放的demo学习一下,在gitHub跟code4APP上面查找了很多帖子,结果很多在线音乐都是基于AudioStream实现的,我感觉用起来不太方便.后来突然发现, ...
随机推荐
- hdu 4739 状压DP
这里有状态压缩DP的好博文 题目:题目比较神,自己看题目吧 分析: 大概有两种思路: 1.dfs,判断正方形的话可以通过枚举对角线,大概每次减少4个三角形,加上一些小剪枝的话可以过. 2.状压DP,先 ...
- xcode报错 has been modified since the precompiled header was built
删除/Users/username/Library/Developer/Xcode/DerivedData/ModuleCache 下的所有文件
- IDG合伙人李丰:O2O中的C2C蕴藏巨大商机
[ 亿欧导读 ] IDG合伙人李丰表示,每个新趋势出现,都是在解决上一轮行业革新时没有解决好的市场需求.而O2O中的C2C将会出现巨大商机的原因在于移动互联网的出现创造了新的交互方式,可以更快速的匹配 ...
- 五.CSS盒子模型
所谓盒模型,就是浏览器为每个HTML元素生成的矩形盒子.即HTML页面实际上就是由一系列盒子组成.这些盒子是按照可见版式在页面上排布的.并由三个属性进行控制:position属性,display属性, ...
- android app性能优化大汇总(UI渲染性能优化)
UI性能测试 性能优化都需要有一个目标,UI的性能优化也是一样.你可能会觉得“我的app加载很快”很重要,但我们还需要了解终端用户的期望,是否可以去量化这些期望呢?我们可以从人机交互心理学的角度来考虑 ...
- java中的@Override是否需要
java中的重载注解 @Override 是否需要?今天被人问到这个问题,回答的不太好,下来看了一下源码 /** * Annotation type used to mark methods that ...
- C#自定义时间显示格式
string time = System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); 下面是常见的一些日期时间显示格式 标准的For ...
- 快速调试chromium
上一篇我们简单的将了在Ubuntu上编译chromium,android content_shell_apk的编译,一切顺利的就能生成apk.但是我们仅仅只是照搬了人家google开源的东西,作为一个 ...
- C#中如何查找Dictionary中的重复值
简介 在这篇帮助文档中,我将向你展示如何实现c#里字典中重复值的查找.你知道的对于一个老鸟来说,这是非常简单的代码.但是尽管如此,这也是一篇对c#初学者非常有用的帮助文档. 背景 多数程序员对小型数据 ...
- Sql中判断"库、表、列,视图,存储过程"是否存在
--判断数据库是否存在 IF EXISTS (SELECT * FROM MASTER.sys.sysdatabases WHERE NAME = '库名') PRINT 'exists ' else ...



