2014-5-7 06:46| 发布者: admin| 查看: 437| 评论: 0

 
摘要:   在iOS开发中,播放视频通常有两种方式,一种是使用MPMoviePlayerController(需要导入MediaPlayer.Framework),还有一种是使用AVPlayer。关于这两个类的区别可以参考http://stackoverflow.com/questions/814694 ...
 
 

  在ios开发中,播放视频通常有两种方式,一种是使用MPMoviePlayerController(需要导入MediaPlayer.Framework),还有一种是使用AVPlayer。关于这两个类的区别可以参考http://stackoverflow.com/questions/8146942/avplayer-and-mpmovieplayercontroller-differences,简而言之就是MPMoviePlayerController使用更简单,功能不如AVPlayer强大,而AVPlayer使用稍微麻烦点,不过功能更加强大。这篇博客主要介绍下AVPlayer的基本使用,由于博主也是刚刚接触,所以有问题大家直接指出~

  在开发中,单纯使用AVPlayer类是无法显示视频的,要将视频层添加至AVPlayerLayer中,这样才能将视频显示出来,所以先在ViewController的@interface中添加以下属性

  1. @property (nonatomic ,strong) AVPlayer *player;@property (nonatomic ,strong) AVPlayerItem *playerItem;
    @property (nonatomic ,weak) IBOutletPlayerView *playerView;

其中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

  1. + (Class)layerClass { return [AVPlayerLayer class];}- (AVPlayer *)player { return [(AVPlayerLayer *)[self layer] player];}- (void)setPlayer:(AVPlayer *)player { [(AVPlayerLayer *)[self layer] setPlayer:player];}

然后在viewDidLoad中执行初始化:

  1. 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];
    [[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(moviePlayDidEnd:) name:AVPlayerItemDidPlayToEndTimeNotificationobject: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 AVPlayerItemTrack—that correspond to the tracks in the asset.)

然后监听playerItem的status和loadedTimeRange属性,status有三种状态:

AVPlayerStatusUnknown,

AVPlayerStatusReadyToPlay,

AVPlayerStatusFailed

当status等于AVPlayerStatusReadyToPlay时代表视频已经可以播放了,我们就可以调用play方法播放了。

loadedTimeRange属性代表已经缓冲的进度,监听此属性可以在UI中更新缓冲进度,也是很有用的一个属性。

最后添加一个通知,用于监听视频是否已经播放完毕,然后实现KVO的方法:

  1. - (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方法:

  1. - (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做一些自定义,代码如下:

  1. - (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的基本使用的更多相关文章

  1. AVPlayer

    AVPlayer     AVPlayerLayer是CALayer的一个子类,由于AVPlayer这个播放器只能安置在AVPlayerLayer 这个图层之上,所以我们需要实例化一个UIView,并 ...

  2. 基于 AVPlayer 自定义播放器

    如果我只是简单的播放一个视频,而不需要考虑播放器的界面.iOS9.0 之前使用 MPMoviePlayerController, 或者内部自带一个 view 的 MPMoviePlayerViewCo ...

  3. iOS播放器 - AVPlayer

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

  4. 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 ...

  5. iOS:基于AVPlayer实现的视频播放器

    最近在学习AVFoundation框架的相关知识,写了一个基于AVPlayer的视频播放器,相关功能如下图: 代码github:https://github.com/wzpziyi1/VideoPla ...

  6. iOS开发 - AVPlayer实现流音频边播边存

    边播边下有三套左右实现思路,本文使用AVPlayer + AVURLAsset实现. 概述 1. AVPlayer简介 AVPlayer存在于AVFoundation中,可以播放视频和音频,可以理解为 ...

  7. AVPlayer的使用本地视频

    1引入AVFoundation.framework框架 2引入头文件<AVFoundation/AVFoundation.h>,并拖入需要播放的视频文件 代码如下: 自定义播放的View, ...

  8. iOS - AVPlayer 音视频播放

    前言 NS_CLASS_AVAILABLE(10_7, 4_0) @interface AVPlayer : NSObject @available(iOS 4.0, *) public class ...

  9. iOS在线音乐播放SZKAVPlayer(基于AVPlayer的封装)

    由于最近闲着没事,想找有关在线音乐播放的demo学习一下,在gitHub跟code4APP上面查找了很多帖子,结果很多在线音乐都是基于AudioStream实现的,我感觉用起来不太方便.后来突然发现, ...

随机推荐

  1. CentOS里下载百度网盘 / 360 网盘资源的方法

    wget -c --referer=引用地址 -O 文件名 "真实下载地址" 例如,我下载资源原在的页面为http://pan.baidu.com/s/1cfJXZ ,实际下载地址 ...

  2. 基于JQuery的渐隐渐现轮播

    <div id="ads"> <div> <!--轮播图片--> <ul> <li><a href="# ...

  3. 【CSS3】---结构性伪类选择器-first-child+last-child

    结构性伪类选择器—first-child “:first-child”选择器表示的是选择父元素的第一个子元素的元素E.简单点理解就是选择元素中的第一个子元素,记住是子元素,而不是后代元素. 示例演示 ...

  4. ASP.NET中后台注册js脚本攻略(转)

    用Page.ClientScript.RegisterClientScriptBlock 和Page.ClientScript.RegisterStartupScript:区别:   1.使用Page ...

  5. Mysql部分常用类型长度含义

    Int:一个Int类型4字节                              在sql中长度为1则代表一个Int类型的长度          有符号区分的范围:2147483647~-214 ...

  6. 浅谈sqlserver数据库优化(一)----开光篇

    今天暂时无事,风和日丽,万里无云.游山的.玩水的.遛麻雀的都闲的不亦乐乎,也忙的不亦乐乎.在这美好的季节,依旧躲在被窝或是电脑旁绞尽脑汁敲键盘的人们,也别有一番滋味.废话少说,言归正传. 赶上了一个最 ...

  7. 应该始终以PreparedStatement代替Statement

    在JDBC应用中,如果你已经是稍有水平开发者,你就应该始终以PreparedStatement代替Statement.也就是说,在任何时候都不要使用Statement 一.代码的可读性和可维护性.虽然 ...

  8. iOS开发那些事-iOS6苹果地图实用开发

    在iOS 6之后,不再使用谷歌地图了,而是使用苹果自己的地图,但是API编程接口没有太大的变化.开发人员不需要再学习很多新东西就能开发地图应用,这是负责任的做法.因此本节介绍的内容也同样适用于iOS5 ...

  9. Objective-C排序算法实现

    算法作为程序猿的一种基本技能,对我来说却一直是一个硬伤.毕竟平时的工作接触算法的地方很少,大部分时间都是在搭建UI,写业务逻辑,写网络请求.然而在面试当中,算法往往又是考察的重点. 也许你会说这些平时 ...

  10. 【Unity3D】Unity3D之 注册表动态存取游戏存档——PlayerPrefs类

    [Unity3D]Unity3D之 注册表动态存取游戏存档--PlayerPrefs类 1.Unity3D提供了一个用于本地持久化保存与读取的类--PlayerPrefs.工作原理非常简单,以键值对的 ...