[iOS] AVPlayerItemVideoOutput.hasNewPixelBufferForItemTime无法正常工作

时间:2014-07-17 10:12:34

标签: ios iphone video avplayer

这是我的第一个问题,所以不要太严厉。

我正在使用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] 的开头) - 您可以取消注释的替代网址,则会成功读取所有网址。

任何帮助将不胜感激!

3 个答案:

答案 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 AFTER AVPlayerItem状态已准备就绪。

     

所以

     
      
  1. 创建播放器&播放器项目,调度队列和显示链接

  2.   
  3. 注册AVPlayerItem状态键

  4. 的观察者   
  5. 在状态AVPlayerStatusReadyToPlay上,创建AVPlayerItemVideoOutput并开始显示链接

  6.         

    感谢所有人的灵感

         

    雷诺

答案 2 :(得分:2)

我注意到AVPlayerItemVideoOutput在使用HLS多比特率播放列表时会以某种方式“阻塞”。当玩家更改为更高比特率时 - >播放器视频轨道的轨道变化 - >它将获得几个像素缓冲区,但之后hasNewPixelBufferForItemTime将始终返回NO。

我花了几天时间解决这个问题。我意外地注意到,如果我去背景,然后回到前景 - >视频将以更高的比特率正常播放。这不是解决方案。

最后,我找到了解决此问题的方法。我为失败的像素缓冲区设置了计数器,100次失败后我从playeritem中删除当前输出并将相同的实例设置回来。

if (failedCount > 100)
    {
        failedCount = 0;
        [_playerItem removeOutput:_output];
        [_playerItem addOutput:_output];
    }