iOS平台播放视频,系统提供了下面三种方式:MPMoviePlayerController、AVPlayerViewController、AVPlayer。前两种简单易用,但不可定制。最后一种AVPlayer:功能强大,可定制度高,唯一美中不足的是需要将视频层添加至AVPlayerLayer中,这样才能将视频显示出来。
开发时这样做
在ViewController的@interface中添加以下属性:
@property (nonatomic ,strong) AVPlayer *player;
@property (nonatomic ,strong) AVPlayerItem *playerItem;
@property (nonatomic , strong) PlayerView *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
+ (Class)layerClass {
return [AVPlayerLayer class];
}
- (AVPlayer *)player {
return [(AVPlayerLayer *)[self layer] player];
}
- (void)setPlayer:(AVPlayer *)player {
[(AVPlayerLayer *)[self layer] setPlayer:player];
}
然后执行下面代码,即可播放视频:
NSURL *videoUrl = [NSURL URLWithString:@"http://www.jxvdy.com/file/upload/201405/05/18-24-58-42-627.mp4"];
self.playerItem = [AVPlayerItem playerItemWithURL:videoUrl];
// status 播放状态
[self.playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
// loadedTimeRanges 缓存时间
[self.playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
// playbackBufferEmpty 缓存不足
[self.playerItem addObserver:self forKeyPath:@"playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:nil];
// playbackLikelyToKeepUp 缓存充足
[self.playerItem addObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];
self.player = [AVPlayer playerWithPlayerItem:self.playerItem];
[[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(moviePlayDidEnd:) name:AVPlayerItemDidPlayToEndTimeNotificationobject:self.playerItem];
AVPlayerItem监听的几个对象:
- status 播放状态
typedef NS_ENUM(NSInteger, AVPlayerItemStatus) {
AVPlayerItemStatusUnknown,//未知
AVPlayerItemStatusReadyToPlay,//准备播放
AVPlayerItemStatusFailed//播放失败
};
使用KVO监测playItem.status,可以获取播放状态的变化
- loadedTimeRanges 缓存时间
监测它可以知道视频的缓存情况,必要时可在缓存完成后将视频存入本地。 - playbackBufferEmpty与playbackLikelyToKeepUp,这两个是一对,即通常配对使用
playbackBufferEmpty可以让我们在缓存不够(视频加载不出来)时,暂停播放显示loading;
playbackLikelyToKeepUp则告诉我们缓存足够播放,此时重启播放。
KVO监听:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
if ([object isKindOfClass:[AVPlayerItem class]]) {
if ([keyPath isEqualToString:@"status"]) {
switch (_playerItem.status) {
case AVPlayerItemStatusReadyToPlay:
//推荐将视频播放放在这里
[self play];
break;
case AVPlayerItemStatusUnknown:
NSLog(@"AVPlayerItemStatusUnknown");
break;
case AVPlayerItemStatusFailed:
NSLog(@"AVPlayerItemStatusFailed")
break;
default:
break;
}
}else if ([keyPath isEqualToString:@"loadedTimeRanges"]){
NSArray *array = _playerItem.loadedTimeRanges;
CMTimeRange timeRange = [array.firstObject CMTimeRangeValue];//本次缓冲时间范围
float startSeconds = CMTimeGetSeconds(timeRange.start);
float durationSeconds = CMTimeGetSeconds(timeRange.duration);
NSTimeInterval totalBuffer = startSeconds + durationSeconds;//缓冲总长度
NSLog(@"当前缓冲时间:%f",totalBuffer);
}else if ([keyPath isEqualToString:@"playbackBufferEmpty"]) {
//some code show loading
}else if([keyPath isEqualToString:@"playbackLikelyToKeepUp"]) {
//由于 AVPlayer 缓存不足就会自动暂停,所以缓存充足了需要手动播放,才能继续播放
[_player play];
}
}
}
AVPlayerItem的几个常用通知:
//播放完成
AVPlayerItemDidPlayToEndTimeNotification
//播放失败
AVPlayerItemFailedToPlayToEndTimeNotification
//异常中断
AVPlayerItemPlaybackStalledNotification
// 使用
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerMovieFinish:) name:AVPlayerItemDidPlayToEndTimeNotification object:[self.player currentItem]];
参考:
1、AVPlayer的基本使用
2、AVPlayer详解系列(一)参数设置
网友评论