如何关闭之前的AVPlayer和AVPlayerItem

8
我正在使用Swift制作一个iOS应用程序,在屏幕右上角的小层中循环播放特定颜色物品的视频。然后用户点击屏幕上对应的彩色物品。当他们这样做时,videoName变量会随机更改为下一个颜色,并触发相应的视频。我没有问题使用AVPlayer、AVPlayerItem在附加的代码中提到的方式来升起、播放和循环视频。 我遇到的问题是,每当下一个视频出现时,之前的视频仍然停留在它的后面。此外,在我的iPad上播放16个视频后,播放器就完全消失了。我尝试了许多在本网站和其他网站上提出的建议,但是Swift要么发现了问题,要么根本不起作用。 所以问题是:在我的代码中,我如何告诉它“嘿,下一个视频已经开始播放,删除前一个视频及其图层并释放内存,以便我可以播放尽可能多的视频”?
//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()
    }

}

`


每当下一个视频播放时,前面的视频都会保持在其后面打开。这是因为您使用了“self.view.layer.addSublayer(playerLayer)”将它们一层层叠加。在添加新视频之前,应该先移除之前的视频。 - Eric Aya
3个回答

4
我改编了@Anupam Mishra的Swift代码建议。一开始它不起作用,但最终发现我必须将playerLayer移出函数,并在将播放器设置为nil后关闭playerLayer。此外,我创建了一个变量开关来指示何时说“杀死播放器和图层”,而不是使用“if(player!.rate> 0 ...)”,这无疑仍然有效。如下所示。它可能不太好看,但它有效!以下内容是给像我一样的绝对新手 - 我从这个经验中学到了什么:我认为ios设备只允许向viewController(或superLayer)添加16个图层。因此,除非您真的想要同时运行16个图层,否则每个图层都需要在打开具有其播放器的下一个图层之前被删除。此代码可以在现有视图控制器上创建可调整大小的图层,并在无限循环中播放来自您捆绑包中的视频。当即将调用下一个视频时,当前视频和该层将完全删除,释放内存,然后播放新视频的新图层。使用playerLayer.frame = CGRectMake(left,top,width,height)参数可以完全自定义视频图层的大小和位置。如何使所有内容都正常工作:假设您已将视频添加到捆绑包中,请为按钮点击创建另一个函数。在该函数中,首先调用“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()
 }
}

`


我也遇到了16层限制的问题。感谢您的建议和代码。 - Firas Shrourou
请注意,在关闭播放器时需要移除观察者。 - Firas Shrourou

2
为什么不在您的播放器上使用replaceCurrentItemWithPlayerItem?这样,您将为所有视频保留相同的播放器。我认为这是更好的方法。
编辑:必须在主线程上调用replaceCurrentItemWithPlayerItem

这看起来很有前途。我尝试以各种方式实现它,但似乎无法使其工作。您能否将我的代码复制并粘贴到上面,展示如何使用replaceCurrentItemWithPlayerItem?另外我刚刚添加了我的player和PlayerItem变量。 - TuxedoedCastle
我从未使用过它,所以无法告诉你,但应该可以工作。否则,如@Eric D建议的那样,在视频结束时执行playerLayer.removeFromSuperlayer()并为下一个视频添加新图层。 - AnthoPak
问题在于当更改replaceCurrentItemWithPlayerItem时,会出现闪烁效果,这真的很烦人。 - StackGU

0

在进入下一个轨道之前,请先检查播放器是否有任何视频或音乐,要停止它,请进行以下检查:

Swift 代码-

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

Objective-C 代码 -

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

我尝试以各种方式使用这个(Swift)建议。当我在showVideo()函数的开头使用它时,我认为这是最明显的使用场景,游戏会崩溃并抛出致命错误。对此有什么想法吗? - TuxedoedCastle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接