如何减少iOS AVPlayer启动延迟


115

请注意,针对以下问题:所有资产在设备上都是本地的-不会进行网络流传输。视频包含音轨。

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

要查看实际的启动延迟,我要做的是调用addBoundaryTimeObserverForTimes视频播放器,其时间为一毫秒,以查看视频实际开始播放的时间,我将时间戳记与指示开始播放哪个资产的代码。

从目前为止我所看到的,我发现使用AVAsset加载的组合,然后AVPlayerItem在准备好之后从中创建一个,然后AVPlayerStatusReadyToPlay在调用播放之前等待,通常需要1-3秒才能开始夹。

从那以后,我切换到了我认为大致相等的位置:呼叫[AVPlayerItem playerItemWithURL:]并等待AVPlayerItemStatusReadyToPlay播放。大致相同的性能。

我观察到的一件事是,第一个AVPlayer项加载比其他项慢。似乎有一个想法是,在尝试播放第一个视频之前,先用空/空资产预播AVPlayer,这可能是一种很好的常规做法。[ 第一次播放声音时,AVAudioPlayer的启动缓慢

我希望尽可能缩短视频的开始时间,并且对要尝试的事情有一些想法,但希望有可能提供帮助的人提供一些指导。

更新:下面的想法7的实现产生了大约500 ms的切换时间。这是一个改进,但是最好更快地完成。

想法1:使用N个AVPlayers(无效)

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

我认为这行不通,因为我读过AVPlayer'siOS中的活动限制大约为4 。这里有人在StackOverflow上问这个问题,并发现了4 AVPlayer的限制:在视频之间使用avfoundation快速切换

想法2:使用AVQueuePlayer(无效)

我不相信,推搡10 AVPlayerItemsAVQueuePlayer会预载了他们全部无缝启动。 AVQueuePlayer是一个队列,我认为它实际上只能使队列中的下一个视频准备好立即播放。我不知道要播放约10个视频中的哪个,直到该开始播放为止。ios-AVplayer视频预加载

理念3:加载,播放和保留AVPlayerItems背景(尚未100%确定-效果并不理想)

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

从理论上讲,最近播放AVPlayer/AVPlayerItem的可能仍会保留一些准备好的资源,从而可以加快后续播放的速度。到目前为止,我还没有看到任何好处,但是我可能没有AVPlayerLayer正确设置背景。我怀疑这是否真的会改善我所看到的情况。

想法4:使用其他文件格式-也许是加载速度更快的文件格式?

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

理念5:无损视频格式+ 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

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


对于它的价值,我将使用Idea7。它仍然很慢,但没有其他选项那么慢。我的下一个问题是-编解码器选项,分辨率和关键帧频率是否会影响seekto时序?
Bernt Habermeier 2012年

游戏晚了,但值得尽快切换视频(即在新视频开始播放后立即切换),并对应用程序进行性能分析以了解它在大部分CPU时间上所花费的时间。
tc。

1
差不多一年后的今天,您从中发现了什么?
lnafziger 2013年

1
我选择了选项7,到达了300ms至500ms的搜索距离。我发现的一件事是,mp4编解码器选项越高级,seekTo越慢。有一些视频压缩选项可以实现更好的压缩并保持视频质量,但会缩短解码时间。
Bernt Habermeier 2013年

2
这是一个合理的要求,但实际上要实现选项7,实现中涉及的面太多。考虑:(a)创建一个工具链来合并视频资产,(b)确保跟踪视频片段偏移,(c)当请求播放特定剪辑时查找偏移,(d)使用addPeriodicTimeObserverForInterval检查如果你跑了视频剪辑,并作出相应的反应(使用此方法与单次addBoundaryTimeObserverForTimes,因为我已经找到了后者有时不触发......总之,这本身不适合于粘贴代码。
伯恩特Habermeier

Answers:


4

对于iOS 10.x及更高版本,为了减少AVPlayer启动延迟,我设置了: avplayer.automaticallyWaitsToMinimizeStalling = false; 这似乎为我解决了。这可能会带来其他后果,但我还没有实现。

我从以下地方得到了这个主意:https : //stackoverflow.com/a/50598525/9620547


我减少了6-7秒的延迟。但是我在这里有一个问题,这会对应用程序性能产生影响吗?
kalpa

@kalpa我们在生产应用程序中使用此代码已有一年多了,没有任何明显的负面影响。在美国,我们通常会向听众播放20-60分钟的音频文件,而移动数据的覆盖范围通常很快。您的用例可能会有所不同。
灰熊

谢谢(你的)信息。@grizzb
kalpa

1

一旦创建资产,资产可能尚未准备就绪,它可能会进行计算,例如电影的持续时间,请确保在文件中包含电影的所有元数据。


1

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


视频的音频部分呢?我需要视频和音频进行同步。
Bernt Habermeier

是的,已经在音频轨道和视频片段之间非常紧密地同步处理了音频。请参阅示例xcode项目。它已经全部实现,您只需要下载并试用即可。
MoDJ

是否可以使用AVAnimator播放网络视频?
理查德·托普奇伊

不,它适用于本地文件,流式网络视频是完全不同的东西。
MoDJ

0

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

当然,我不知道切换是否可以如此平稳地进行,以至于不会干扰播放。

(如果可以的话,将其添加为评论。)

最好,彼得


我发现在一个AVPlayer上连续加载10个资产没有好处。此外,我不理解您的建议,因为我看到选项(1)和(7)是互斥的。选项7将所有视频资产合并为一个资产-因此,只有一个资产需要加载。这就是我今天要做的,而且值得的是,我在实际的开始/播放时间上大约延迟了500毫秒。值得注意的是,SeekTo的完成速度比实际第一帧的播放速度快,因此对于真实的开始时间,我通过定时回调来测量第一帧的实际播放时间。
Bernt Habermeier 2012年

为了使我的想法更清楚:我的想法是将资产分为两个部分:前几秒钟和其余部分。现在您已经从一项资产中提取了两项。您将加入10个开始,并使用“跳过”,在播放开始时将加载其余的。然后包含建议8,该建议会添加到您的列表中。
ilmiacs 2012年

但是据我从您的最后评论中了解到,与此同时,您进一步推动了研究,这是好的,解决方案7也不可行。看来,AV根本就不会影响您,唯一可行的方法可能是使用底层技术,即Core Media,以获得对资产的更多控制权。彼得
ilmiacs 2012年

哦,我现在更了解你的想法了。谢谢。调查短视频片段的快速搜索时间是否有趣。我还没有尝试过,但是值得考虑。关于核心媒体的使用-我在该API上找不到任何好的参考资料。您有什么好资源可以指点我吗?
Bernt Habermeier 2012年

不,谢谢。正如我所说,我不是AV或Core Media的专家。只需阅读您的问题,并对我个人将如何进行并想分享它们有一些想法。彼得
ilmiacs 2012年

0

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

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

但是,限制已扩展到视频,正如我所说,它是一个音频库,因此仍然必须使用AVPlayer进行任何视频操作。但是-seekToTime:toleranfeBefore:toleranceAfter:,只要您预滚动了所有必要的选项,使用就能在视频中快速搜索。

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

PS:BASS乍一看可能令人生畏,因为它类似于C格式,但实际上使用起来非常简单。


-2

这是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;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.