sti*_*ggs 5 macos cocoa avfoundation
我的视频播放器遇到了一个奇怪的情况,其核心代码与我之前制作的应用程序中的功能没有太大变化.这是问题所在:我正在插入一个"_loadingLayer"(一个说明视频正在加载的CATextLayer),然后观察AVPlayer的currentItem的status属性以确定何时删除"_loadingLayer"并将其替换为我的实际"_playerLayer" .这是我的KVO代码:
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ((object == _playerLayer) && (_playerLayer.player.currentItem.status == AVPlayerItemStatusReadyToPlay)) {
[CATransaction setAnimationDuration:1.8];
_loadingLayer.opaque = NO;
if (_playerLayer.readyForDisplay) {
NSLog(@"Should be ready now.");
}
[self addPlayerLayerToLayerTree];
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是视频正在启动,但只播放音频 - 图层保持黑色.当我在上面插入NSLog语句时,我发现了原因:显然虽然currentItem的状态是"AVPlayerItemStatusReadyToPlay",但是播放器层实际上并不是readyForDisplay.这对我来说毫无意义 - 这似乎违反直觉.有人可以给我一些指导吗?
通过将其背景颜色设置为红色,我能够验证是否正在将_playerLayer添加到图层树中.
我认为另一个奇怪的事情可能是相关的....我在调试器控制台中看到了这些消息:
PSsetwindowlevel,错误设置窗口级别(1000)CGSSetIgnoresCycle:错误1000设置或清除窗口标记
提前致谢.这是Apple Dev论坛的一个交叉点.
我们遇到了类似的问题,并将其追溯到我认为是 iOS 5.1(可能还有更早版本)中的错误。它已在 iOS 6.0 中修复。由于我无法在任何地方找到解决方案,因此我正在为未来遇到此问题的人写一篇长篇文章。
如果 AVPlayerItem 在获得 AVPlayerLayer 之前报告了 AVPlayerStatusReadyToPlay 的状态,那么 AVPlayer 将永远不会报告它是 readyForDisplay。
所以当你这样做时:
self.player = [AVPlayer playerWithPlayerItem:self.playerItem];
Run Code Online (Sandbox Code Playgroud)
确保后面跟着:
self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
Run Code Online (Sandbox Code Playgroud)
并且如果两者之间有任何代码,则您没有太多代码。
我建立了一个测试台,让它在 100% 的时间内工作或在 100% 的时间内失败。请注意,查看实际应用程序中发生的事情可能会很棘手,因为视频加载时间不同,这将影响 playerItem 报告 AVPlayerStatusReadyToPlay 的速度。
如果您想在您的应用程序中进行测试,请将其放入一个简单的视图中。以下在 iOS 5.1 上不起作用(即您会听到音频但看不到视频)。如果您将 loadPlayerLayer 切换为在 loadPlayer 结束时调用,它将始终有效。
未来读者的后续:一些玩家事件可以改变这个顺序,让你认为它是有效的。他们是红鲱鱼,因为他们无意中颠倒了加载顺序,这样 playerLayer 在 AVStatusReadyToPlay 之前被抓取。事件是:寻找视频,转到主屏幕,然后重新激活应用程序,播放器切换到 HLS 视频内的不同视频/音频轨道。这些动作再次触发 AVStatusReadyToPlay,从而使 playerLayer 在 AVStatusReadyToPlay 之前发生。
这是使用 Apple 的测试 HLS 视频的测试工具:
-(void)loadPlayer
{
NSLog(@"loadPlayer invoked");
NSURL *url = [NSURL URLWithString:@"https://devimages.apple.com.edgekey.net/resources/http-streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8"];
self.playerItem = [AVPlayerItem playerItemWithURL:url];
[self.playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:&kPlayerContext];
self.player = [AVPlayer playerWithPlayerItem:self.playerItem];
}
-(void)loadPlayerLayer
{
NSLog(@"starting player layer");
self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
[self.playerLayer addObserver:self forKeyPath:@"readyForDisplay" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:&kPlayerLayerContext];
[self.playerLayer setFrame:[[self view] bounds]];
[[[self view] layer] addSublayer:self.playerLayer];
}
-(void)observeValueForKeyPath:(NSString*)path ofObject:(id)object change:(NSDictionary*)change context:(void*) context
{
if(context == &kPlayerContext){
if([self.player status] == AVPlayerStatusReadyToPlay){
NSLog(@"Player is ready to play");
//Robert: Never works if after AVPlayerItem reports AVPlayerStatusReadyToPlay
if(!self.startedPlayerLayer){
self.startedPlayerLayer = YES;
[self loadPlayerLayer];
}
}
}
if(context == &kPlayerLayerContext){
if([self.playerLayer isReadyForDisplay] == YES){
NSLog(@"PlayerLayer says it's ready to display now");
[self playTheVideoIfReady];
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3332 次 |
| 最近记录: |