使用 AVQueuePlayer 跳到上一个的更好方法?

Better way to do skip to previous with AVQueuePlayer?

我在我的应用程序中使用 AVQueuePlayer。我有两个滑动手势可以跳到下一个和跳到上一个 avplayeritems。现在要跳到下一个,我只是在运行良好的 avqueueplayer 上调用 advanceToNextItem。

然而,跳到上一个我正在删除所有项目并将它们重新添加到前面的上一个视频中,这在多次跳到上一个时真的很慢。我怎样才能让它更快,就像调用 advanceToNextItem?

我的代码如下所示:

func skipToPrevious() {
    queuePlayer.removeAllItems()
    // move the previous playerItem to the front of the list then add them all back in
    for playerItem in playerItems:
        queuePlayer.insertItem(playerItem, afterItem: nil)

}

似乎 AVQueuePlayer 在调用 advanceToNextItem 时从播放队列中删除了当前项目。从理论上讲,如果不重建队列,就无法取回此项目。

你可以做的是使用标准 AVPlayer,有一个 AVPlayerItems 的数组,以及一个保存当前曲目的索引的整数索引。

Swift 3:

let player = AVPlayer()
let playerItems = [AVPlayerItem]() // your array of items
var currentTrack = 0

func previousTrack() {
    if currentTrack - 1 < 0 {
        currentTrack = (playerItems.count - 1) < 0 ? 0 : (playerItems.count - 1)
    } else {
        currentTrack -= 1
    }

    playTrack()
}

func nextTrack() {
    if currentTrack + 1 > playerItems.count {
        currentTrack = 0
    } else {
        currentTrack += 1;
    }

    playTrack()
}

func playTrack() {

    if playerItems.count > 0 {
        player.replaceCurrentItem(with: playerItems[currentTrack])
        player.play()
    }
}

Swift 2.x:

func previousTrack() {
    if currentTrack-- < 0 {
        currentTrack = (playerItems.count - 1) < 0 ? 0 : (playerItems.count - 1)
    } else {
        currentTrack--
    }

    playTrack()
}

func nextTrack() {
    if currentTrack++ > playerItems.count {
        currentTrack = 0
    } else {
        currentTrack++;
    }

    playTrack()
}

func playTrack() {

    if playerItems.count > 0 {
        player.replaceCurrentItemWithPlayerItem(playerItems[currentTrack])
        player.play()
    }
}

replaceCurrentItemWithPlayerItem 有限制,应尽可能避免,在 Apple's document 中,它指出 "The new item must have the same compositor as the item it replaces, or have no compositor."

而不是使用循环一个一个地插入 playerItems,只创建一个 AVQueuePlayer 会更快:

func skipToPrevious() {
    queuePlayer = AVQueuePlayer.queuePlayerWithItems(playerItem)
}

队列是否处理多个向前跳过顺利?如果是这样,您可以不断地将之前的视频重新插入到索引 n+2 处的队列中。当用户想播放上一首曲目时,你会向前跳两次。

如果从曲目 A 播放到 F 没有任何跳过,模式将如下所示:

A B C D E F
B C D E F

// re-insert A after next track
B C A D E F
C A D E F

// remove A then re-insert B
C D E F
C D B E F
D B E F

// remove B then re-insert C
D E F
D E C F
E C F

// remove C then re-insert D
E F
E F D
F D

// remove D then re-insert E
F
FE

使用这个模式你只能平滑地向后跳一次,但可以修改它以允许更多。

绝对不是理想的解决方案,但可能有效!

我正在考虑一种非常不同的方法,实际上是在 advanceToNextItem 方法方面。你说 advanceToNextItem 工作正常。所以我想知道您是否可以使用 advanceToNextItem 本身实现跳到上一个,但是通过将队列指向当前播放项目的后两个项目。

例如如果你的队列是这个,粗体是当前项目

A B C D E F G H

然后将当前项目设置为C,然后使用advanceToNextItem,使其播放D。

但不确定您的 advanceToNextItem 是如何实现的。所以这取决于那个。

  1. 在第一项之后插入第一项:
    player.insert(player.items()[0], after: player.items()[0])
  2. 在第一项之后插入重新创建的前一项:
    player.insert(prevItem, after: player.items()[0])
  3. 呼叫player.advanceToNextItem().

您可以用之前的项目替换当前项目并添加被替换的项目:

let previousItem = AVPlayerItem(url: url )
let currentItem = AVPlayerItem(url: currentUrl)

 player.replaceCurrentItem(with: previousItem)
    if player.canInsert(currentItem, after: previousItem) {
         player.insert(currentItem, after: previousItem)
    }

// 或者像这样

 let previousItem = AVPlayerItem(url: url )
 if let currentItem = player.currentItem {
   player.replaceCurrentItem(with: previousItem)
     if player.canInsert(currentItem, after: previousItem) {
         player.insert(currentItem, after: previousItem)
     }
  }