IOS 無限循環小視頻播放
無限循環播放我們的小視頻,我們有三中選擇:
1.MPMoviePlayerController
2.AVPlayer
3.AVAssetReader+AVAssetReaderTrackOutput
但是我們這個預覽層是自定義的喔,所以MPMoviePlayerController只能馬上給篩選掉了,所以用,那麼我們就要用到 AVPlayer 了,雖然上 AVPlayer 最多隻能創建16個,性能上不及用 AVAssetReader+AVAssetReaderTrackOutput 方法好,但是對於這麼個視頻小播放也是足夠的了。(PS:接下來博主會寫一篇關於如何用AVAssetReader+AVAssetReaderTrackOutput來實現播放視頻)
AVPlayer
AVPlayer本身並不能顯示視頻,而且它也不像MPMoviePlayerController有一個view屬性。如果AVPlayer要顯示必須創建一個播放器層AVPlayerLayer用於展示,播放器層繼承於CALayer,
有了AVPlayerLayer之添加到控制器視圖的layer中即可。要使用AVPlayer首先了解一下幾個常用的類:
AVAsset:主要用於獲取多媒體信息,是一個抽象類,不能直接使用。
AVURLAsset:AVAsset的子類,可以根據一個URL路徑創建一個包含媒體信息的AVURLAsset對象。
AVPlayerItem:一個媒體資源管理對象,管理者視頻的一些基本信息和狀態,一個AVPlayerItem對應着一個視頻資源。
我們先來熟悉一下 AVPlayer 的這些類
那麼運用AVPlayer播放視頻的步驟如下:
1.創建 AVPlayerItem ,用來實例化AVPlayer並監控視頻的狀態
- (AVPlayer *)player
{
if (!_player ) {
AVPlayerItem *playerItem = [self getPlayItem];
_player = [[AVPlayer alloc]initWithPlayerItem:playerItem];
// 可以利用 AVPlayerItem 對這個視頻的狀態進行監控
}
return _player;
}
- (AVPlayerItem *)getPlayItem
{
NSString *cachePath=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *savePath=[cachePath stringByAppendingPathComponent:MOVIEPATH];
NSURL *saveUrl=[NSURL fileURLWithPath:savePath];
// 通過文件 URL 來實例化 AVPlayerItem
AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithURL:saveUrl];
return playerItem;
}
2.通過AVPlayer 創建預覽層(AVPlayerLayer)並添加到可視的圖層上播放
AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
playerLayer.frame = _viewContrain.bounds;
playerLayer.videoGravity=AVLayerVideoGravityResizeAspectFill;//視頻填充模式
[_viewContrain.layer addSublayer:playerLayer];
[self.player play];
3.通過 KVO 來監聽視頻的屬性,查看是否播放完成,播放長度爲多小,緩衝了多少等等
/** * 給播放器添加進度更新 */
-(void)addProgressObserver{
AVPlayerItem *playerItem=self.player.currentItem;
UIProgressView *progress=self.progress; //這裏設置每秒執行一次
[self.player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
float current=CMTimeGetSeconds(time);
float total=CMTimeGetSeconds([playerItem duration]);
NSLog(@"當前已經播放%.2fs.",current);
if (current) {
[progress setProgress:(current/total) animated:YES];
}
}];
}
#pragma mark - KVO
/** * 給AVPlayerItem添加監控 *
* @param playerItem AVPlayerItem對象 */
-(void)addObserverToPlayerItem:(AVPlayerItem *)playerItem{
//監控狀態屬性,注意AVPlayer也有一個status屬性,通過監控它的status也可以獲得播放狀態
[playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
//監控網絡加載情況屬性
[playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
}
-(void)removeObserverFromPlayerItem:(AVPlayerItem *)playerItem{
[playerItem removeObserver:self forKeyPath:@"status"];
[playerItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
}
/** * 通過KVO監控播放器狀態 *
* @param keyPath 監控屬性
* @param object 監視器
* @param change 狀態改變
* @param context 上下文 */
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
AVPlayerItem *playerItem=object;
if ([keyPath isEqualToString:@"status"]) {
AVPlayerStatus status= [[change objectForKey:@"new"] intValue];
if(status==AVPlayerStatusReadyToPlay){
NSLog(@"正在播放...,視頻總長度:%.2f",CMTimeGetSeconds(playerItem.duration));
}
}
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(@"共緩衝:%.2f",totalBuffer);
}
}
到此,我們就把 AVPlayer 視頻播放的方法創建完畢了。
那麼我們在視頻錄製完成的時候調用播放視頻的方法了
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error
{
NSLog(@"---- 錄製結束 ----");
}
- (void)completeHandle
{
// 完成後不斷播放
[_captureVideoPreviewLayer removeFromSuperlayer];
// 播放視頻
// 1.創建播放層
// 這裏爲什麼要調用延遲1.0秒呢,我們說過用 AVCaptureMovieFileOutput 來錄製視頻,是邊錄邊寫的,即使是錄製完成了,真實的是視頻還在寫,大概時間是延遲1.2秒左右。
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 在此方法調用創建 AVPlayer 播放視頻的第二部
2.通過AVPlayer 創建預覽層(AVPlayerLayer)並添加到可視的圖層上播放
[self addNotification];
});
}
添加視頻播放完後的監控來循環播放視頻
/**
* 添加播放器通知
*/
-(void)addNotification{
//給AVPlayerItem添加播放完成通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem];
}
-(void)removeNotification{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
/**
* 播放完成通知
*
* @param notification 通知對象
*/
-(void)playbackFinished:(NSNotification *)notification{
NSLog(@"視頻播放完成.");
// 播放完成後重複播放
// 跳到最新的時間點開始播放
[_player seekToTime:CMTimeMake(0, 1)];
[_player play];
}