iOS已經(jīng)提供了一些視頻播放的API,封裝性很強,使用上也比較方便,但是自定制UI比較困難,自由度比較低:
- MPMoviePlayerController
- AVPictureInPictureController
所以我們自己用AVPlayer實現(xiàn)一些視頻播放的定制開發(fā)。AVPlayer屬于AVFoundation框架,可以播放視頻、音頻,支持本地、網(wǎng)絡視頻源,相對來說更加接近底層。
實現(xiàn)視頻播放
AVFoundtion 框架中主要使用 AVAsset 類來展示媒體信息,了解幾個常用類:
1、AVAsset:AVAsset類專門用于獲取多媒體的相關信息,包括獲取多媒體的畫面、聲音等信息,屬于一個抽象類,不能直接使用。
2、AVURLAsset:AVAsset的子類,可以根據(jù)一個URL路徑創(chuàng)建一個包含媒體信息的AVURLAsset對象。
3、AVPlayerItem:一個媒體資源管理對象,管理者視頻的一些基本信息和狀態(tài),一個AVPlayerItem對應著一個視頻資源。
在AVPlayer實現(xiàn)視頻播放的開發(fā)中,AVPlayerLayer 顯示視頻,AVPlayerItem 提供視頻信息, AVPlayer 管理和調(diào)控.
AVPlayer 本身并不能顯示視頻, 顯示視頻的是 AVPlayerLayer。 AVPlayerLayer 繼承自 CALayer。
初始化操作:
AVPlayer初始化
- (AVPlayer *)avPlayer
{
if (_avPlayer == nil) {
_avPlayer = [[AVPlayer alloc] init];
// 設置默認音量
_avPlayer.volume = 0.5;
}
return _avPlayer;
}
- (instancetype)init
{
if (self = [super init]) {
// 讓view的layerClass為AVPlayerLayer類,那么self.layer就為AVPlayerLayer的實例
self.playerLayer = (AVPlayerLayer *)self.layer;
self.playerLayer.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6].CGColor;
// 初始化playerLayer的player
self.playerLayer.player = self.avPlayer;
}
return self;
}
設置媒體資源
- (void)settingPlayerItem:(AVPlayerItem *)playerItem
{
_playerItem = playerItem;
[self.avPlayer pause];
/*
replaceCurrentItemWithPlayerItem: 用于切換視頻
*/
// 設置當前playerItem
[self.avPlayer replaceCurrentItemWithPlayerItem:playerItem];
[self.avPlayer play];
}
視頻播放
- (void)viewDidLoad {
[super viewDidLoad];
CGFloat palyerW = [UIScreen mainScreen].bounds.size.width;
NKAVPlayerView *playerView = [[NKAVPlayerView alloc] init];
playerView.frame = CGRectMake(0, 0, palyerW, palyerW / 7 * 4);
[self.view addSubview:playerView];
NSString *moviePath = [[NSBundle mainBundle] pathForResource:@"movie" ofType:@"mp4"];
[playerView settingPlayerItemWithUrl:[NSURL fileURLWithPath:moviePath]];
}
這樣視頻播放就完成,附上運行效果:
視頻播放的控制
- 監(jiān)控播放狀態(tài)
// 監(jiān)控它的status也可以獲得播放狀態(tài)
[self.avPlayer.currentItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
- 監(jiān)控緩沖加載
//監(jiān)控緩沖加載
[self.avPlayer.currentItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
- 監(jiān)控播放完成
//監(jiān)控播放完成
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.avPlayer.currentItem];
- 監(jiān)控時間進度
//監(jiān)控時間進度(根據(jù)API提示,如果要監(jiān)控時間進度,這個對象引用計數(shù)器要+1,retain)
__weak typeof(self) weakSelf = self;
self.timeObserver = [self.avPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
// 獲取 item 當前播放秒
float currentPlayTime = (double)weakSelf.avPlayer.currentItem.currentTime.value/ weakSelf.avPlayer.currentItem.currentTime.timescale;
[weakSelf updateVideoSlider:currentPlayTime];
}];
- 橫豎屏切換
// 添加通知
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(orientationHandler)
name:UIDeviceOrientationDidChangeNotification
object:nil
];
// 切換到大屏
- (void)fullScreenButtonClick {
[self forceChangeOrientation:UIInterfaceOrientationLandscapeRight];
self.controlView.fullScreenButton.hidden = YES;
self.controlView.shrinkScreenButton.hidden = NO;
self.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
}
// 切換到小屏
- (void)shrinkScreenButtonClick {
[self forceChangeOrientation:UIInterfaceOrientationPortrait];
self.controlView.fullScreenButton.hidden = NO;
self.controlView.shrinkScreenButton.hidden = YES;
self.frame = _shrinkRect;
}
/**
* 強制橫屏
*
* @param orientation 橫屏方向
*/
- (void)forceChangeOrientation:(UIInterfaceOrientation)orientation
{
int val = orientation;
if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
SEL selector = NSSelectorFromString(@"setOrientation:");
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
[invocation setSelector:selector];
[invocation setTarget:[UIDevice currentDevice]];
[invocation setArgument:&val atIndex:2];
[invocation invoke];
}
}
AVQueuePlayer
AVQueuePlayer集成于AVPlayer,主要實現(xiàn)添加多個AVPlayerItem,然后順序播放。
總結(jié)一下播放視頻的步驟
首先,得到視頻的URL
根據(jù)URL創(chuàng)建AVPlayerItem
把AVPlayerItem 提供給 AVPlayer
AVPlayerLayer 顯示視頻。
AVPlayer 控制視頻, 播放, 暫停, 跳轉(zhuǎn) 等等。
播放過程中獲取緩沖進度,獲取播放進度。
視頻播放完成后做些什么,是暫停還是循環(huán)播放,還是獲取最后一幀圖像。
后續(xù)繼續(xù)更新一些小問題,進度條、彈出動畫等等
??附上demo,如果幫到你了請給個小星星??
GitHub