ios 如何减少iOS AVPlayer启动延迟
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11171374/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to reduce iOS AVPlayer start delay
提问by Bernt Habermeier
Note, for the below question: All assets are local on the device -- no network streaming is taking place. The videos contain audio tracks.
请注意,对于以下问题:所有资产都在设备本地 - 没有发生网络流。视频包含音轨。
I'm working on an iOS application that requires playing video files with minimum delay to start the video clip in question. Unfortunately we do not know what specific video clip is next until we actually need to start it up. Specifically: When one video clip is playing, we will know what the next set of (roughly) 10 video clips are, but we don't know which one exactly, until it comes time to 'immediately' play the next clip.
我正在开发一个 iOS 应用程序,该应用程序需要以最小延迟播放视频文件才能启动有问题的视频剪辑。不幸的是,在我们真正需要启动它之前,我们不知道接下来是什么特定的视频剪辑。具体来说:当一个视频剪辑正在播放时,我们将知道下一组(大约)10 个视频剪辑是什么,但我们不知道究竟是哪一个,直到“立即”播放下一个剪辑。
What I've done to look at actual start delays is to call addBoundaryTimeObserverForTimes
on the video player, with a time period of one millisecond to see when the video actually started to play, and I take the difference of that time stamp with the first place in the code that indicates which asset to start playing.
我为查看实际开始延迟所做的工作是调用addBoundaryTimeObserverForTimes
视频播放器,以一毫秒的时间段查看视频实际开始播放的时间,然后我将该时间戳记与第一个位置的差值指示开始播放哪个资产的代码。
From what I've seen thus-far, I have found that using the combination of AVAsset
loading, and then creating an AVPlayerItem
from that once it's ready, and then waiting for AVPlayerStatusReadyToPlay
before I call play, tends to take between 1 and 3 seconds to start the clip.
从到目前为止我所看到的情况来看,我发现使用AVAsset
加载的组合,然后AVPlayerItem
在准备好后从中创建一个,然后AVPlayerStatusReadyToPlay
在我调用播放之前等待,往往需要 1 到 3 秒来启动夹子。
I've since switched to what I think is roughly equivalent: calling [AVPlayerItem playerItemWithURL:]
and waiting for AVPlayerItemStatusReadyToPlay
to play. Roughly same performance.
从那以后,我转向了我认为大致相同的内容:打电话[AVPlayerItem playerItemWithURL:]
并等待AVPlayerItemStatusReadyToPlay
比赛。表现大致相同。
One thing I'm observing is that the first AVPlayer item load is slower than the rest. Seems one idea is to pre-flight the AVPlayer with a short / empty asset before trying to play the first video might be of good general practice. [Slow start for AVAudioPlayer the first time a sound is played
我观察到的一件事是第一个 AVPlayer 项目加载比其他项目慢。似乎一个想法是在尝试播放第一个视频之前使用短/空资产预检 AVPlayer 可能是一种很好的一般做法。[第一次播放声音时,AVAudioPlayer 启动缓慢
I'd love to get the video start times down as much as possible, and have some ideas of things to experiment with, but would like some guidance from anyone that might be able to help.
我很想尽可能缩短视频的开始时间,并有一些可以尝试的想法,但希望得到任何可能提供帮助的人的指导。
Update: idea 7, below, as-implemented yields switching times of around 500 ms. This is an improvement, but it it'd be nice to get this even faster.
更新:下面的想法 7 实现后的切换时间约为 500 毫秒。这是一个改进,但如果能更快地获得它会很好。
Idea 1: Use N AVPlayers (won't work)
想法 1:使用 N 个 AVPlayer(不起作用)
Using ~ 10 AVPPlayer
objects and start-and-pause all ~ 10 clips, and once we know which one we really need, switch to, and un-pause the correct AVPlayer
, and start all over again for the next cycle.
使用 ~ 10 个AVPPlayer
对象并开始并暂停所有 ~ 10 个剪辑,一旦我们知道我们真正需要哪个剪辑,切换到正确的 并取消暂停AVPlayer
,然后重新开始下一个循环。
I don't think this works, because I've read there is roughly a limit of 4 active AVPlayer's
in iOS. There was someone asking about this on StackOverflow here, and found out about the 4 AVPlayer limit: fast-switching-between-videos-using-avfoundation
我不认为这行得通,因为我读过AVPlayer's
iOS 中大约有 4 个活动限制。有人在 StackOverflow 上问过这个问题,发现了 4 个 AVPlayer 限制:fast-switching-between-videos-using-avfoundation
Idea 2: Use AVQueuePlayer (won't work)
想法 2:使用 AVQueuePlayer(不起作用)
I don't believe that shoving 10 AVPlayerItems
into an AVQueuePlayer
would pre-load them all for seamless start. AVQueuePlayer
is a queue, and I think it really only makes the next video in the queue ready for immediate playback. I don't know which one out of ~10 videos we do want to play back, until it's time to start that one. ios-avplayer-video-preloading
我不相信将 10 个推AVPlayerItems
入一个AVQueuePlayer
会预加载它们以实现无缝启动。 AVQueuePlayer
是一个队列,我认为它实际上只会使队列中的下一个视频准备好立即播放。我不知道我们想要播放大约 10 个视频中的哪一个,直到开始播放那个视频。ios-avplayer-video-preloading
Idea 3: Load, Play, and retain AVPlayerItems
in background (not 100% sure yet -- but not looking good)
想法 3:AVPlayerItems
在后台加载、播放和保留(还不是 100% 确定——但看起来不太好)
I'm looking at if there is any benefit to load and play the first second of each video clip in the background (suppress video and audio output), and keep a reference to each AVPlayerItem
, and when we know which item needs to be played for real, swap that one in, and swap the background AVPlayer with the active one. Rinse and Repeat.
我正在研究在后台加载和播放每个视频剪辑的第一秒是否有任何好处(抑制视频和音频输出),并保留对每个AVPlayerItem
,以及何时需要播放哪个项目的引用真实的,交换那个,然后用活动的 AVPlayer 交换背景 AVPlayer。冲洗并重复。
The theory would be that recently played AVPlayer/AVPlayerItem
's may still hold some prepared resources which would make subsequent playback faster. So far, I have not seen benefits from this, but I might not have the AVPlayerLayer
setup correctly for the background. I doubt this will really improve things from what I've seen.
理论上,最近播放AVPlayer/AVPlayerItem
的 s 可能仍然持有一些准备好的资源,这将使后续播放速度更快。到目前为止,我还没有看到这样做的好处,但我可能没有AVPlayerLayer
正确设置背景。我怀疑这真的会改善我所看到的情况。
Idea 4: Use a different file format -- maybe one that is faster to load?
想法 4:使用不同的文件格式——也许是一种加载速度更快的格式?
I'm currently using .m4v's (video-MPEG4) H.264 format. H.264 has a lot of different codec options, so it's possible that some options are faster to seek than others. I have found that using more advanced settings that make the file size smaller increase the seek time, but have not found any options that go the other way.
我目前使用 .m4v 的(视频-MPEG4)H.264 格式。H.264 有很多不同的编解码器选项,因此某些选项的搜索速度可能比其他选项更快。我发现使用更高级的设置来缩小文件大小会增加查找时间,但没有找到任何相反的选项。
Idea 5: Combination of lossless video format + AVQueuePlayer
思路五:无损视频格式+AVQueuePlayer的组合
If there is a video format that is fast to load, but maybe where the file size is insane, one idea might be to pre-prepare the first 10 seconds of each video clip with a version that is bloated but faster to load, but back that up with an asset that is encoded in H.264. Use an AVQueuePlayer, and add the first 10 seconds in the uncompressed file format, and follow that up with one that is in H.264 which gets up to 10 seconds of prepare/preload time. So I'd get 'the best' of both worlds: fast start times, but also benefits from a more compact format.
如果有一种视频格式加载速度很快,但可能文件大小很疯狂,一个想法可能是预先准备每个视频剪辑的前 10 秒,使用一个臃肿但加载速度更快的版本,但返回这与以 H.264 编码的资产有关。使用 AVQueuePlayer,并在未压缩文件格式中添加前 10 秒,然后使用 H.264 格式的播放器,它最多可获得 10 秒的准备/预加载时间。所以我会得到两全其美的“最佳”:快速启动时间,但也受益于更紧凑的格式。
Idea 6: Use a non-standard AVPlayer / write my own / use someone else's
想法6:使用非标准的AVPlayer/自己写/使用别人的
Given my needs, maybe I can't use AVPlayer, but have to resort to AVAssetReader, and decode the first few seconds (possibly write raw file to disk), and when it comes to playback, make use of the raw format to play it back fast. Seems like a huge project to me, and if I go about it in a naive way, it's unclear / unlikely to even work better. Each decoded and uncompressed video frame is 2.25 MB. Naively speaking -- if we go with ~ 30 fps for the video, I'd end up with ~60 MB/s read-from-disk requirement, which is probably impossible / pushing it. Obviously we'd have to do some level of image compression (perhaps native openGL/es compression formats via PVRTC)... but that's kind crazy. Maybe there is a library out there that I can use?
考虑到我的需求,可能我不能用AVPlayer,只能求助于AVAssetReader,把前几秒解码(可能是把raw文件写到磁盘),播放的时候用raw格式播放快回来。对我来说似乎是一个巨大的项目,如果我以天真的方式进行,则不清楚/不太可能更好地工作。每个解码和未压缩的视频帧为 2.25 MB。天真地说——如果我们为视频采用约 30 fps 的速度,我最终会得到约 60 MB/s 的磁盘读取要求,这可能是不可能的/推动它。显然,我们必须进行某种程度的图像压缩(也许是通过 PVRTC 的原生 openGL/es 压缩格式)……但这有点疯狂。也许那里有一个我可以使用的图书馆?
Idea 7: Combine everything into a single movie asset, and seekToTime
想法 7:将所有内容合并为一个电影资产,然后seekToTime
One idea that might be easier than some of the above, is to combine everything into a single movie, and use seekToTime. The thing is that we'd be jumping all around the place. Essentially random access into the movie. I think this may actually work out okay: avplayer-movie-playing-lag-in-ios5
一个可能比上述一些更容易的想法是将所有内容组合成一部电影,并使用seekToTime。问题是我们会到处跳来跳去。基本上是随机访问电影。我认为这实际上可以解决问题:avplayer-movie-playing-lag-in-ios5
Which approach do you think would be best? So far, I've not made that much progress in terms of reducing the lag.
您认为哪种方法最好?到目前为止,我在减少延迟方面还没有取得太大进展。
回答by grizzb
For iOS 10.x and greater to reduce AVPlayer start delay I set:
avplayer.automaticallyWaitsToMinimizeStalling = false;
and that seemed to fix it for me. This could have other consequences, but I haven't hit those yet.
对于 iOS 10.x 及更高版本以减少我设置的 AVPlayer 启动延迟:
avplayer.automaticallyWaitsToMinimizeStalling = false;
这似乎为我解决了这个问题。这可能会产生其他后果,但我还没有达到这些后果。
I got the idea for it from: https://stackoverflow.com/a/50598525/9620547
回答by nova
The asset may not ready once you create it, it may does calculations like duration of movie, be sure to contain all metadata of the movie in the file.
资产可能在您创建后还没有准备好,它可能会进行电影时长等计算,请确保在文件中包含电影的所有元数据。
回答by MoDJ
You should try option #7 first, just to see if you can get that working. I suspect that it will not actually work for your needs since the seek time will likely not be fast enough to give you seamless switching between clips. If you try that and it fails, then I would advise that you do option 4/6 and take a look at my iOS library designed specifically for this purpose, just do a quick google search on AVAnimator to find out more. My library makes it possible to implement seamless loops and switching from one clip to another, it is very fast because video has to be decoded into a file before hand. In your case, all 10 video clips would get decoded into files before you begin, but then switching between them would be fast.
您应该先尝试选项 #7,看看您是否可以使其正常工作。我怀疑它实际上不能满足您的需求,因为搜索时间可能不够快,无法在剪辑之间无缝切换。如果您尝试这样做但失败了,那么我建议您执行选项 4/6 并查看我专门为此目的设计的 iOS 库,只需在 AVAnimator 上进行快速谷歌搜索即可了解更多信息。我的库可以实现无缝循环并从一个剪辑切换到另一个剪辑,速度非常快,因为必须事先将视频解码为文件。就您而言,在您开始之前,所有 10 个视频剪辑都会被解码为文件,但随后在它们之间切换会很快。
回答by ilmiacs
Without having done anything like this in the past, based on your thoughts and experiences I would try a combination of 7 and 1: Preload one AVPlayer with the first couple of seconds of the 10 follow up videos. Then skipping will very likely be faster and more reliable due to less data. While you are playing the selected piece, you have enough time to prepare the AVPlayer for the rest of the selected follow up video in the background. When the beginning is finished, you switch to the prepared AVPlayer. So in total, you at any given time have a maximum of 2 AVPlayers loaded.
过去没有做过这样的事情,根据你的想法和经验,我会尝试 7 和 1 的组合:在 10 个后续视频的前几秒钟预加载一个 AVPlayer。由于数据较少,因此跳过很可能会更快、更可靠。在播放所选片段时,您有足够的时间为 AVPlayer 在后台为所选后续视频的其余部分做好准备。开始完成后,您切换到准备好的 AVPlayer。所以总的来说,您在任何给定时间最多加载 2 个 AVPlayer。
Of course I don't know whether the switching can be done so smoothly that it does not disturb playback.
当然不知道切换能不能流畅到不干扰播放。
(Would have added this as a comment if I could.)
(如果可以的话,我会将此添加为评论。)
Best, Peter
最好的,彼得
回答by donkey
If I understood your issue correctly, it seems that you have one continuous video to which you need to load the audio track for on a moment's notice.
如果我正确理解您的问题,那么您似乎有一个连续的视频,您需要立即加载音轨。
If that is the case I suggest looking into BASS. BASS is an audio library much like AVPlayer that gives you (relatively) easy access to the low-level API's of the AudioUnits framework in iOS. What does the mean for you? It means that with a tiny bit of buffer manipulation (you may not even need it, depends on how tiny you want the delay) you can start playing music instantly.
如果是这种情况,我建议研究BASS。BASS 是一个很像 AVPlayer 的音频库,它让您(相对)轻松地访问 iOS 中 AudioUnits 框架的低级 API。这对你来说意味着什么?这意味着通过一点点缓冲区操作(您甚至可能不需要它,这取决于您想要延迟的程度)您可以立即开始播放音乐。
The limitations however extend to video, as I said, it is an audiolibrary so any video manipulation will still have to be done with AVPlayer. However using-seekToTime:toleranfeBefore:toleranceAfter:
you should be able to achieve fast seeking within the video as long as you preroll with all the necessary options.
然而,限制扩展到视频,正如我所说,它是一个音频库,因此任何视频操作仍然必须使用 AVPlayer 完成。但是-seekToTime:toleranfeBefore:toleranceAfter:
,只要您预卷了所有必要的选项,您就应该能够在视频中实现快速搜索。
If you're syncing across multiple devices (which your application might suggest) just leave a comment and I'd be happy to edit my answer.
如果您要跨多个设备(您的应用程序可能会建议)进行同步,请发表评论,我很乐意编辑我的答案。
PS: BASS may look daunting at first because of it's C-like format, but it's really really easy to use for what it is.
PS:BASS 起初可能看起来令人生畏,因为它是类似 C 的格式,但它真的很容易使用。
回答by James Bush
Here are several properties and methods provided by the AVAsset class that may help:
以下是 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;