iOS - AVPlayer 音視頻播放


前言

	NS_CLASS_AVAILABLE(10_7, 4_0) @interface AVPlayer : NSObject 
	@available(iOS 4.0, *)		   public class AVPlayer : NSObject
	
	NS_CLASS_AVAILABLE_IOS(8_0) @interface AVPlayerViewController : UIViewController
	@available(iOS 8.0, *)		 public class AVPlayerViewController : UIViewController 
  • AVPlayer 既可以播放音樂又可以播放視頻;使用 AVPlayer 不能直接顯示視頻,必須要加入 AVPlayerLayer 中,並添加到其他能顯示的 layer 中,AVPlayer 播放界面中不帶播放控件。

    • MediaPlayer 的影片是放在 UIView 里面,而 AVPlayer 是放在 AVPlayerLayer 里面,AVPlayerLayer 是 CALayer 的子類別。
    • 使用 MediaPlayer 前,要記得加入 MediaPlayer.framework 及 #import <MediaPlayer/MediaPlayer.h>
    • 使用 AVPlayer 前,要記得加入 AVFoundation.framework 及 #import <AVFoundation/AVFoundation.h>
  • MeidaPlayer 框架中的 MPMoviePlayerController 類和 MPMoviePlayerViewController 類是 iOS 中視頻播放的開發相關類和方法。在 iOS8 中,iOS 開發框架中引入了一個新的視頻框架 AVKit,其中提供了視頻開發類 AVPlayerViewController 用於在應用中嵌入播放視頻的控件。AVPlayerViewcontroller 繼承自 UIViewController,一般適用於點擊一個視頻縮略圖,modal 出一個新的界面來進行播 放的情況,AVPlayerViewcontroller 既可以播放音樂又可以播放視頻,播放界面中自帶播放控件。在 iOS8 中,這兩個框架中的視頻播放功能並無太大差異,基本都可以滿足開發者的需求。iOS9 系統后,iPad Air 正式開始支持多任務與畫中畫的分屏功能,所謂畫中畫,即是用戶可以將當前播放的視頻縮小放在屏幕上同時進行其他應用程序的使用。這個革命性的功能將極大的方便用戶的使用。於此同時,在 iOS9 中,MPMoviePlayerController 與 MPMoviePlayerViewController 類也被完全棄用,開發者使用 AVPlayerViewController 可以十分方便的實現視頻播放的功能並在一些型號的 iPad 上集成畫中畫的功能。

  • 實現畫中畫要實現以下三步:

    • 1、確保當前調試版本在 9.0 以上。

    • 2、在項目 TARGETS 中的 Capabilities -> Gapabilities -> Background Mode(選項開關打開)-> 勾選 Audio, AirPlay and Picture in Picture

    • 3、設置 AVAudioSession,這兩行必須設置,不然畫中畫不能用,如果不寫模擬器中可以畫中畫,但是在 iPad 設備中不能。

          AVAudioSession *audioSession = [AVAudioSession sharedInstance];
          [audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
      
  • 播放設置:

    • 使用 AVPlayer 播放:

      	添加庫文件:AVFoundation.framework
      	包含頭文件:#import <AVFoundation/AVFoundation.h>
      
    • 使用 AVPlayerViewController 播放:

      	添加庫文件:AVKit.framework
      			   AVFoundation.framework
      
      	包含頭文件:#import <AVKit/AVKit.h>
      			   #import <AVFoundation/AVFoundation.h>
      

1、本地/網絡音視頻播放

1.1 使用 AVPlayer 播放

  • Objective-C

    	添加庫文件:AVFoundation.framework
    	包含頭文件:#import <AVFoundation/AVFoundation.h>
    
    • 直接由 URL 創建

      	// 加載本地音樂
      	NSURL *movieUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"藍蓮花" ofType:@"mp3"]];
      	
      	// 加載本地視頻
      	NSURL *movieUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"步步高手機" ofType:@"mp4"]];
      	
      	// 加載網絡視頻
      	NSURL *movieUrl = [NSURL URLWithString:@"http://w2.dwstatic.com/1/5/1525/127352-100-1434554639.mp4"];
         
       	// 創建 AVPlayer 播放器
      	AVPlayer *player = [AVPlayer playerWithURL:movieUrl];
       
       	// 將 AVPlayer 添加到 AVPlayerLayer 上
      	AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];
      
       	// 設置播放頁面大小
       	playerLayer.frame = CGRectMake(10, 30, self.view.bounds.size.width - 20, 200);
       	
       	// 設置畫面縮放模式
       	playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
          
       	// 在視圖上添加播放器
       	[self.view.layer addSublayer:playerLayer];
        
       	// 開始播放
       	[player play];
      
    • 由 AVPlayerItem 創建

      	// 加載本地音樂
       	NSURL *movieUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"藍蓮花" ofType:@"mp3"]];
       	
       	// 加載本地視頻
       	NSURL *movieUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"步步高手機" ofType:@"mp4"]];
       	
       	// 加載網絡視頻
       	NSURL *movieUrl = [NSURL URLWithString:@"http://w2.dwstatic.com/1/5/1525/127352-100-1434554639.mp4"];
      
       	AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:movieUrl];
      
      	// 創建 AVPlayer 播放器
       	AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];
      
      	// 將 AVPlayer 添加到 AVPlayerLayer 上
       	AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];
      
      	// 設置播放頁面大小
       	playerLayer.frame = CGRectMake(10, 30, self.view.bounds.size.width - 20, 200);
       	
       	// 設置畫面縮放模式
       	playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
      
      	// 在視圖上添加播放器
       	[self.view.layer addSublayer:playerLayer];
      
      	// 開始播放
       	[player play];
      
  • Swift

    	添加庫文件:AVFoundation.framework
    	包含頭文件:import AVFoundation
    
    • 直接由 URL 創建

      	// 加載本地音樂
      	let movieUrl:NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("藍蓮花", ofType: "mp3")!)
      
      	// 加載本地視頻
      	let movieUrl:NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("步步高手機", ofType: "mp4")!)
      
      	// 加載網絡視頻
      	let movieUrl:NSURL = NSURL(string: "http://w2.dwstatic.com/1/5/1525/127352-100-1434554639.mp4")!
      
      	// 創建 AVPlayer 播放器
      	let player:AVPlayer = AVPlayer(URL: movieUrl)
      
      	// 將 AVPlayer 添加到 AVPlayerLayer 上
      	let playerLayer:AVPlayerLayer = AVPlayerLayer(player: player)
      
      	// 設置播放頁面大小
      	playerLayer.frame = CGRectMake(10, 30, self.view.bounds.size.width - 20, 200)
      
      	// 設置畫面縮放模式                                      
      	playerLayer.videoGravity = AVLayerVideoGravityResizeAspect
      
      	// 在視圖上添加播放器
      	self.view.layer.addSublayer(playerLayer)
      
      	// 開始播放
      	player.play()
      
    • 由 AVPlayerItem 創建

      	// 加載本地音樂
      	let movieUrl:NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("藍蓮花", ofType: "mp3")!)
      
      	// 加載本地視頻
      	let movieUrl:NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("步步高手機", ofType: "mp4")!)
      
      	// 加載網絡視頻
      	let movieUrl:NSURL = NSURL(string: "http://w2.dwstatic.com/1/5/1525/127352-100-1434554639.mp4")!
      
      	let playerItem:AVPlayerItem = AVPlayerItem(URL: movieUrl)
      	            
      	// 創建 AVPlayer 播放器
      	let player:AVPlayer = AVPlayer(playerItem: playerItem)
      
      	// 將 AVPlayer 添加到 AVPlayerLayer 上
      	let playerLayer:AVPlayerLayer = AVPlayerLayer(player: player)
      
      	// 設置播放頁面大小
      	playerLayer.frame = CGRectMake(10, 30, self.view.bounds.size.width - 20, 200)
      	            
      	// 設置畫面縮放模式                                     
      	playerLayer.videoGravity = AVLayerVideoGravityResizeAspect
      
      	// 在視圖上添加播放器
      	self.view.layer.addSublayer(playerLayer)
      
      	// 開始播放
      	player.play()
      

