【问题标题】:How to reduce iOS AVPlayer start delay如何减少 iOS AVPlayer 启动延迟
【发布时间】:2012-06-25 15:33:35
【问题描述】:

请注意,对于以下问题:所有资产都在设备上本地 - 没有发生网络流式传输。视频包含音轨。

我正在开发一个 iOS 应用程序,该应用程序需要以最小延迟播放视频文件才能启动相关视频剪辑。不幸的是,在我们真正需要启动它之前,我们不知道接下来是什么特定的视频剪辑。具体来说:当播放一个视频剪辑时,我们将知道下一组(大约)10 个视频剪辑是什么,但我们不知道具体是哪一个,直到“立即”播放下一个剪辑。

我查看实际开始延迟的方法是在视频播放器上调用addBoundaryTimeObserverForTimes,以一毫秒的时间段查看视频实际开始播放的时间,我取那个时间的差标记代码中的第一位,指示要开始播放的资产。

从我目前看到的情况来看,我发现使用AVAsset 加载的组合,然后在它准备好后从中创建一个AVPlayerItem,然后在我调用播放之前等待AVPlayerStatusReadyToPlay ,开始剪辑通常需要 1 到 3 秒。

我已经切换到我认为大致等效的方式:调用[AVPlayerItem playerItemWithURL:] 并等待AVPlayerItemStatusReadyToPlay 播放。性能大致相同。

