播放器
對於資源的播放,你應使用AVPlayer類。你可以使用AVPlayerItem執行個體去管理整個資源的顯示狀態,使用AVPlayerIteamTrack類去管理單獨任務的顯示狀態。你可以使用AVPlayerLayer類進行顯示 播放資源
player是你用來管理一個資源播放裝置的控制類,比如開始播放、結束播放,特定時間的情況等。你可以使用一個AVPlayer執行個體去播放一個單獨的資源。你可以使用一個AVQueuePlayer(AVPlayer的子類)類去播放一個資源隊列。在macOS,你可以選擇使用AVKit架構下的AVPlayerView播放視頻。
….. 操作不同類型的資源
你配置一個資源播放裝置的的方式也許取決於你想要播放資源的種類。總的來說,這有兩種類型:檔案資源,比如本地檔案、攝像資源、媒體庫等;流檔案,流媒體檔案、網路視頻等 載入和播放檔案資源,這有幾個步驟來播放檔案資源: 使用AVURLAsset建立資源 建立AVPlayItem執行個體使用資源 通過AVPlayer與item進行綁定 等待直到item的狀態特徵指示為準備播放(你可以使用key-value監聽狀態的改變) 建立和準備流媒體播放裝置。
通過使用URL初始化一個AVPlayerItem執行個體(你不能直接使用AVAsset執行個體去替代流媒體檔案)
let url = NSURL("http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8")videoItem = AVPlayerItem(URL:url) self.playerItem.addObserver(self,forKeyPath:"status",options:.New,context:nil) //監聽狀態videoplayer = AVPlayer(playerItem:self.playerItem)
當你將playerItem和player綁定時,它就變成了準備播放狀態,當它變成了準備播放狀態,playerItem就會建立一個AVAsset和AVAssetTrack執行個體,你可以使用這些檢查流媒體的內容。
你可以擷取視頻時間長度,通過playItem的duration屬性,當視頻變成了準備播放狀態時,這個屬性就會拿到視頻的正確時間長度。
你可以監聽狀態視頻播放狀態,例如上面代碼。 播放單獨資源
videoplayer.play() //播放
播放速度
videoplayer.rate = 2 //速度
值為1表示正常的播放速度,將速度設為0就等同於暫停。它也支援反向播放,通過將速度設為一個負值,你通過設定canPlayReverse屬性來設定支援反向播放的狀態,它預設的速度是-1,canPlaySlowReverse屬性的速度在0到-1之間,canPlayFastReverse屬性的速度是小於-1的值。 重新置放播放頭
通過使用seekToTime:可以將播放移動到特定的時間:
let fiveSecondsIn = CMTimeMake(30, 1)//當前第20幀,每秒1幀,當前播放時間20/1 videoplayer.seekToTime(fiveSecondsIn)//跳到fiveSecondsIn
然而,seekToTime:方法更偏向於效能而非精確。如果你想非常精確地跳轉到某個進度,你應該使用seekToTime:toleranceBefore:toleranceAfter:
videoplayer.seekToTime(fiveSecondsIn, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero)
當播放完成之後,播放頭正好是停留在結束的位置,即使你使用play也沒有任何作用,為了讓視頻播放完之後重新回到開始的位置,我們可以在通知中樞註冊一個AVPlayerItemDidPlayToEndTimeNotification通知。在通知的回調方法中,你可以通過seekToTime:將參數設為kCMTimeZero。
//監聽播放結束 NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(FCFAVPlayerController.playItemDidReachEnd(_:)), name: AVPlayerItemDidPlayToEndTimeNotification, object: videoItem)func playItemDidReachEnd(notifacation:NSNotification) { videoplayer.seekToTime(kCMTimeZero)}
播放多個資源
你可以使用AVQueuePlayer播放一個資源隊列,AVQueuePlayer是AVPlayer的子類,初始化一個AVQueuePlayer:
let playItem1 = AVPlayerItem(URL:NSURL(string: "http://tsmusic128.tc.qq.com/37023937.mp3")!)let playItem2 = AVPlayerItem(URL:NSURL(string:"http://down.treney.com/mov/test.mp4")!)let items = NSArray(array: [playItem1,playItem2])let queuePlayer = AVQueuePlayer(items: items as! [AVPlayerItem])let layer = AVPlayerLayer(player: queuePlayer)layer.frame = CGRectMake(20, 200, CGRectGetWidth(self.view.frame)-40, 200)layer.backgroundColor = UIColor.blueColor().CGColorself.view.layer.addSublayer(layer)queuePlayer.play()
你可以使用play()播放資源隊列,就像AVPlayer一樣,隊列按順序播放每一個資源,如果你想播放在一個資源,你可以使用advanceToNextItem。
你同樣可以使用insertItem:afterItem:,removeItem:,removeAllItem:修改資源隊列。當你要增加一個新的資源的時候,你最好使用canInsertItem:afterItem:先判斷隊列是否可以插入新的資源,第二個參數裡傳入nil則是測試新資源追加到隊列末尾。
let playNewItem = AVPlayerItem(URL:NSURL(string:"http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8")!)if queuePlayer.canInsertItem(playNewItem, afterItem: nil) { queuePlayer.insertItem(playNewItem, afterItem: nil) }
監聽播放
你可以監聽當前現正播放的資源的呈現狀態及播放項目的各個方面,這對於那些無法直接控制下的狀態變化非常有用,比如說:
* 如果使用者使用多線程切換不同的app時,播放器的速度將有可能降至0
* 如果現正播放的是一個遠程媒體,隨著越來越多的資料可用item的loadedTimeRange和seekableTimeRange屬性將會改變。這些屬性將會告訴你資源的哪些時間段是可用的。
* 播放器的currentItem屬性會隨著新的item建立而改變
* 播放的過程中item的tracks屬性可能會隨著播放改變,一般是當內容有多種轉碼方式的時候,當編碼方式切換的時候tracks會改變
* 播放器、item的status可能會改變如果播放失敗或者其他一些原因
你可以使用key-value監聽這些屬性的改變。 監聽狀態的改變
當播放器或者item的狀態改變時,它會發出一個通知。如果一個資源出於某些原因無法播放,那麼status就會改變成AVPlayerStatusFailed或者AVPlayerItemStatusFailed,這種狀態時,屬性error將會有關於為什麼不能播放的描述。
AV Foundation沒有說明返回的通知是在什麼線程,如果你想要更新UI,你必須確保任何相關的ui代碼是在主線程中,例如:
//監控狀態屬性, videoItem.addObserver(self, forKeyPath: "status", options: .New, context:nil) //監控網路載入情況的屬性 videoItem.addObserver(self, forKeyPath: "loadedTimeRanges", options: .New, context: nil)override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) { let playItem:AVPlayerItem = object as! AVPlayerItem if keyPath == "status" { if playItem.status == AVPlayerItemStatus.Failed { let error = playItem.error print(error) return } print("現正播放...,視頻總長\(CMTimeGetSeconds(playItem.duration))") }else if keyPath == "loadedTimeRanges" { let array = playItem.loadedTimeRanges let timeRange = array.first?.CMTimeRangeValue //本次緩衝時間範圍 let startSecondes = CMTimeGetSeconds((timeRange?.start)!); let durationSeconds = CMTimeGetSeconds((timeRange?.duration)!) let totalBuffer = startSecondes + durationSeconds //緩衝總長度 print("緩衝總長度 \(totalBuffer)") }}
追蹤顯示狀態
當資源有顯示內容的話,你可以擷取一個AVPlayerLayer的readyForDisplay屬性通知 追蹤時間
你可以使用addPeriodicTimeObserverForInterval:queue:usingBlock:或者addBoundaryTimeObserverForTimes:queue:usingBlock:去追蹤播放進度。這樣你就知道已經完成的時間和剩餘時間,並且同步操作更新UI。 addPeriodicTimeObserverForInterval:queue:usingBlock:這個方法傳入的是一個CMTime結構時間,每隔這個時間段,block會回調一次,開始和結束的時候,也會回調一次。 addBoundaryTimeObserverForTimes:queue:usingBlock:這個是傳入了一個CMTime結構的數組,當播放至數組裡的時間時,block會回調一次。
你同樣可以使用removeTimeObserver:取消這個觀察者。
對於這兩個方法,AVFoundation不會保證每次時間點到了都會回調block,如果前面的block沒有執行完的時候,下一次就不會回調。所以應該保證block不會太耗時。
//追蹤時間 let durations = CMTimeGetSeconds(asset.duration) let firstTrack = CMTimeMakeWithSeconds(durations/3.0, 1) let secondTrack = CMTimeMakeWithSeconds(durations*2.0/3.0, 1) let times = [NSValue(CMTime: firstTrack),NSValue(CMTime:secondTrack)] self.videoplayer.addBoundaryTimeObserverForTimes(times, queue: nil) { print("xxxxx") }