1.2 使用 AVPlayerViewController 播放

  • Objective-C

    	添加庫文件:AVKit.framework
    		  	   AVFoundation.framework
    
    	包含頭文件:#import <AVKit/AVKit.h>
    		  	   #import <AVFoundation/AVFoundation.h>
    
    • 彈出顯示頁面直接開始播放

      	// 加載本地音樂
      	NSURL *movieUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"藍蓮花" ofType:@"mp3"]];
      
      	// 加載本地視頻
      	NSURL *movieUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"步步高手機" ofType:@"mp4"]];
      
      	// 加載網絡視頻     	
      	NSURL *movieUrl = [NSURL URLWithString:@"http://w2.dwstatic.com/1/5/1525/127352-100-1434554639.mp4"];
      
      	// 創建播放控制器
      	AVPlayerViewController *playerViewController = [[AVPlayerViewController alloc] init];
      
      	playerViewController.player = [AVPlayer playerWithURL:movieUrl];
      
      	// 彈出播放頁面
      	[self presentViewController:playerViewController animated:YES completion:^{
      
      		// 開始播放
      		[playerViewController.player play];
      	}];
      
    • 手動播放

      	// 加載本地視頻	
      	NSURL *movieUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"步步高手機" ofType:@"mp4"]];  
      	
      	// 創建播放控制器  	
      	AVPlayerViewController *playerViewController = [[AVPlayerViewController alloc] init];                              	
      	playerViewController.player = [AVPlayer playerWithURL:movieUrl];
      
      	// 彈出播放頁面,需要點擊播放按鈕開始播放
      	[self presentViewController:playerViewController animated:YES completion:nil];
      
  • Swift

    	添加庫文件:AVKit.framework
    		       import AVFoundation
    
    
    	包含頭文件:import AVKit
    		       AVFoundation.framework
    
    • 彈出顯示頁面直接開始播放

      	// 加載本地音樂
      	let movieUrl:NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("藍蓮花", ofType: "mp3")!)
      	
      	// 加載本地視頻 
      	let movieUrl:NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("步步高手機", ofType: "mp4")!)
      	
      	// 加載網絡視頻	
      	let movieUrl:NSURL = NSURL(string: "http://w2.dwstatic.com/1/5/1525/127352-100-1434554639.mp4")!
      
      	// 創建播放控制器
      	let playerViewController:AVPlayerViewController = AVPlayerViewController()
      
      	playerViewController.player = AVPlayer(URL: movieUrl)
      
      	// 彈出播放頁面
      	self.presentViewController(playerViewController, animated: true) {
      
      		// 開始播放
          	playerViewController.player?.play()
      	}
      
    • 手動播放

      	// 加載本地視頻
      	let movieUrl:NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("步步高手機", ofType: "mp4")!)
      	
      	// 創建播放控制器	
      	let playerViewController:AVPlayerViewController = AVPlayerViewController()
      
      	playerViewController.player = AVPlayer(URL: movieUrl)
      
      	// 彈出播放頁面,需要點擊播放按鈕開始播放
      	self.presentViewController(playerViewController, animated: true, completion:nil)
      