我观察到的一件事是第一个 AVPlayer 项目的加载速度比其他项目慢。似乎一个想法是在尝试播放第一个视频之前使用短/空资产预飞行 AVPlayer 可能是一个很好的一般做法。 [Slow start for AVAudioPlayer the first time a sound is played

我希望尽可能缩短视频的开始时间,并有一些可以尝试的想法,但希望得到任何可能提供帮助的人的指导。

更新:下面的想法 7 实现后的切换时间约为 500 毫秒。这是一项改进,但如果能更快地实现这一点会更好。

想法 1:使用 N 个 AVPlayer(行不通)

使用 ~ 10 个 AVPPlayer 对象并开始和暂停所有 ~ 10 个剪辑,一旦我们知道我们真正需要哪个剪辑,切换到并取消暂停正确的 AVPlayer,然后重新开始下一个循环。

我认为这行不通,因为我读过 iOS 中的活动 AVPlayer's 大约有 4 个限制。有人在 StackOverflow 上问过这个问题,发现了 4 AVPlayer 限制:fast-switching-between-videos-using-avfoundation

想法 2:使用 AVQueuePlayer(行不通)

我不相信将 10 个 AVPlayerItems 推入 AVQueuePlayer 会预先加载它们以实现无缝启动。 AVQueuePlayer 是一个队列,我认为它实际上只会使队列中的下一个视频准备好立即播放。我不知道我们想要播放大约 10 个视频中的哪一个,直到该开始播放那个了。 ios-avplayer-video-preloading

想法 3:在后台加载、播放和保留 AVPlayerItems(还不能 100% 确定——但看起来不太好)

我正在研究在后台加载和播放每个视频剪辑的第一秒是否有任何好处(抑制视频和音频输出),并保留对每个 AVPlayerItem 的引用,以及当我们知道哪个项目需要真正播放,交换那个,并将背景 AVPlayer 与活动的交换。冲洗并重复。

理论上,最近播放的AVPlayer/AVPlayerItem 可能仍保留一些准备好的资源,这将使后续播放更快。到目前为止,我还没有看到这样做的好处,但我可能没有为背景正确设置AVPlayerLayer。我怀疑这真的会改善我所看到的情况。

想法 4:使用不同的文件格式——也许加载速度更快?

我目前正在使用 .m4v 的(视频-MPEG4)H.264 格式。 H.264 有很多不同的编解码器选项,因此某些选项可能比其他选项搜索得更快。我发现使用更高级的设置来减小文件大小会增加查找时间,但没有找到任何相反的选项。

思路五:无损视频格式+AVQueuePlayer的组合

如果有一种加载速度很快的视频格式,但文件大小可能很疯狂,一个想法可能是预先准备每个视频剪辑的前 10 秒,使用一个臃肿但加载速度更快的版本,但使用以 H.264 编码的资产来支持它。使用 AVQueuePlayer,并以未压缩的文件格式添加前 10 秒,然后使用 H.264 格式的文件,它可以获得长达 10 秒的准备/预加载时间。所以我会得到两全其美的“最好的”:快速启动时间,但也受益于更紧凑的格式。

想法 6:使用非标准的 AVPlayer/自己编写/使用别人的

鉴于我的需要,也许我不能使用 AVPlayer,但必须求助于 AVAssetReader,并在前几秒解码(可能将原始文件写入磁盘),在播放时,使用原始格式快速播放。对我来说似乎是一个巨大的项目,如果我以一种天真的方式去做,那就不清楚/不太可能做得更好。每个解码和未压缩的视频帧为 2.25 MB。天真地说——如果我们以大约 30 fps 的速度播放视频,我最终会得到大约 60 MB/s 从磁盘读取的要求,这可能是不可能的/推动它。显然,我们必须进行某种程度的图像压缩(也许是通过 PVRTC 的原生 openGL/es 压缩格式)......但这有点疯狂。也许那里有一个我可以使用的库?

想法 7:将所有内容合并到一个电影资产中,并 seekToTime

一个可能比上述一些更容易的想法是将所有内容组合成一个电影,并使用 seekToTime。问题是我们会到处乱跳。基本上是随机访问电影。我认为这实际上可以解决:avplayer-movie-playing-lag-in-ios5

您认为哪种方法最好?到目前为止,我在减少延迟方面没有取得太大进展。

【问题讨论】:

  • 对于它的价值,我将使用 Idea 7。它仍然很慢,但不像其他选项那样慢得不可预知。我的下一个问题是——编解码器选项、分辨率和关键帧频率对搜索时间有影响吗?
  • 游戏晚了,但可能值得尽快切换视频(即在新视频开始播放后立即)并分析应用程序以查看其大部分 CPU 时间花在哪里。
  • 快一年过去了,你发现了什么?
  • 我选择了选项 7,并在 300 毫秒到 500 毫秒之间找到了某个位置。我发现的一件事是 mp4 编解码器选项越漂亮, seekTo 越慢。有一些视频压缩选项可以实现更好的压缩并保持视频质量,但会缩短解码时间。
  • 这是一个合理的要求,但要真正实施选项 7,实施中的方面太多,无法发布。考虑:(a) 制作一个工具链来合并视频资产,(b) 确保跟踪视频片段偏移量,(c) 在请求播放特定剪辑时查找偏移量,(d) 使用 addPeriodicTimeObserverForInterval 来检查如果您播放视频剪辑并做出相应反应(使用此方法与单次 addBoundaryTimeObserverForTimes 相比,因为我发现后者有时不会触发......总的来说,这不适合粘贴代码。

标签: ios delay avplayer


【解决方案1】:

对于 iOS 10.x 及更高版本以减少 AVPlayer 启动延迟我设置: avplayer.automaticallyWaitsToMinimizeStalling = false; 这似乎为我解决了问题。这可能会产生其他后果,但我还没有达到这些后果。

我的想法来自: https://stackoverflow.com/a/50598525/9620547

【讨论】:

  • 延迟减少了 6-7 秒。但我有一个问题,它会影响应用性能吗?
  • @kalpa 我们已经在生产应用程序中使用此代码一年多了,没有任何明显的负面影响。我们主要向美国的听众播放 20-60 分钟的音频文件,那里的移动数据覆盖率通常很快。不过,您的用例可能会有所不同。
【解决方案2】:

资产可能在您创建后尚未准备好,它可能会进行电影时长等计算,请务必在文件中包含电影的所有元数据。

【讨论】:

    【解决方案3】:

    您应该先尝试选项 #7,看看您是否可以让它发挥作用。我怀疑它实际上无法满足您的需求,因为搜索时间可能不够快,无法让您在剪辑之间无缝切换。如果您尝试这样做但失败了,那么我建议您执行选项 4/6 并查看我专门为此目的设计的 iOS 库,只需在 AVAnimator 上进行快速谷歌搜索以了解更多信息。我的库可以实现无缝循环并从一个剪辑切换到另一个剪辑,它非常快,因为必须事先将视频解码成一个文件。在您的情况下,所有 10 个视频剪辑都会在您开始之前被解码为文件,但是在它们之间切换会很快。

    【讨论】:

    • 视频的音频部分怎么样?我需要同步视频和音频。
    • 是的,音频已经处理好,音轨和视频剪辑之间的同步非常紧密。请参阅示例 xcode 项目。已经全部实现了,你只需要下载试用一下。
    • 有没有可能用AVAnimator播放网络视频?
    • 不,它适用于本地文件,流式网络视频是完全不同的东西。
    【解决方案4】:

    过去没有做过类似的事情,根据您的想法和经验,我会尝试 7 和 1 的组合:在 10 个后续视频的前几秒预加载一个 AVPlayer。然后,由于数据较少,跳过很可能会更快、更可靠。在播放所选曲目时,您有足够的时间在后台为所选后续视频的其余部分准备 AVPlayer。开始完成后,切换到准备好的 AVPlayer。因此,总的来说,您在任何给定时间最多加载 2 个 AVPlayer。

    当然不知道能不能流畅的切换到不打扰播放。

    (如果可以的话,我会添加这个作为评论。)

    最好的,彼得

    【讨论】:

    • 我发现在一个 AVPlayer 上连续加载 10 个资产没有任何好处。此外,我不理解您的建议,因为我认为选项 (1) 和 (7) 相互排斥。选项 7 将所有视频资产合并为一个资产——因此只有一个资产要加载周期。这就是我今天正在做的事情,值得我在实际开始/播放时间上延迟大约 500 毫秒。值得注意的是,SeekTo 完成的速度比实际播放的第一帧要快,所以对于真正的开始时间,我通过定时回调测量第一帧实际播放的时间。
    • 只是为了说明我的想法:我的想法是将资产分成两部分:前几秒和其余部分。现在您已经从一项资产中获得了两项资产。您将加入并使用跳过的 10 个开头,在播放开头时您将加载其余部分。然后,这包括添加到您的列表中的建议 8。
    • 但正如我从您上次的评论中了解到的那样,同时您进一步推动了研究,这很好,解决方案 7 也没有奏效。看起来 AV 从根本上挡住了你的路,你唯一的出路可能是使用下面的技术,即 Core Media,来更好地控制你的资产。彼得。
    • 哦,我现在更理解你的想法了。谢谢。如果您获得短视频剪辑的快速搜索时间,调查一下会很有趣。我还没有尝试过,但值得考虑。关于核心媒体的使用——我在那个 API 上没有找到任何好的参考资料。你有好的资源可以指点我吗?
    • 不,抱歉。正如我所说,我不是 AV 或 Core Media 方面的专家。只需阅读您的问题,并对我个人将如何进行并想分享它们有一些想法。彼得
    【解决方案5】:

    如果我正确理解了您的问题,您似乎有一个连续的视频,您需要立即加载音轨。

    如果是这种情况,我建议查看BASS。 BASS 是一个类似于 AVPlayer 的音频库,它让您(相对)轻松地访问 iOS 中 AudioUnits 框架的低级 API。对你来说意味着什么?这意味着通过一点点缓冲区操作(您甚至可能不需要它,取决于您希望延迟多小),您就可以立即开始播放音乐。

    然而限制延伸到视频,正如我所说,它是一个音频库,所以任何视频操作仍然必须使用 AVPlayer 完成。但是,使用-seekToTime:toleranfeBefore:toleranceAfter:,您应该能够在视频中实现快速搜索,只要您预先设置所有必要的选项。

    如果您要跨多个设备进行同步(您的应用程序可能会建议),只需发表评论,我很乐意编辑我的答案。

    PS:BASS 乍一看可能会让人望而生畏,因为它是类似 C 的格式,但实际上它真的很容易使用。

    【讨论】:

      【解决方案6】:

      以下是 AVAsset 类提供的几个属性和方法,它们可能会有所帮助:

      - (void)_pu_setCachedDuration:(id)arg1;
      - (id)pu_cachedDuration; 
      - (struct
       { 
         long long x1; 
         int x2;
         unsigned int x3; 
         long long x4; 
      })pu_duration;
      - (void)pu_loadDurationWithCompletionHandler:(id /* block */)arg1;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-08-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-17
        • 2018-04-10
        • 1970-01-01
        • 2015-04-04
        相关资源
        最近更新 更多