请注意,对于以下问题:所有资产都是设备上的本地资产 - 没有网络流媒体正在发生.视频包含音轨.
我正在开发一个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's
iOS中大约有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.问题是我们会四处奔跑.基本上随机访问电影.我认为这可能实际上没问题: …
我在viewDidLoad中设置了一个AVAudioPlayer对象,根据Apple指南,将prepareToPlay称为viewDidLoad中的最后一行(我也尝试过awakeFromNib).
当我按下我的播放按钮时,有一个暂停,因为它似乎加载文件,然后播放.
在audioPlayerDidFinishPlaying中,我用不同的声音重新加载播放器,当再次单击播放时,文件立即播放.
什么会导致玩家在第一场比赛中落后?
谢谢.
这个问题已经出现在其他几个问题中:
我已尝试实施建议的修复,但没有一个能解决我的问题。我的应用程序向用户呈现一系列可供触摸的对象,当触摸对象时会播放声音。除了初始触摸时有约 2 秒的延迟之外,此功能非常有效。
为了解决这个问题,我使用虚拟 aiff 文件初始化音频播放器:
- (void)viewDidLoad{
NSString *soundFile = [Card loadCardSoundPath:@"dummy"];
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:
[NSURL fileURLWithPath:soundFile] error:nil];
self.audioPlayer = player;
[audioPlayer setDelegate:self];
[audioPlayer prepareToPlay];
// [audioPlayer play];
[player release];
...
[super viewDidLoad];
}
Run Code Online (Sandbox Code Playgroud)
然后当触摸一个物体时我调用:
NSString *soundFile = [Card loadCardSoundPath:name];
if (soundFile != nil){
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:
[NSURL fileURLWithPath:soundFile] error:nil];
self.audioPlayer = player;
[self.audioPlayer setDelegate:self];
[self.audioPlayer prepareToPlay];
[self.audioPlayer play];
[player release];
}
Run Code Online (Sandbox Code Playgroud)
我观察到的行为是这样的:如果我创建一个虚拟音频播放器并调用prepareToPlay但不播放,那么当我单击第一个对象时,我会观察到音频延迟。但是,如果我在虚拟音频播放器上调用 play,那么我不会得到初始对象的延迟,但视图加载会延迟 2 秒。 …
我正在使用AVAssetReader读取ipod库资产音频数据并渲染波形图像.这是使用我在回答这个问题时所描述的代码进行的
这有时会发生在AVAudioPlayer实例播放音频的时候.
无论播放的音频是否与正在阅读的资产相同,我点击的那一刻
[reader startReading];
Run Code Online (Sandbox Code Playgroud)
播放的音频"淡出".(好像AVAudioPlayer已被告知停止播放).这很奇怪,因为我实际上并没有播放音频,只是阅读它.
我在SO上搜索并找到了这个可能的解决方案但是我发现这似乎没有解决问题.
注意 - 我能够播放几个AVAudioPlayer实例,并且启动这些实例似乎并没有相互干扰 - 但是
[reader startReading];
Run Code Online (Sandbox Code Playgroud)
甚至会杀死AVAudioPlayer的多个同时实例,导致它们全部同步淡出.
有任何想法吗?
是否有可能AVAudioPlayer
在通话后知道何时准备就绪prepareToPlay
?
如果没有,是否还有其他类提供此功能?
我想实现这样的事情:
- (void) prepare {
[audioPlayer prepareToPlay];
// Update UI to indicate that the audio is being prepared
}
- (void) onAudioReady {
// Update UI to indicate that the audio is ready
}
Run Code Online (Sandbox Code Playgroud) 嗨!
我正在使用GCD构建一个计时器,以便以特定的间隔播放声音,更准确地说,它是一个节拍器声音.我一直在努力解决我的问题,但没有.一切都很好但是当我把我的节奏设置为更大的值时,让我们说150 bpm或200 bpm,当声音第一次开始时,它会很快发射(几乎像两个声音在同一时间意味着它没有预期间隔)并在此之后,它进行校准.我第二次启动声音,一切都很好......所以这只发生在我第一次恢复调度源时所以我猜它与从磁盘加载声音有关,就像在这篇帖子中一样:慢第一次播放声音时启动AVAudioPlayer.对于我的声音我在第一次的实例中使用AVAudioPlayer
与prepareToPlay
并且play
还在AppDelegate类中创建它,它还没有工作......我甚至尝试过@NickLockwood开发的SoundManager类,同样的问题.目前,我正在使用SystemSoundID
.至于计时器,这是我的第一个GCD计时器,我已经尝试了经典的NSTimer
,CADisplayLink
以及在git上找到的其他计时器...都是徒劳的.
另一个有趣的问题是,与其他计时器一样,在模拟器上一切都很完美,但在设备上却出现了同样的故障.
这是代码,我希望有人能把我带到光明之中.
-(void)playButtonAction //
{
if (_metronomeIsAnimatingAndPLaying == NO)
{
[self startAnimatingArm]; // I start my animation and create my timer
metronomeTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
dispatch_source_set_timer(metronomeTimer,dispatch_time(DISPATCH_TIME_NOW, duration * NSEC_PER_SEC),duration * NSEC_PER_SEC,duration *NSEC_PER_SEC);
dispatch_source_set_event_handler(metronomeTimer, ^{[self playTick];});
dispatch_resume(metronomeTimer);
_metronomeIsAnimatingAndPLaying = YES;
}
}
-(void)playTick
{
AudioServicesPlaySystemSound(appDeleg.soundID); // soundID is created in appDelegate
}
Run Code Online (Sandbox Code Playgroud)
在我的应用程序didFinishLaunching
NSString *path = [[NSBundle mainBundle] pathForResource:@"tick"
ofType:@"caf"]; …
Run Code Online (Sandbox Code Playgroud) ios ×3
audio ×2
delay ×2
ios4 ×2
iphone ×2
avplayer ×1
core-audio ×1
lag ×1
objective-c ×1
timing ×1