2、本地/網絡音視頻播放設置

2.1 使用 AVPlayer 播放

  • Objective-C

    	// 在視圖上添加播放器
    	/*
    		必須添加到 layer 上
    	*/
    	avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:avPlayer];
    	[self.view.layer addSublayer:avPlayerLayer];
    
    	// 設置播放頁面大小
    	avPlayerLayer.frame = CGRectMake(10, 30, self.view.bounds.size.width - 20, 200);
    
    	// 設置畫面縮放模式
    	/*
    		AVLayerVideoGravityResizeAspect       適應屏幕大小,保持寬高比,默認
    		AVLayerVideoGravityResizeAspectFill   充滿屏幕,保持寬高比
    		AVLayerVideoGravityResize             充滿屏幕,不保持寬高比
    	*/
    	avPlayerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
                
    	// 獲取顯示在接收視圖范圍內的視頻圖像的位置和大小
    	CGRect videoRect = avPlayerLayer.videoRect;
      	
    	// 判斷是否准備好顯示
    	BOOL readyForDisplay = avPlayerLayer.isReadyForDisplay;
       	
    	// 獲取視頻准備播放狀態
    	/*
    		AVPlayerItemStatusUnknown,      狀態未知
    		AVPlayerItemStatusReadyToPlay,  准備好播放
    		AVPlayerItemStatusFailed        准備失敗
    	*/
    	AVPlayerItemStatus status = avPlayerItem.status;
     	
    	// 監聽准備播放狀態屬性
    	[avPlayerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
    
    	// 系統自帶監聽方法
    	- (void)observeValueForKeyPath:(NSString *)keyPath 
    	                      ofObject:(id)object 
    	                        change:(NSDictionary<NSString *,id> *)change 
    	                       context:(void *)context {   
    
    		if ([keyPath isEqualToString:@"status"]) {
    
    		}
    	}
    
    	// 獲取視頻緩沖進度
    	NSArray<NSValue *> *loadedTimeRanges = avPlayerItem.loadedTimeRanges;
      
    	CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];  // 獲取緩沖區域                
    	float startSeconds = CMTimeGetSeconds(timeRange.start);
    	float durationSeconds = CMTimeGetSeconds(timeRange.duration);
        
    	float loadedSecond = startSeconds + durationSeconds;                      // 計算緩沖總進度
        
    	// 監聽緩沖進度屬性
    	[avPlayerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
      
    	// 系統自帶監聽方法
    	- (void)observeValueForKeyPath:(NSString *)keyPath 
    	                      ofObject:(id)object 
    	                        change:(NSDictionary<NSString *,id> *)change 
    	                       context:(void *)context {   
    
    		if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
    
    		}
    	}
    
    	// 獲取當前播放進度
    	/*
    		或用 avPlayerItem.currentTime.value/avPlayerItem.currentTime.timescale;
    	*/
    	CMTime currentTime = avPlayerItem.currentTime;
    	float currentSecond = CMTimeGetSeconds(currentTime);
        
    	// 監聽播放進度
    	/*
    		NULL 在主線程中執行,每個一秒執行一次該 Block
    	*/
    	[avPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:NULL usingBlock:^(CMTime time) {
    
    	}];
    
    	// 添加播放完成通知
    	[[NSNotificationCenter defaultCenter] addObserver:self 
    	                                         selector:@selector(playDidEnd:) 
    	                                             name:AVPlayerItemDidPlayToEndTimeNotification 
    	                                           object:avPlayerItem];
    
    	// 獲取視頻總長度
    	/*
    		轉換成秒,或用 duration.value / duration.timescale; 計算
    	*/
    	CMTime duration = avPlayerItem.duration;
    	float totalSecond = CMTimeGetSeconds(duration);
    
    	// 跳轉到指定位置
    	/*
    		10 / 1 = 10,跳轉到第 10 秒的位置處  
    	*/
    	[avPlayerItem seekToTime:CMTimeMake(10, 1)];    
    
    	// 設置播放速率
    	/*
    		默認為 1.0 (normal speed),設為 0.0 時暫停播放。設置后立即開始播放,可放在開始播放后設置
    	*/
    	avPlayer.rate = 1.0;
    
    	// 獲取當前播放速率
    	float rate = avPlayer.rate;
       	
    	// 開始播放
    	[avPlayer play];
    	
    	// 暫停播放
    	[avPlayer pause];
    
    	// 設置音量
    	/*
    		范圍 0 - 1,默認為 1
    	*/
    	avPlayer.volume = 0;
    
  • Swift

    	// 在視圖上添加播放器
    	/*
    		必須添加到 layer 上
    	*/
    	avPlayerLayer = AVPlayerLayer(player: avPlayer)
    	self.view.layer.addSublayer(avPlayerLayer)
    
    	// 設置播放頁面大小
    	avPlayerLayer.frame = CGRectMake(10, 30, self.view.bounds.size.width - 20, 200)
    
    	// 設置畫面縮放模式
    	/*
    		AVLayerVideoGravityResizeAspect       適應屏幕大小,保持寬高比,默認
    		AVLayerVideoGravityResizeAspectFill   充滿屏幕,保持寬高比
    		AVLayerVideoGravityResize             充滿屏幕,不保持寬高比
    	*/
    	avPlayerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
    
    	// 獲取顯示在接收視圖范圍內的視頻圖像的位置和大小
    	let videoRect:CGRect = avPlayerLayer.videoRect
          	
    	// 判斷是否准備好顯示
    	let readyForDisplay:Bool = avPlayerLayer.readyForDisplay
          	
    	// 獲取視頻准備播放狀態
    	/*
    		case Unknown       狀態未知
    		case ReadyToPlay   准備好播放
    		case Failed        准備失敗
    	*/
    	let status:AVPlayerItemStatus = avPlayerItem.status
       	
    	// 監聽准備播放狀態屬性
    	avPlayerItem.addObserver(self, forKeyPath: "status", options: .New, context: nil)
    
    	// 系統自帶監聽方法
    	override func observeValueForKeyPath(keyPath: String?, 
    	                             ofObject object: AnyObject?, 
    	                                      change: [String : AnyObject]?, 
    	                                     context: UnsafeMutablePointer<Void>) {
    
    		if keyPath == "status" {
    
    		}
    	}
    
    	// 獲取視頻緩沖進度
    	let loadedTimeRanges:[NSValue] = avPlayerItem.loadedTimeRanges
    
    	let timeRange:CMTimeRange = loadedTimeRanges.first!.CMTimeRangeValue  // 獲取緩沖區域
    	let startSeconds = CMTimeGetSeconds(timeRange.start)
    	let durationSeconds = CMTimeGetSeconds(timeRange.duration)
    
    	let loadedSecond:Double = startSeconds + durationSeconds              // 計算緩沖總進度
    
    	// 監聽緩沖進度屬性	
    	avPlayerItem.addObserver(self, forKeyPath: "loadedTimeRanges", options: .New, context: nil)
    
    	// 系統自帶監聽方法
    	override func observeValueForKeyPath(keyPath: String?, 
    	                             ofObject object: AnyObject?, 
    	                                      change: [String : AnyObject]?, 
    	                                     context: UnsafeMutablePointer<Void>) {
    
    		if keyPath == "loadedTimeRanges" {
    
    		}
    	}
    
    	// 獲取當前播放進度
    	/*
    		或用 avPlayerItem.currentTime.value/avPlayerItem.currentTime.timescale;
    	*/
    	let currentTime:CMTime = self.avPlayerItem.currentTime()
    	let currentSecond = CMTimeGetSeconds(currentTime)
    
    	// 監聽播放進度	
    	/*
    		nil 在主線程中執行,每個一秒執行一次該 Block
    	*/	
    	avPlayer.addPeriodicTimeObserverForInterval(CMTimeMake(1, 1), queue: nil) { (time:CMTime) in
    
    	}
    
    	// 添加播放完成通知
    	NSNotificationCenter.defaultCenter().addObserver(self, 
    	                                        selector: #selector(AvPlayer.playDidEnd(_:)), 
    	                                            name: AVPlayerItemDidPlayToEndTimeNotification, 
    	                                          object: avPlayerItem)
    
    	// 獲取視頻總長度
    	/*
    		轉換成秒,或用 duration.value / duration.timescale; 計算
    	*/
    	let duration:CMTime = avPlayerItem.duration
    	let totalSecond:Double = CMTimeGetSeconds(duration)
    
    	// 跳轉到指定位置
    	/*
    		10 / 1 = 10,跳轉到第 10 秒的位置處 
    	*/
    	avPlayerItem.seekToTime(CMTimeMake(10, 1))
    
    	// 設置播放速率
    	/*
    		默認為 1.0 (normal speed),設為 0.0 時暫停播放。設置后立即開始播放,可放在開始播放后設置
    	*/
    	avPlayer.rate = 1.0
        
    	// 獲取當前播放速率
    	let rate:Float = avPlayer.rate
    
    	// 開始播放
    	avPlayer.play()
        
    	// 暫停播放
    	avPlayer.pause()
        
    	// 設置音量
    	/*
    		范圍 0 - 1,默認為 1
    	*/
    	avPlayer.volume = 0
    

