【发布时间】: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 相比,因为我发现后者有时不会触发......总的来说,这不适合粘贴代码。