【问题标题】:How to close previous AVPlayer and AVPlayerItem如何关闭以前的 AVPlayer 和 AVPlayerItem
【发布时间】:2016-06-28 07:31:14
【问题描述】:

我正在用 Swift 制作一个 iOS 应用程序,它在屏幕右上角的一个小层中循环播放视频,该层显示特定颜色项目的视频。然后用户点击屏幕上相应的彩色项目。当他们这样做时,videoName 变量会随机更改为下一种颜色,并触发相应的视频。如附件代码所示,我可以使用 AVPlayer、AVPlayerItem 提升、播放和循环视频。 我被卡住的地方是,每当显示下一个视频时,以前的视频都会在它后面保持打开状态。此外,播放 16 个视频后,播放器在我的 iPad 上完全消失。我已经尝试了这个站点和其他站点中提出的许多建议,但要么迅速发现它们有问题,要么就是不起作用。 所以问题:在我的代码中,我如何告诉它“嘿,下一个视频已开始播放,删除上一个视频及其图层并释放内存,以便我可以根据需要播放尽可能多的视频”?

//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()
    }

}

`

【问题讨论】:

  • whenever the next video is shown, previous ones stay open behind it 因为您不断将它们与self.view.layer.addSublayer(playerLayer) 叠加在一起。在添加新的之前,您应该删除之前的。

标签: ios swift avplayer avplayeritem


【解决方案1】:

我改编了@Anupam Mishra 的 Swift 代码建议。起初它不起作用,但最终我认为我必须将 playerLayer 放在函数之外并在我将 player 设置为 nil 后关闭 playerLayer。还。而不是使用 'if(player!.rate>0 ...)' 这无疑仍然有效,我创建了一个变量开关来指示何时说“杀死玩家和图层”,如下所示。它可能不漂亮,但它有效! 以下内容适用于像我这样的绝对新手 - 我从这次经历中学到了什么:在我看来,ios 设备只允许将 16 层添加到 viewController(或 superLayer)。因此,除非您真的希望同时运行 16 层,否则在使用其播放器打开下一层之前,需要删除每一层。 下面这段代码对你的实际作用:这段代码在现有的 viewController 上创建了一个可调整大小的层,并在无限循环中播放 你的 bundle 中的视频。当即将调用下一个视频时,将当前视频和图层完全删除,释放内存,然后播放带有新视频的新图层。使用 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 层限制有同样的问题。感谢您的建议和代码
  • 请注意关闭播放器时需要移除观察者
【解决方案2】:

为什么不在你的播放器上使用replaceCurrentItemWithPlayerItem 呢?您将为所有视频保留相同的播放器。我认为这是一种更好的方法。

编辑: replaceCurrentItemWithPlayerItem 必须在主线程上调用

【讨论】:

  • 这看起来很有希望。我尝试以各种方式实现这一点,但似乎无法让它发挥作用。您能否复制并粘贴我上面的代码以显示如何使用它实现 replaceCurrentItemWithPlayerItem?我还刚刚添加了我的 player 和 PlayerItem 变量。
  • 我从未使用过它,我不能告诉你,但它应该可以工作。否则,正如@Eric D 建议的那样,在视频结束时执行playerLayer.removeFromSuperlayer() 并为下一个添加新图层。
  • 问题是,当更改replaceCurrentItemWithPlayerItem时,你会得到一个闪光效果,真的很烦人
【解决方案3】:

在继续下一个曲目之前首先检查播放器是否有任何视频或音乐,要阻止它,请执行以下检查:

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() 函数的开头使用它时,游戏崩溃并引发致命错误。对此有何想法?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-22
  • 2019-10-05
相关资源
最近更新 更多