【问题标题】:Better way to do skip to previous with AVQueuePlayer?使用 AVQueuePlayer 跳到上一个的更好方法?
【发布时间】:2016-01-24 03:21:46
【问题描述】:

我在我的应用程序中使用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)

}

【问题讨论】:

  • 我也面临这个问题有一段时间了。在用户点击上一个项目时,我已经诉诸于重新创建队列播放器。然后我使用延迟函数和屏幕上的进度条,让队列播放器有至少 1.0 秒的时间来重新创建队列并缓冲该项目的一部分。当然,这并不能解决您想要更快速度的问题。我会多挖一点。
  • 到目前为止我发现的最好的方法是在播放完成后将 avplayeritem 保存在内存中,这样它就已经被缓冲了,然后就像我在问题中所做的那样重新插入项目,而不是重新创建队列一起来。
  • 一个想法 -> 当一个项目正在播放时,将当前正在播放的项目存储在变量中并将其加载到 AVPlayer 中。当用户点击快退时,您可以立即播放 AVPlayer,然后您可以简单地在后台暂停和快退 AVQueuePlayer,这样当 AVPlayer 完成时,队列播放器就可以开始了……有点hacky 当然
  • github.com/dgiovann/AVQueuePlayerPrevious ...有点老了,但这可能对你有帮助

标签: ios swift avqueueplayer avplayeritem


【解决方案1】:

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

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

斯威夫特 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()
    }
}

【讨论】:

  • 这是我的想法,但试图避免。有没有avqueueplayer来源的例子?我想以此为基础
  • @Tyler 是AVQueuePlayer 的来源吗?我认为没有人拥有它,因为它是 Apple 内部的。我可以为您提供的是 AVQueuePlayerAVQueuePlayerInternal 的私有标头。
  • 这是 100% 的最佳解决方案。关键是将 avplayeritems 保存在内存中,而不是在跳转到上一个时重新加载它们。只是需要注意不要在内存中保留太多,有些最终会被丢弃。谢谢!
  • @Sulthan 如果您在第 0 条轨道上怎么办?如果您在第一首曲目并尝试返回,您将超出范围,除非您找到播放列表中的最后一项。这也是快速存根代码。
  • @JAL 您的第二个版本要好得多。我可能会使用let previous = (currentTrack - 1 + playerItems.count) % playerItems.countlet next = (currentTrack + 1) % playerItems.count,但这是一个选择问题。
【解决方案2】:

队列是否可以顺利处理多个向前跳过?如果是这样,您可以不断地将前一个视频重新插入到索引 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

使用这种模式,您只能顺利向后跳过一次,但可以对其进行修改以允许更多。

绝对不是一个理想的解决方案,但可能会奏效!

【讨论】:

    【解决方案3】:

    replaceCurrentItemWithPlayerItem 有限制,应尽可能避免使用,在 Apple's document 中,它声明“新项目必须具有与其替换的项目相同的合成器,或者没有合成器。”

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

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

    【讨论】:

    • 为什么这会提高速度?慢的原因是它没有预先缓冲前面的avplayitem
    【解决方案4】:

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

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

    A B C D E F G H

    然后将当前item设置为C,然后使用advanceToNextItem让它播放D。

    不确定您的 AdvanceToNextItem 是如何实现的。所以这取决于它。

    【讨论】:

      【解决方案5】:

      您可以将当前项目替换为上一个项目并添加已替换的项目:

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

      【讨论】:

        【解决方案6】:
        1. 在第一项之后插入第一项:
          player.insert(player.items()[0], after: player.items()[0]).
        2. 在第一项之后插入重新创建的上一项:
          player.insert(prevItem, after: player.items()[0])
        3. 致电player.advanceToNextItem()

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-05-03
          • 2011-06-30
          • 1970-01-01
          相关资源
          最近更新 更多