1. 程式人生 > >iOS SDK詳解之視訊播放(AVPlayer)附Demo

iOS SDK詳解之視訊播放(AVPlayer)附Demo

前言
最近在研究視訊播放,所以研究了下這個類,學習的過程中寫了個簡單的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)));
    }];