iOS SDK詳解之視訊播放(AVPlayer)附Demo
阿新 • • 發佈:2019-02-09
前言
最近在研究視訊播放,所以研究了下這個類,學習的過程中寫了個簡單的Demo,這裡寫出來分析給想要的人呢。實現了
- 透明的導航欄
- 螢幕垂直的時候小螢幕/水平大螢幕之前的切換,支援螢幕旋轉觸發,按鍵觸發
- 重播
- 播放/暫停
- 顯示播放進度
- 隱藏控制圖示,導航欄
GIF
全屏->小螢幕
小螢幕到全屏
暫停,重播
幾個關鍵的類
- AVPlayer (負責視訊操作,例如播放,暫停,聲音大小,跳到指定時間)
- AVPlayerLayer(負責視訊的可視區域,視訊的播放模式,注意是CALayer,不能接受觸控)
- AVPlayerItem(表示AVPlayer播放的資源物件,可以監聽其狀態)
幾個關鍵點
- 如何實現全屏
嘗試過兩種方式,一種是利用transform來讓view旋轉,但是這樣有個缺陷是程式碼複雜,沒辦法響應裝置旋轉,另外調整音訊大小的時候,系統出來的圖示不對。本文采用另一種方式,利用AutoLayout,這樣程式碼簡潔而且動畫流暢。
利用XCode的Size Class,對iphone的橫屏豎屏分別設定不同的約束即可
- 如何實現AVPlayerLayer的AutoLayout
按照View的方式處理Layer,我之前講過的,感興趣的可以參考下我這篇部落格,
新建一個UIView的子類,用這個類來處理視訊播放
標頭檔案
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
@interface PlayVideoView : UIView
@property(nonatomic)AVPlayer * player;
@property(nonatomic,readonly)AVPlayerLayer * playerLayer;
@end
.m檔案
#import "PlayVideoView.h"
@implementation PlayVideoView
+(Class)layerClass{
return [AVPlayerLayer class];
}
- (AVPlayer*)player {
return [(AVPlayerLayer *)[self layer] player];
}
- (void)setPlayer:(AVPlayer *)player {
[(AVPlayerLayer *)[self layer] setPlayer:player];
}
- (AVPlayerLayer *)playerLayer{
return (AVPlayerLayer *)self.layer;
}
@end
- 實現透明的導航欄
[self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
[self.navigationController.navigationBar setShadowImage:[UIImage new]];
- 監聽視訊資源是否準備好
KVO
[player addObserver:self forKeyPath:@"status" options:0 context:0];
然後監聽,注意例子只有一個KVO,所以沒有進行判斷是哪一個KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if(self.playvideoView.player.status == AVPlayerStatusFailed){
}else if(self.playvideoView.player.status == AVPlayerStatusReadyToPlay){
self.playButton.hidden = false;
}
}
- 獲取播放視訊的進度
[player addPeriodicTimeObserverForInterval:CMTimeMake(1, 2) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
CMTime currentTime = self.playvideoView.player.currentTime;
CMTime totalTime = self.playvideoView.player.currentItem.duration;
CGFloat progress = CMTimeGetSeconds(currentTime)/CMTimeGetSeconds(totalTime);
NSLog(@"%.2f",progress);
self.progressView.progress = progress;
NSLog(@"%d",(int)(CMTimeGetSeconds(totalTime) - CMTimeGetSeconds(currentTime)));
}];