2.2 使用 AVPlayerViewController 播放

  • Objective-C

    	// 顯示播放頁面
    	[self presentViewController:avPlayerVC animated:YES completion:nil];
    
    	// 設置畫面縮放模式
    	/*
    		AVLayerVideoGravityResizeAspect       適應屏幕大小,保持寬高比,默認
    		AVLayerVideoGravityResizeAspectFill   充滿屏幕,保持寬高比
    		AVLayerVideoGravityResize             充滿屏幕,不保持寬高比
    	*/
    	avPlayerVC.videoGravity = AVLayerVideoGravityResizeAspect;
    
    	// 獲取顯示在接收視圖范圍內的視頻圖像的位置和大小
    	CGRect videoBounds = avPlayerVC.videoBounds;
    	
    	// 獲取播放控件所在的視圖
    	/*
    		播放控件與播放內容界面之間的疊加視圖
    	*/
    	UIView *contentOverlayView = avPlayerVC.contentOverlayView;
    
    	// 設置是否顯示播放控件
    	/*
    		Default is YES
    	*/
    	avPlayerVC.showsPlaybackControls = YES;
    
    	// 設置是否允許畫中畫播放
    	/*
    		Default is YES
    	*/
    	avPlayerVC.allowsPictureInPicturePlayback = YES;
    
    	// 判斷是否准備好顯示
    	BOOL readyForDisplay = avPlayerVC.isReadyForDisplay;
    
    	// 設置畫中畫播放代理,需遵守協議 <AVPlayerViewControllerDelegate>
    	avPlayerVC.delegate = self;
    
    	// 實現畫中畫播放
    	/*
    		這兩行必須設置,不然畫中畫不能用,如果不寫模擬器中可以畫中畫,但是在設備中不能
    	*/
    	AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    	[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
    
    	// 獲取視頻准備播放狀態
    	/*
    		AVPlayerItemStatusUnknown,      狀態未知
    		AVPlayerItemStatusReadyToPlay,  准備好播放
    		AVPlayerItemStatusFailed        准備失敗
    	*/
    	AVPlayerItemStatus status = avPlayerVC.player.currentItem.status;
      	  	
    	// 監聽准備播放狀態屬性
    	[avPlayerVC.player.currentItem addObserver:self 
    	                                forKeyPath:@"status" 
    	                                   options:NSKeyValueObservingOptionNew 
    	                                   context:nil];
    
    	// 系統自帶監聽方法
    	- (void)observeValueForKeyPath:(NSString *)keyPath 
    	                      ofObject:(id)object 
    	                        change:(NSDictionary<NSString *,id> *)change 
    	                       context:(void *)context {   
    
    		if ([keyPath isEqualToString:@"status"]) {
    
    		}
    	}
    
    	// 獲取視頻緩沖進度
    	NSArray<NSValue *> *loadedTimeRanges = avPlayerVC.player.currentItem.loadedTimeRanges;
        
    	CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];  // 獲取緩沖區域
    	float startSeconds = CMTimeGetSeconds(timeRange.start);
    	float durationSeconds = CMTimeGetSeconds(timeRange.duration);
        
    	float loadedSecond = startSeconds + durationSeconds;                      // 計算緩沖總進度
        
    	// 監聽緩沖進度屬性	
    	[avPlayerVC.player.currentItem addObserver:self 
    	                                forKeyPath:@"loadedTimeRanges" 
    	                                   options:NSKeyValueObservingOptionNew 
    	                                   context:nil];
    
    	// 系統自帶監聽方法
    	- (void)observeValueForKeyPath:(NSString *)keyPath 
    	                      ofObject:(id)object 
    	                        change:(NSDictionary<NSString *,id> *)change 
    	                       context:(void *)context {   
    
    		if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
    
    		}
    	}
    
    	// 獲取當前播放進度
    	/*
    		或用 avPlayerItem.currentTime.value/avPlayerItem.currentTime.timescale;
    	*/
    	CMTime currentTime = avPlayerVC.player.currentItem.currentTime;
    	float currentSecond = CMTimeGetSeconds(currentTime);
        	
    	// 監聽播放進度
    	/*
    		NULL 在主線程中執行,每個一秒執行一次該 Block
    	*/
    	[avPlayerVC.player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:NULL usingBlock:^(CMTime time) {
    
    	}];
    
    	// 添加播放完成通知
    	[[NSNotificationCenter defaultCenter] addObserver:self 
    	                                         selector:@selector(playDidEnd:) 
    	                                             name:AVPlayerItemDidPlayToEndTimeNotification 
    	                                           object:avPlayerVC.player.currentItem];
    
    	// 獲取視頻總長度
    	/*
    		轉換成秒,或用 duration.value / duration.timescale; 計算
    	*/
    	CMTime duration = avPlayerVC.player.currentItem.duration;
    	float totalSecond = CMTimeGetSeconds(duration);
    
    	// 跳轉到指定位置
    	/*
    		10 / 1 = 10,跳轉到第 10 秒的位置處 
    	*/
    	[avPlayerVC.player.currentItem seekToTime:CMTimeMake(10, 1)];
    
    	// 設置播放速率
    	/*
    		默認為 1.0 (normal speed),設為 0.0 時暫停播放。設置后立即開始播放,可放在開始播放后設置
    	*/
    	avPlayerVC.player.rate = 1.0;
    
    	// 獲取當前播放速率
    	float rate = avPlayerVC.player.rate;
    
    	// 開始播放
    	[avPlayerVC.player play];
        
    	// 暫停播放
    	[avPlayerVC.player pause];
        
    	// 設置音量
    	/*
    		范圍 0 - 1,默認為 1
    	*/
    	avPlayerVC.player.volume = 0;
    
  • Swift

    	// 顯示播放頁面
    	self.presentViewController(avPlayerVC, animated: true, completion:nil)
    
    	// 設置畫面縮放模式
    	/*
    		AVLayerVideoGravityResizeAspect      適應屏幕大小,保持寬高比,默認
    		AVLayerVideoGravityResizeAspectFill  充滿屏幕,保持寬高比
    		AVLayerVideoGravityResize            充滿屏幕,不保持寬高比
    	*/
    	avPlayerVC.videoGravity = AVLayerVideoGravityResizeAspect
    
    	// 獲取顯示在接收視圖范圍內的視頻圖像的位置和大小
    	let videoBounds:CGRect = avPlayerVC.videoBounds
       	
    	// 獲取播放控件所在的視圖
    	/*
    		播放控件與播放內容界面之間的疊加視圖
    	*/
    	let contentOverlayView:UIView = avPlayerVC.contentOverlayView!
       	
    	// 設置是否顯示播放控件
    	/*
    		Default is YES
    	*/
    	avPlayerVC.showsPlaybackControls = true
    
    	// 設置是否允許畫中畫播放
    	/*
    		Default is YES
    	*/
    	avPlayerVC.allowsPictureInPicturePlayback = true
    
    	// 判斷是否准備好顯示
    	let readyForDisplay:Bool = avPlayerVC.readyForDisplay
       	
    	// 設置畫中畫播放代理,需遵守協議 <AVPlayerViewControllerDelegate>
    	avPlayerVC.delegate = self
    
    	// 實現畫中畫播放
    	/*
    		這兩行必須設置,不然畫中畫不能用,如果不寫模擬器中可以畫中畫,但是在設備中不能
    	*/
    	let audioSession:AVAudioSession = AVAudioSession.sharedInstance()
    	try! audioSession.setCategory(AVAudioSessionCategoryPlayback)
    
    	// 獲取視頻准備播放狀態
    	/*
    		AVPlayerItemStatusUnknown,      狀態未知
    		AVPlayerItemStatusReadyToPlay,  准備好播放
    		AVPlayerItemStatusFailed        准備失敗
    	*/
    	let status:AVPlayerItemStatus = avPlayerVC.player!.currentItem!.status
        	
    	// 監聽准備播放狀態屬性
    	avPlayerVC.player!.currentItem!.addObserver(self, forKeyPath: "status", options: .New, context: nil)
    
    	// 系統自帶監聽方法
    	override func observeValueForKeyPath(keyPath: String?, 
    	                             ofObject object: AnyObject?, 
    	                                      change: [String : AnyObject]?, 
    	                                     context: UnsafeMutablePointer<Void>) {
    
    		if keyPath == "status" {
    
    		}
    	}
    
    	// 獲取視頻緩沖進度
    	let loadedTimeRanges:[NSValue] = avPlayerVC.player!.currentItem!.loadedTimeRanges
        
    	let timeRange:CMTimeRange = loadedTimeRanges.first!.CMTimeRangeValue   // 獲取緩沖區域
    	let startSeconds = CMTimeGetSeconds(timeRange.start)
    	let durationSeconds = CMTimeGetSeconds(timeRange.duration)
        
    	let loadedSecond:Double = startSeconds + durationSeconds               // 計算緩沖總進度
        
    	// 監聽緩沖進度屬性	
    	avPlayerVC.player!.currentItem!.addObserver(self, forKeyPath: "loadedTimeRanges", options: .New, context: nil)
    
    	// 系統自帶監聽方法
    	override func observeValueForKeyPath(keyPath: String?, 
    	                             ofObject object: AnyObject?, 
    	                                      change: [String : AnyObject]?, 
    	                                     context: UnsafeMutablePointer<Void>) {
    
    		if keyPath == "loadedTimeRanges" {
    
    		}
    	}
    
    	// 獲取當前播放進度
    	let currentTime:CMTime = self.avPlayerVC.player!.currentItem!.currentTime()
    	let currentSecond = CMTimeGetSeconds(currentTime)
        
    	// 監聽播放進度
    	avPlayerVC.player?.addPeriodicTimeObserverForInterval(CMTimeMake(1, 1), queue: nil, usingBlock: { (time:CMTime) in
    	
    	})
    
    	// 添加播放完成通知
    	NSNotificationCenter.defaultCenter().addObserver(self, 
    	                                        selector: #selector(AvPlayer.playDidEnd(_:)), 
    	                                            name: AVPlayerItemDidPlayToEndTimeNotification, 
    	                                          object: avPlayerVC.player!.currentItem!)
    
    	// 獲取視頻總長度
    	/*
    		轉換成秒,或用 duration.value / duration.timescale; 計算
    	*/
    	let duration:CMTime = avPlayerVC.player!.currentItem!.duration
    	let totalSecond = CMTimeGetSeconds(duration)
    
    	// 跳轉到指定位置
    	/*
    		10 / 1 = 10,跳轉到第 10 秒的位置處 
    	*/
    	avPlayerVC.player!.currentItem!.seekToTime(CMTimeMake(10, 1))
    
    	// 設置播放速率
    	/*
    		默認為 1.0 (normal speed),設為 0.0 時暫停播放。設置后立即開始播放,可放在開始播放后設置
    	*/
    	avPlayerVC.player!.rate = 1.0
        
    	// 獲取當前播放速率
    	let rate = avPlayerVC.player!.rate
          	
    	// 開始播放
    	avPlayerVC.player!.play()
        
    	// 暫停播放
    	avPlayerVC.player!.pause()
    
    	// 設置音量
    	/*
    		范圍 0 - 1,默認為 1
    	*/
    	avPlayerVC.player!.volume = 0
    

