2016-06-28 110 views
4

我正在Swift中製作一個iOS應用程序,在屏幕右上角的小圖層中循環播放視頻,該視頻顯示特定彩色項目的視頻。用戶然後點擊屏幕上相應的彩色項目。當他們這樣做時,videoName變量會隨機更改爲下一個顏色,並觸發相應的視頻。我沒有問題提出,播放和AVPlayer,AVPlayerItem循環視頻,如附件所示。 我卡住的地方在於,無論何時顯示下一個視頻,以前的視頻都保持打開狀態。此外,在播放了16個視頻後,播放器會在我的iPad上完全消失。我已經嘗試過在這個站點和其他站點上提出的許多建議,但swift發現它們存在問題,或者它不起作用。 所以問題:在我的代碼中,我該如何告訴它「嘿,下一個視頻已經開始播放,刪除以前的視頻,它是分層和釋放內存,所以我可以根據需要播放盡可能多的視頻」?如何關閉以前的AVPlayer和AVPlayerItem

//set variables for video play 
var playerItem:AVPlayerItem? 
var player:AVPlayer? 

//variables that contain video file path, name and extension 
var videoPath = NSBundle.mainBundle().resourcePath! 
var videoName = "blue" 
let videoExtension = ".mp4" 

//DISPLAY VIDEO 
func showVideo(){ 

     //Assign url path 
     let url = NSURL(fileURLWithPath: videoPath+"/Base.lproj/"+videoName+videoExtension) 
     playerItem = AVPlayerItem(URL: url) 
     player=AVPlayer(playerItem: playerItem!) 
     let playerLayer=AVPlayerLayer(player: player!) 

     //setplayser location in uiview and show video 
     playerLayer.frame=CGRectMake(700, 5, 350, 350) 
     self.view.layer.addSublayer(playerLayer) 
     player!.play() 

    // Add notification to know when the video ends, then replay it again. THIS IS A CONTINUAL LOOP 
    NSNotificationCenter.defaultCenter().addObserverForName(AVPlayerItemDidPlayToEndTimeNotification, object: player!.currentItem, queue: nil) 
    { notification in 
     let t1 = CMTimeMake(5, 100); 
     self.player!.seekToTime(t1) 
     self.player!.play() 
    } 

} 

`

+0

'每當顯示的下一個視頻,以前的因爲你不斷加入他們一個與'self.view.layer另一個的上面留it'後面開。 addSublayer(playerLayer)'。在添加新的之前,您應該刪除前一個。 – Moritz

回答

0

我改編了@Anupam Mishra的Swift代碼建議。它一開始並沒有工作,但最終認爲我必須將playerLayer放在該函數之外,並在將播放器設置爲零後關閉playerLayer。也。而不是使用'if(player!.rate> 0 ...)',這無疑仍然有效,我創建了一個變量開關來指示何時說「殺死播放器和圖層」,如下所示。它可能不漂亮,但它的工作原理! 以下是我自己的絕對新手 - 我從這個經驗中學到了什麼:在我看來,ios設備只允許將16層添加到viewController(或superLayer)中。因此在使用其播放器打開下一個圖層之前,需要刪除每個圖層,除非您確實需要一次運行16個圖層。 以下代碼實際適用於您的代碼:此代碼在現有viewController上創建可重新分層的圖層,並從您的包中以無限循環方式播放視頻。當下一個視頻即將被調用時,當前視頻和圖層被完全移除,釋放內存,然後播放帶有新視頻的新圖層。視頻圖層大小和位置可以使用playerLayer.frame = CGRectMake(左,上,寬,高)參數完全自定義。 如何使所有工作:假設您已經將視頻添加到您的視頻包中,請爲您的按鈕輕擊創建另一個功能。在該函數中,首先調用'stopPlayer()'函數,將'videoName'變量更改爲所需的新視頻名稱,然後調用'showVideo()'函數。 (如果您需要更改視頻擴展名,請將'videoExtension'從let改爲var。

`

//set variables for video play 
var playerItem:AVPlayerItem? 
var player:AVPlayer? 
var playerLayer = AVPlayerLayer() //NEW playerLayer var location 

//variables that contain video file path, name and extension 
var videoPath = NSBundle.mainBundle().resourcePath! 
var videoName = "blue" 
let videoExtension = ".mp4" 

var createLayerSwitch = true /*NEW switch to say whether on not to create the layer when referenced by the closePlayer and showVideo functions*/ 

//DISPLAY VIDEO 
func showVideo(){ 

    //Assign url path 
    let url = NSURL(fileURLWithPath: videoPath+"/Base.lproj/"+videoName+videoExtension) 
    playerItem = AVPlayerItem(URL: url) 
    player=AVPlayer(playerItem: playerItem!) 
    playerLayer=AVPlayerLayer(player: player!) //NEW: remove 'let' from playeLayer here. 

    //setplayser location in uiview and show video 
    playerLayer.frame=CGRectMake(700, 5, 350, 350) 
    self.view.layer.addSublayer(playerLayer) 
    player!.play() 

    createLayerSwitch = false //NEW switch to tell if a layer is already created or not. I set the switch to false so that when the next tapped item/button references the closePlayer() function, the condition is triggered to close the player AND the layer 

// Add notification to know when the video ends, then replay it again without a pause between replays. THIS IS A CONTINUAL LOOP 
NSNotificationCenter.defaultCenter().addObserverForName(AVPlayerItemDidPlayToEndTimeNotification, object: player!.currentItem, queue: nil) 
{ notification in 
    let t1 = CMTimeMake(5, 100); 
    self.player!.seekToTime(t1) 
    self.player!.play() 
} 
} 
    //NEW function to kill the current player and layer before playing the next video 
func closePlayer(){ 
if (createLayerSwitch == false) { 
    player!.pause() 
    player = nil 
    playerLayer.removefromsuperlayer() 
} 
} 

`

0

爲什麼不只是使用播放器上的replaceCurrentItemWithPlayerItem?您將爲所有視頻保留相同的播放器。我認爲這是一個更好的方法。

編輯:replaceCurrentItemWithPlayerItem必須是主線程

+0

這看起來很有希望。我嘗試以各種方式實現這一點,但似乎無法讓它工作。你能否複製並粘貼上面的代碼,以顯示你將如何實現replaceCurrentItemWithPlayerItem?我還剛剛添加了我的播放器和PlayerItem變量。 – TuxedoedCastle

+0

我從來沒有使用它,我不能告訴你,但它應該工作。否則,正如@Eric D建議的那樣,當視頻結束時,執行'playerLayer.removeFromSuperlayer()'併爲下一個添加一個新圖層。 – AnthoPak

0

移動在接下來的跟蹤第一次檢查之前打電話,是具有任何視頻或音樂播放器,以阻止它做以下檢查 -

斯威夫特代碼 -

if (player!.rate>0 && player!.error == nil) 
      { 
       player!.pause(); 
       player = nil 
      } 

Objective-C的代碼 -

if (player.rate>0 && !player.error) 
    { 
     [player setRate:0.0]; 
    } 
+0

我試過以各種方式使用這個(swift)建議。在showVideo()函數的開始處使用它時,我認爲這是最明顯的使用它的地方,遊戲崩潰並且引發致命錯誤。對此有何想法? – TuxedoedCastle

相關問題