请注意,对于以下问题:所有资产都是设备上的本地资产 - 没有网络流媒体正在发生.视频包含音轨.
我正在开发一个iOS应用程序,它需要播放视频文件,延迟时间最短才能启动相关视频剪辑.不幸的是,在我们真正需要启动之前,我们不知道下一个具体的视频剪辑.具体来说:当播放一个视频片段时,我们将知道下一组(大约)10个视频片段是什么,但我们不知道究竟是哪一个,直到"立即"播放下一个片段为止.
我看到实际启动延迟的做法是调用addBoundaryTimeObserverForTimes视频播放器,时间段为1毫秒,以查看视频实际开始播放的时间,并且我将该时间戳与第一个时间戳区别开来.指示开始播放哪个资产的代码.
从我迄今为止看到的情况来看,我发现使用AVAsset加载的组合,然后AVPlayerItem在它准备就绪之后创建一个,然后AVPlayerStatusReadyToPlay在我调用play之前等待,往往需要1到3秒才能启动夹.
我已经切换到我认为大致相同的东西:打电话[AVPlayerItem playerItemWithURL:]等待AVPlayerItemStatusReadyToPlay比赛.大致相同的性能.
我观察到的一件事是第一个AVPlayer项目加载比其余项目慢.似乎有一个想法是在尝试播放第一个视频之前用短/空资产预先飞行AVPlayer可能是一个很好的通用做法.[ AVAudioPlayer第一次播放声音时启动缓慢
我希望尽可能地缩短视频开始时间,并且有一些可以尝试的东西的想法,但是希望得到任何可能提供帮助的人的指导.
更新:下面的想法7,实施时产生大约500毫秒的切换时间.这是一个改进,但它更快更好.
想法1:使用N AVPlayers(不起作用)
使用~10个AVPPlayer对象并启动和暂停所有~10个剪辑,一旦我们知道我们真正需要哪个,切换到并取消暂停正确AVPlayer,并在下一个循环中重新开始.
我认为这不起作用,因为我已经读过AVPlayer'siOS中大约有4个活动限制.这里有人在StackOverflow上询问这个问题,并发现了4个AVPlayer限制:快速切换 - 视频 - 使用 - 基础
想法2:使用AVQueuePlayer(不起作用)
我不相信将10推AVPlayerItems入一个AVQueuePlayer会预加载它们以便无缝启动. 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.问题是我们会四处奔跑.基本上随机访问电影.我认为这可能实际上没问题: …
我想在云中运行一个庞大的节点集群(AWS,Heroku,或者可能是自我管理的VMS),其时钟必须与预定义的容差同步.我正在寻找可能200毫秒的容差.这意味着如果我有250个节点,250个节点中任何一个节点之间的最大时钟差异不应超过200毫秒.我真的不关心世界的实际日期/时间.解决方案必须是容错的,并且不需要依赖任何一个系统的时钟精度 - 实际上,很可能没有一个时钟会非常准确.
要求足够强大,如果由于任何原因确定时钟同步对于任何特定节点不可靠,我宁愿由于时钟失步而从集群中丢弃节点 - 所以在任何可疑的故障时,我都会喜欢能够执行该节点的某种类型的受控关闭.
我喜欢使用类似NTP的东西,但根据NTP 已知问题twiki:
NTP不是为在虚拟机内部运行而设计的.它需要一个高分辨率的系统时钟,响应时间到时钟中断,并以高精度提供服务.没有已知的虚拟机能够满足这些要求.
虽然然后同样的twiki描述了解决这种情况的各种方法(例如在主机操作系统上运行ntp),但我不相信我能够使用AWS或者horoku来修改环境以符合解决方法.
即使我没有在VM中运行,一位拥有多年运行ntp经验的值得信赖的运营经理告诉我,由于每隔一段时间内本地时钟漂移不良,ntp可以并且会丢失同步(或者说得失时间).它不会经常发生,但确实会发生,并且随着您增加机器,您会增加发生这种情况的机会.AFAIK,检测你的距离需要停止ntpd,运行查询模式命令,然后重新启动它,并且可能需要很长时间才能得到答案.
总结一下 - 我需要一个时钟同步,其主要目标如下:
从描述来看,似乎伯克利算法可能是正确的选择,但是它已经实现了吗?
很高兴有:
我有两种方法(一种用于音频,一种用于视频),它们通过各自的AVAssetWriterInput将它们各自的样本附加到AVAssetWriter.一切都适用于简单的启动和停止案例.这里的一些背景是音频流来自coreAudio,我已应用回声抑制,而视频输入来自AVCaptureVideoDataOutputSampleBufferDelegate,通过setSampleBufferDelegate从AVCaptureVideoDataOutput提供.
问题是当我想暂停录制,然后重新开始重新编码时,会对源的音频和视频部分发生不同的事情.到目前为止,我一直无法在暂停恢复后保持音频和视频同步.
看来,当通过appendSampleBuffera附加音频样本数据时,即使CMSampleBufferRef具有准确的时间戳,它似乎也没有"跳过"没有样本的时间段.我的意思是,当附加音频样本时,它并不关心CMSampleBuffer上的时间戳是什么......它只是不断地将样本背靠背堆积,即使有(例如)120秒音频数据中的差距,它不会为它创造一个"空白空间".
我坦率地不在乎,只要视频样本的行为是相同的(但事实并非如此).对于视频样本,得到的视频编码确实跳过了样本,尽管它在没有数据的时间段内产生了延长的空视频帧.
因此,从一个简单的实现,在暂停期间,您会在暂停期间获得一个空白视频部分,但对于音频部分,您将获得下一个未暂停部分的样本背靠背.这意味着暂停和取消暂停(通过抑制向avasset写入器添加缓冲区数据)会导致音频和视频之间完全失步.
我试过的补救措施:
使用CMSetAttachment()设置kCMSampleBufferAttachmentKey_FillDiscontinuitiesWithSilence - 对于音频通道,希望它能像视频流那样做.这根本没有效果.我可能做错了,但没有关于此的真实文档,所以在这个黑暗中拍摄.
在"暂停"的受影响持续时间内添加我自己的空样本(通过appendLapsedAudiotime).问题是我不认为我的缓冲区是正确的,而且我不清楚是否可以添加一个只有0或1个样本的音频缓冲区,并在很长一段时间内将其拉长.如果我也可以将音频缓冲区格式更改为在整个暂停期间执行1个样本,但是下游低级API将不太喜欢不稳定的采样率设置.
使用CMSampleBufferCreateCopyWithNewTiming()更改视频的呈现时间,以符合音频的行为.这证明既不稳定,也没有用.我对此进行了多次迭代,包括调整音频和视频的时间戳.这可能是我在那里犯了错误,但考虑到没有文件,我对这种方法也是盲目的.
使用多个startSessionAtSourceTime/endSessionAtSourceTime以及在暂停状态期间抑制写入示例,但这不起作用,实际上Apples头文件中的注释警告您不支持此操作(与其在线文档相反):注意:目前不支持多个样本编写会话.调用startSessionAtSourceTime是一个错误:在调用endSessionAtSourceTime后第二次:
所以我的下一个方法是创建多个AVAssets.当有一个"暂停开始"时,我将完成录音,当有"暂停"时,我将开始一个全新的录音,当完成所有操作后,我将使用AVAssetComposition来将它们全部重新组合在一起.我对这种方法感到有些紧张,因为我发现在设置新的av捕获时,快速av捕获停止并开始在各个地方出现无法解释的故障.在尝试开始新的av捕获之前,我可能不得不强制"取消暂停"等待一段时间.
所以问题是......有更好的方式吗?