这是我的第一个问题,所以不要太严厉。
我正在使用AVPlayer播放来自网络的视频。我使用附加到 AVPlayer 播放的 AVPlayerItem 的 AVPlayerItemVideoOutput 输出当前帧。要检查新帧是否准备好,我调用 [AVPlayerItemVideoOutput hasNewPixelBufferForItemTime] ,然后使用OpenGL ES输出它。如果我读取mp4,一切都很完美,但是如果我尝试读取m3u8,它可以工作大约1秒钟(~30帧),但在此期间之后 [AVPlayerItemVideoOutput hasNewPixelBufferForItemTime] 开始仅返回FALSE,所以当前帧未更新。
如果我在此问题首次出现之前使用 [AVPlayer seekToTime] 寻找当前帧,则一切正常。
测试我使用的m3u8视频:
http://195.16.112.71/adaptive/3006a26a-9154-4b38-a327-4fa2a2381ae6.video/3006a26a-9154-4b38-a327-4fa2a2381ae6.m3u8
为了重现这个问题,我修改了Apple的AVPlayerDemo示例,其中就是:https://yadi.sk/d/T2aVGoKnWmf5Z
主要的变化是我调用 [AVPlayerDemoPlaybackViewController update] ,调用提到 [AVPlayerItemVideoOutput hasNewPixelBufferForItemTime] 。此函数具有静态变量计数器,用于存储成功的 [AVPlayerItemVideoOutput copyPixelBufferForItemTime] 调用的数量。
视频网址设置在 [AVPlayerDemoPlaybackViewController setURL] 中,它在功能的开头硬编码。默认情况下,它的值指向m3u8视频,它会再现问题,在这种情况下,计数器的平均值约为30,在具有该索引的帧 [AVPlayerItemVideoOutput hasNewPixelBufferForItemTime] 之后仅返回FALSE。
如果使用其他视频网址(请参阅 [AVPlayerDemoPlaybackViewController setURL] 的开头) - 您可以取消注释的替代网址,则会成功读取所有网址。
任何帮助将不胜感激!
答案 0 :(得分:5)
代码打击并没有解决我的问题,我仍然没有得到[AVPlayerItemVideoOutput hasNewPixelBufferForItemTime]
if (failedCount > 100) {
failedCount = 0;
[_playerItem removeOutput:_output];
[_playerItem addOutput:_output];
}
最后在测试我的代码一整天之后。我找到了解决问题的方法。
#pragma mark - AVPlayerItemOutputPullDelegate
- (void)outputMediaDataWillChange:(AVPlayerItemOutput *)sender {
if (![self.videoOutput hasNewPixelBufferForItemTime:CMTimeMake(1, 10)]) {
[self configVideoOutput];
}
[self.displayLink setPaused:NO];
}
调用[AVPlayerItemVideoOutput hasNewPixelBufferForItemTime]
时检查outputMediaDataWillChange:
。 如果没有0.1秒的新像素缓冲区,则重新创建AVPlayerItemVideoOutput
。
[self configVideoOutput];
中的代码只需重新创建新的AVPlayerItemVideoOutput
即可替换当前的videoOutput
属性。
为什么0.1秒?
我经过多次测试和实验,发现前1或2帧可能总是没有像素缓冲区。因此,首先1 / 30s,2 / 30s(对于30fps的视频)可能没有帧和像素缓冲区。但如果在0.1s之后没有视频像素缓冲,则视频输出可能会破坏或出现问题。所以我们需要重新创建它。
答案 1 :(得分:3)
在AVPlayerItem.status
AVPlayerItemStatusReadyToPlay
方法之前,请确保- (void)addOutput:(AVPlayerItemOutput *)output
等于AVPlayerItem
参考:Renaud's reply on this page
我的实施遇到了同样的问题。在尝试了这里提出的解决方案之后,我想我终于找到了做事的可靠方法
必须创建
AVPlayerItemVideoOutput
AFTERAVPlayerItem
状态已准备就绪。所以
创建播放器&播放器项目,调度队列和显示链接
- 的观察者
注册
AVPlayerItem
状态键- 醇>
在状态
AVPlayerStatusReadyToPlay
上,创建AVPlayerItemVideoOutput
并开始显示链接感谢所有人的灵感
雷诺
答案 2 :(得分:2)
我注意到AVPlayerItemVideoOutput在使用HLS多比特率播放列表时会以某种方式“阻塞”。当玩家更改为更高比特率时 - >播放器视频轨道的轨道变化 - >它将获得几个像素缓冲区,但之后hasNewPixelBufferForItemTime将始终返回NO。
我花了几天时间解决这个问题。我意外地注意到,如果我去背景,然后回到前景 - >视频将以更高的比特率正常播放。这不是解决方案。
最后,我找到了解决此问题的方法。我为失败的像素缓冲区设置了计数器,100次失败后我从playeritem中删除当前输出并将相同的实例设置回来。
if (failedCount > 100)
{
failedCount = 0;
[_playerItem removeOutput:_output];
[_playerItem addOutput:_output];
}