在iOS開發(fā)中,播放視頻通常有兩種方式,一種是使用MPMoviePlayerController(需要導入MediaPlayer.Framework),還有一種是使用AVPlayer。關(guān)于這兩個類的區(qū)別可以參考http://stackoverflow.com/questions/8146942/avplayer-and-mpmovieplayercontroller-differences,簡而言之就是MPMoviePlayerController使用更簡單,功能不如AVPlayer強大,而AVPlayer使用稍微麻煩點,不過功能更加強大。這篇博客主要介紹下AVPlayer的基本使用,由于博主也是剛剛接觸,所以有問題大家直接指出~
0x01.新建一個ViewController類并添加下面代碼
在開發(fā)中,單純使用AVPlayer類是無法顯示視頻的,要將視頻層添加至AVPlayerLayer中,這樣才能將視頻顯示出來,所以先在ViewController的@interface中添加以下屬性
viewController.m
@property (nonatomic,strong) AVPlayer *avPlayer;
@property (nonatomic,strong) AVPlayerItem *avPlayerItem;
@property (nonatomic,strong) AVPlayerLayer *avPlayerLayer;
在viewDidLoad中寫下下面代碼。
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.avPlayerItem = [AVPlayerItem playerItemWithURL:self.videoUrl];
//對item添加監(jiān)聽
[self.avPlayerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
[self.avPlayerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
//[self.playItem addObserver:self forKeyPath:@"playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:nil];
self.avPlayer = [AVPlayer playerWithPlayerItem:self.avPlayerItem];
self.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
AVPlayView *avPlayerView = [[AVPlayView alloc] initWithMoviePlayerLayer:self.avPlayerLayer frame:self.view.bounds];
avPlayerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:avPlayerView];
//這里可以實現(xiàn)界面代碼。
//[self initSubViews];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(moviePlayDidEnd) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
}
- (void)moviePlayDidEnd
{
NSLog(@"播放完成");
[self.avPlayer pause];
[self.link invalidate];
[self dismissViewControllerAnimated:YES completion:nil];
}
其中playerView繼承自UIView,不過重寫了set和get方法,用于將player添加至playerView的AVPlayerLayer中,這樣才能順利將視頻顯示出來
0x02.新建一個AVPlayerView:UIView類并添加下面代碼。
在PlayerView.h中聲明一個AVPlayer對象,由于默認的layer是CALayer,而AVPlayer只能添加至AVPlayerLayer中,所以我們改變一下layerClass,這樣PlayerView的默認layer就變了,之后我們可以把在viewController中初始化的AVPlayer對象賦給AVPlayerLayer的player屬性。
AVPlayerView.h
@property (nonatomic ,strong) AVPlayer *player;
AVPlayerView.m
#import "AVPlayView.h"
@interface AVPlayView()
{
AVPlayerLayer *_playerlayer;
}
@end
@implementation AVPlayView
-(instancetype)initWithMoviePlayerLayer:(AVPlayerLayer *)playerLayer frame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
_playerlayer = playerLayer;
playerLayer.backgroundColor = [UIColor blackColor].CGColor;
_playerlayer.videoGravity = AVLayerVideoGravityResizeAspect;
_playerlayer.contentsScale = [UIScreen mainScreen].scale;
[self.layer addSublayer:_playerlayer];
}
return self;
}
-(void)layoutSublayersOfLayer:(CALayer *)layer{
[super layoutSublayersOfLayer:layer];
_playerlayer.bounds = self.layer.bounds;
_playerlayer.position = self.layer.position;
}
0x03.實現(xiàn)視頻的播放:
第一步在viewDidLoad中執(zhí)行初始化:
先將在線視頻鏈接存放在videoUrl中,然后初始化playerItem,playerItem是管理資源的對象
然后監(jiān)聽playerItem的status和loadedTimeRange屬性,status有三種狀態(tài):
AVPlayerStatusUnknown,
AVPlayerStatusReadyToPlay,
AVPlayerStatusFailed
當status等于AVPlayerStatusReadyToPlay時代表視頻已經(jīng)可以播放了,我們就可以調(diào)用play方法播放了。
loadedTimeRange屬性代表已經(jīng)緩沖的進度,監(jiān)聽此屬性可以在UI中更新緩沖進度,也是很有用的一個屬性。
最后添加一個通知,用于監(jiān)聽視頻是否已經(jīng)播放完畢,然后實現(xiàn)KVO的方法:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
AVPlayerItem *playerItem = (AVPlayerItem *)object;
if ([keyPath isEqualToString:@"loadedTimeRanges"]){
NSTimeInterval loadedTime = [self availableDurationWithplayerItem:playerItem];
NSTimeInterval totalTime = CMTimeGetSeconds(playerItem.duration);
//if (!self.slider.isSliding) {
//self.slider.progressPercent = loadedTime/totalTime;
//}
}else if ([keyPath isEqualToString:@"status"]){
if (playerItem.status == AVPlayerItemStatusReadyToPlay){
//NSLog(@"playerItem is ready");
[self.avPlayer play];
self.slider.enabled = YES;
self.playButton.enabled = YES;
} else{
NSLog(@"load break");
//self.faildView.hidden = NO;
}
}
}
- (NSTimeInterval)availableDurationWithplayerItem:(AVPlayerItem *)playerItem
{
NSArray *loadedTimeRanges = [playerItem loadedTimeRanges];
CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];// 獲取緩沖區(qū)域
NSTimeInterval startSeconds = CMTimeGetSeconds(timeRange.start);
NSTimeInterval durationSeconds = CMTimeGetSeconds(timeRange.duration);
NSTimeInterval result = startSeconds + durationSeconds;// 計算緩沖總進度
return result;
}
此方法主要對status和loadedTimeRanges屬性做出響應,status狀態(tài)變?yōu)锳VPlayerStatusReadyToPlay時,說明視頻已經(jīng)可以播放了,這時我們可以獲取一些視頻的信息,包含視頻長度等,把播放按鈕設(shè)備enabled,點擊就可以調(diào)用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用于監(jiān)聽每秒的狀態(tài),- (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(dispatch_queue_t)queue usingBlock:(void (^)(CMTime time))block;此方法就是關(guān)鍵,interval參數(shù)為響應的間隔時間,這里設(shè)為每秒都響應,queue是隊列,傳NULL代表在主線程執(zhí)行??梢愿乱粋€UI,比如進度條的當前時間等。
0x04.播放器其他元素。
這里只介紹播放方法,具體暫停功能、播放進度、時間顯示等在這里不做討論。