使用 AVPlayer 進行多視頻播放

使用 AVPlayer 進行多視頻播放

鏈接:http://ios.jobbole.com/84287/

從前……不。我在 nKey 從事一個為 Hyundai(現代) 進行的項目,當進入某個場景時,兩個視頻需要同時播放,以便用戶能夠看到當汽車是否存在某種特性(比如電子穩定控制系統)時會如何運作。作為一名經驗豐富的開發者,我立即告訴客戶我們應該合并兩個視頻,以便能在 iOS 上“同時播放”。我向他解釋了,為了在 iOS 上播放視頻,蘋果已經在很久之前發布了 MediaPlayer.framework,根據相關文檔(并且實際上 :P )在同一時間不能夠播放一個以上的視頻(盡管你可以有兩個 MPMoviePlayerController 實例)。

他說好的,然后我們就像之前那樣做了播放功能。但是,需求發生了改變,并且我們不得不添加一個在循環播放的背景視頻…… 結果我在如何協調多個視頻時遇到了問題,我要同時只播放一個視頻并且不引起用戶的注意。

幸運的是在這個星期一,nKey 把派我到在巴西圣保羅瓜魯柳斯機場舉行的 iOS Tech Talk,我加入了 Media Technologies Evangelist 討論中, Eryk Vershen 正在討論 AVFoundation.framework 以及 MediaPlayer.framework (又稱 MPMoviePlayerController )是如何用它來播放視頻的。在伴隨著紅酒和奶酪的交談后,我開始和 Eryk 講述我的問題并向他闡述準備如何解決這個問題。他的回答類似于“當然!大膽去干! iOS 肯定能在同一時間播放多個視的!……呃……大約 4 個是極限。”這個回答讓我很高興并感到好奇,所以我又問他,既然不受框架限制,為什么 MediaPlayer.framework 不能同時播放多個視頻……他告訴我 MPMoviePlayerController 之前是被用來在游戲中做場景切換的。。。這就是為什么之前的 iOS 版本只能全屏播放,該局限是個歷史遺留問題。

當我回到我的筆記本前,我用 AVFoundation.framework 寫了一個非常基礎的視頻播放版本。顯然,當我回到公司后,我需要寫一個更加詳細的版本才能用在項目中。

好了,故事講完了。讓我們回到工作中來!

AVFoundation 框架提供了 AVPlayer 對象來實現單視頻或多視頻播放的控制器和用戶接口。由 AVPlayer 對象生成的可視結果可以顯示在 AVPlayerLayer 類的 CoreAnimation 層上。 在 AVFoundation 中,AVAsset 對象用來表示定時影音媒體,比如視頻和音頻。根據相關文檔,每個資源包含一個用來一起呈現或處理的軌道集合,每個統一媒體類型,包括不僅限于音頻、視頻、文本、隱藏式字幕、字幕。因為定時影音媒體的性質,在成功初始化一個資源后,某些或全部鍵值可能不會立即可用。為了避免阻塞主線程,你可以在特定鍵注冊你感興趣的內容,以在可用時被通知到。

考慮到這一點,繼承 UIViewController 并命名為 VideoPlayerViewController。就像 MPMoviePlayerController ,讓我們添加一個 NSURL 屬性,用于告訴我們應該從哪里抓取視頻。就像上面描述的那樣,添加下面的代碼,一旦 URL 被賦值 AVAsset 就會被加載。

#pragma mark - Public methods

- (void)setURL:(NSURL*)URL {

[_URL release];

_URL = [URL copy];

AVURLAsset *asset = [AVURLAsset URLAssetWithURL:_URL options:nil];

NSArray *requestedKeys = [NSArray arrayWithObjects:kTracksKey,

kPlayableKey, nil];

[asset loadValuesAsynchronouslyForKeys:requestedKeys

completionHandler: ^{ dispatch_async(

dispatch_get_main_queue(), ^{

[self prepareToPlayAsset:asset

withKeys:requestedKeys];

});

}];

}

- (NSURL*)URL {

return _URL;

}

所以,一旦視頻的 URL 被賦值后,創建一個資源來檢查被指定的URL引用的源并且異步的加載這個資源的 “tracks” 和 “playable” 鍵值。等加載結束后,我們就可以在主線程操作 AVPlayer(當播放狀態動態改變時,主線程可以確保安全的獲取播放器的非原子屬性)。

#pragma mark - Private methods

- (void)prepareToPlayAsset: (AVURLAsset *)asset withKeys:

(NSArray *)requestedKeys {

for (NSString *thisKey in requestedKeys) {

NSError *error = nil;

AVKeyValueStatus keyStatus = [asset

statusOfValueForKey:thisKey

error:&error];

if (keyStatus == AVKeyValueStatusFailed) {

return;

}

}

if (!asset.playable) {

return;

}

if (self.playerItem) {

[self.playerItem removeObserver:self forKeyPath:kStatusKey];

[[NSNotificationCenter defaultCenter] removeObserver:self

name:AVPlayerItemDidPlayToEndTimeNotification

object:self.playerItem];

}

self.playerItem = [AVPlayerItem playerItemWithAsset:asset];

[self.playerItem addObserver:self forKeyPath:kStatusKey

options:NSKeyValueObservingOptionInitial |

NSKeyValueObservingOptionNew

context:

AVPlayerDemoPlaybackViewControllerStatusObservationContext];

if (![self player]) {

[self setPlayer:[AVPlayer playerWithPlayerItem:self.playerItem]];

[self.player addObserver:self forKeyPath:kCurrentItemKey

options:NSKeyValueObservingOptionInitial |

NSKeyValueObservingOptionNew

context:

AVPlayerDemoPlaybackViewControllerCurrentItemObservationContext];

}

if (self.player.currentItem != self.playerItem) {

[[self player] replaceCurrentItemWithPlayerItem:self.playerItem];

}

}

在資源所有需要的鍵值加載完成后,我們檢查是否加載成功以及該資源是否可以播放。如果這樣,我們初始化一個 AVPlayerItem (用來表示能被 AVPlayer 對象播放的資源的表示狀態)和一個 AVPlayer 來播放的資源。請注意,我在這一點上沒有添加任何錯誤處理。在這里,我們應該創建一個委托并讓視圖控制器或正在使用你的播放器的用戶,決定如何以最好的方式來處理可能出現的錯誤。

我們也添加了一些鍵值監聽以便于當我們的視圖被綁定到播放器時和 AVPlayerItem 準備好播放時收到通知。

#pragma mark - Key Valye Observing

- (void)observeValueForKeyPath: (NSString*) path

? ? ? ? ? ? ? ? ? ? ?ofObject: (id)object

? ? ? ? ? ? ? ? ? ? ? ?change: (NSDictionary*)change

? ? ? ? ? ? ? ? ? ? ? context: (void*)context {

? ?if (context == AVPlayerDemoPlaybackViewControllerStatusObservation

? ? ? ? ? ? Context) {

? ? ? ? ? ? ?AVPlayerStatus status = [[change objectForKey:

? ? ? ? ? ? ? ?NSKeyValueChangeNewKey] integerValue];

? ? ? ? ? ? ?if (status == AVPlayerStatusReadyToPlay) {

? ? ? ? ? ? ? ? ? [self.player play];

? ? ? ? ? ? ?}

? ?} else if (context == AVPlayerDemoPlaybackViewControllerCurrentItem

? ? ? ? ? ? ObservationContext) {

? ? ? ? ? ? ?AVPlayerItem *newPlayerItem = [change objectForKey:

? ? ? ? ? ? ? ? NSKeyValueChangeNewKey];

if (newPlayerItem) {

[self.playerView setPlayer:self.player];

[self.playerView setVideoFillMode:

AVLayerVideoGravityResizeAspect];

}

} else {

[super observeValueForKeyPath:path ofObject: object

change:change context:context];

}

}

一旦 AVPlayerItem 設置好后,我們可以自由的將 AVPlayer 添加到用來展示可視輸出的播放器層。我們也會確保保留視頻的長寬比和適合視頻圖層的邊界內。

一旦 AVPlayer 準備好了,就讓它開始播放!讓 iOS 來完成艱巨的任務 :)

正如我前面所說,為了播放資源可視組件,您需要一個包含 AVPlayerLayer 的視圖,來指揮 AVPlayer 對象的輸出。下面演示了如何子類化 UIView 來滿足要求︰

@implementation VideoPlayerView

+ (Class)layerClass {

return [AVPlayerLayer class];

}

- (AVPlayer*)player {

return [(AVPlayerLayer*)[self layer] player];

}

- (void)setPlayer: (AVPlayer*)player {

[(AVPlayerLayer*)[self layer] setPlayer:player];

}

- (void)setVideoFillMode: (NSString *)fillMode {

AVPlayerLayer *playerLayer = (AVPlayerLayer*)[self layer];

playerLayer.videoGravity = fillMode;

}

@end

到這里就結束了!

當然,我沒有貼上所有用來編譯和運行的項目代碼,但我不會讓你失望 !轉到 GitHub 并下載完整的源代碼 !

?

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,967評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,273評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,870評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,742評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,527評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,010評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,108評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,250評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,769評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,656評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,853評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,371評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,103評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,472評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,717評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,487評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,815評論 2 372

推薦閱讀更多精彩內容