今天我們拿 AVFoundation 的冰山一角來闡述一下我個人的喜好!相信每個人都會用 iPhone、iPad 來觀看“視頻”,優酷、愛奇藝、搜狐?嗯!還有 Youtube。
原文點擊這里:http://www.zengxianhua.com/2016/02/19/avfoundationde-le-qu/
現在的產品體驗已經足以讓我們玩的爽,也可以玩的 High!
于是我開始研究他們的細節,果然不錯,在體驗和兼容性上確實有一定的難度。
不想用 MPMoviePlayerController 的同學,都會想到 AVFoundation 去自定義,其實重載 MPMoviePlayerController 也可以 自定義UI,但我還是喜歡自己琢磨。
我想用自己寫的播放器來看視頻,可以嗎?當然我就這么干了!
先理解幾個名稱的基本概念。
AVPLayer
我理解的官方解釋:你可以使用 AVPlayer 對象實現控制和自定義UI的單個或多個播放。
這意味著你項目如果有多個播放的需求,這不就幫你解決了嗎?
AVPlayer支持本地與遠程的多媒體文件,正好,我本意就是可以緩存到本地看,也可以在線看。
我們需要怎樣呈現可視內容呢?
AVPlayerLayer
我理解的官方解釋:APLayerLayer 是 CALayer 的子類,AVPLayer可以通過它指導視頻輸出和可視化。
那音頻需要嗎?沒有可視化內容,使用 AVPlayer 就可以播放啦!
AVAsset
我理解的官方解釋:AVAsset是定時的視聽媒體,它可以是視頻、影片、歌曲、播客節目;可以是本地或者遠程的;也可以是限定或者非限定的流;
AVPlayerItem
我理解的官方解釋:協調AVPlayer和AVAsset,同樣具有AVPlayerItemTrack對象,可以控制音量、播放速率等等。
基本實現流程
了解 AVPlayer、AVPlayerLayer、AVPlayerItem、AVAsset 基本概念之后,那如何定制自己的播放器呢?
-
第一步首先需要一個展示的容器,繼承 UIView,隨你喜歡取個類名唄!( VideoLayerView )做以下操作:
.h @property (nonatomic, strong) AVPlayer *player; @property (nonatomic, readonly) AVPlayerLayer *playerLayer; @property (nonatomic, copy) NSString *videoFillMode; .m + (Class)layerClass { return [AVPlayerLayer class]; } - (void)commit { self.playerLayer.backgroundColor = [[UIColor blackColor] CGColor]; self.videoFillMode = AVLayerVideoGravityResizeAspect; } - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self commit]; } return self; } - (void)awakeFromNib { [self commit]; } - (void)setPlayer:(AVPlayer *)player { [(AVPlayerLayer *)[self layer] setPlayer:player]; } - (AVPlayer *)player { return [(AVPlayerLayer *)[self layer] player]; } - (AVPlayerLayer *)playerLayer { return (AVPlayerLayer *)self.layer; } - (void)setVideoFillMode:(NSString *)videoFillMode { [self playerLayer].videoGravity = videoFillMode; } - (NSString *)videoFillMode { return [self playerLayer].videoGravity; }
第二步創建 AVAsset 進行加載多媒體文件
你的是遠程地址?我的是本地路徑?OMG,這些都不是問題
NSURL *mediaURL = [NSURL URLWithString:mediaPath];
if (!mediaURL || ![mediaURL scheme]) {
mediaURL = [NSURL fileURLWithPath:mediaPath];
}
AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:mediaURL options:nil];
AVURLAsset 是 AVAsset的子類
-
第三步通過 AVAsset 的 loadValuesAsynchronouslyForKeys: completionHandler: 方法得到 AVPlayerItem,我們暫時只需要playable、 duration 這兩個key,這里是異步加載數據,你需要判斷加載的狀態。整理如下:
NSArray *keys = @[@“playable", @“duration"]; __weak typeof(self.mediaAsset) weakAsset = urlAsset; [urlAsset loadValuesAsynchronouslyForKeys:keys completionHandler:^{ dispatch_async(dispatch_get_main_queue(), ^{ // check the keys for (NSString *key in keys) { NSError *error = nil; AVKeyValueStatus keyStatus = [weakAsset statusOfValueForKey:key error:&error]; if (keyStatus == AVKeyValueStatusFailed) { NSLog(@"error (%@)", [[error userInfo] objectForKey:AVPlayerItemFailedToPlayToEndTimeErrorKey]); return; } } // check playable if (!weakAsset.playable) { return; } // get AVPlayerItem AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:weakAsset]; }); }];
-
第四步通過異步得到的 AVPlayerItem 進行創建AVPlayer
AVPlayer *player = [AVPLayer playerWithPlayerItem:playerItem]; VideoLayerView *layerView = [[VideoLayerView alloc] initWithFrame:frame]; layerView.player = player; [player play];
這樣就初步完成播放本地、遠程多媒體的播放器了,如果想趕上大公司的產品體驗,還需好好打磨一下。
期待下一回的優化唄!
下一期:打造一個上百Star的開源庫