3、AVPlayerViewControllerDelegate 畫中畫協議方法

  • Objective-C

    	// 將要開始畫中畫播放
    	- (void)playerViewControllerWillStartPictureInPicture:(AVPlayerViewController *)playerViewController {
        	
    	}
    
    	// 已經開始畫中畫播放
    	- (void)playerViewControllerDidStartPictureInPicture:(AVPlayerViewController *)playerViewController {
        	
    	}
    
    	// 畫中畫播放失敗
    	- (void)playerViewController:(AVPlayerViewController *)playerViewController failedToStartPictureInPictureWithError:(NSError *)error {
        	
    	}
    
    	// 將要結束畫中畫播放
    	- (void)playerViewControllerWillStopPictureInPicture:(AVPlayerViewController *)playerViewController {
        	
    	}
    
    	// 已經結束畫中畫播放
    	- (void)playerViewControllerDidStopPictureInPicture:(AVPlayerViewController *)playerViewController {
        	
    	}
    
    	// 畫中畫播放開始時播放控制器界面是否自動退出
    	- (BOOL)playerViewControllerShouldAutomaticallyDismissAtPictureInPictureStart:(AVPlayerViewController *)playerViewController {
        
        	// 是否在開始畫中畫時自動將當前的播放界面 dismiss 掉,返回 YES 則自動 dismiss,返回 NO 則不會自動 dismiss
    		return NO;
    	}
    
    	// 畫中畫停止之前恢復用戶界面
    	- (void)playerViewController:(AVPlayerViewController *)playerViewController restoreUserInterfaceForPictureInPictureStopWithCompletionHandler:(void (^)(BOOL 			restored))completionHandler {
    
    		// 用戶點擊還原按鈕,從畫中畫模式還原回 App 內嵌模式時調用的方法
    	}
    
  • Swift

    	// 將要開始畫中畫播放
    	func playerViewControllerWillStartPictureInPicture(playerViewController: AVPlayerViewController) {
    
    	}
    
    	// 已經開始畫中畫播放
    	func playerViewControllerDidStartPictureInPicture(playerViewController: AVPlayerViewController) {
    
    	}
    
    	// 畫中畫播放失敗
    	func playerViewController(playerViewController: AVPlayerViewController, failedToStartPictureInPictureWithError error: NSError) {
    
    	}
    
    	// 將要結束畫中畫播放
    	func playerViewControllerWillStopPictureInPicture(playerViewController: AVPlayerViewController) {
    
    	}
    
    	// 已經結束畫中畫播放
    	func playerViewControllerDidStopPictureInPicture(playerViewController: AVPlayerViewController) {
    
    	}
    
    	// 畫中畫播放開始時播放控制器界面是否自動退出
    	func playerViewControllerShouldAutomaticallyDismissAtPictureInPictureStart(playerViewController: AVPlayerViewController) -> Bool {
    
    		// 是否在開始畫中畫時自動將當前的播放界面 dismiss 掉,返回 YES 則自動 dismiss,返回 NO 則不會自動 dismiss
    		return false
    	}
    
    	// 畫中畫停止之前恢復用戶界面
    	func playerViewController(playerViewController: AVPlayerViewController, restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: (Bool) 		-> Void) {
    
    		// 用戶點擊還原按鈕,從畫中畫模式還原回 App 內嵌模式時調用的方法
    	}
    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM