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


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

我正在使用AVPlayer从网上播放视频。我使用输出当前帧 AVPlayerItemVideoOutput 附在 AVPlayerItem 由...发挥 AVPlayer。为了检查新帧是否准备好,我打电话 [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更新] 哪个电话提到了 [AVPlayerItemVideoOutput hasNewPixelBufferForItemTime]。这个函数有静态变量 计数器 它存储了成功的数量 [AVPlayerItemVideoOutput copyPixelBufferForItemTime] 调用。

视频网址已设置 [AVPlayerDemoPlaybackViewController setURL],它在函数的开头是硬编码的。默认情况下,它的值指向m3u8视频,它会再现问题,在这种情况下是平均值 计数器 在具有该指数的框架之后约为30 [AVPlayerItemVideoOutput hasNewPixelBufferForItemTime] 仅返回FALSE。

在使用其他视频网址的情况下(参见开头) [AVPlayerDemoPlaybackViewController setURL]  - 您可以取消注释另一个Url),所有帧都已成功读取。

任何帮助将不胜感激!


11341
2017-07-17 10:12


起源



答案:


代码打击并没有解决我的问题,我仍然没有得到任何东西 [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: 调用。 重新创建你的 AVPlayerItemVideoOutput 如果没有0.1s的新像素缓冲区。

代码 [self configVideoOutput]; 只是重新创建一个新的 AVPlayerItemVideoOutput 替换当前 videoOutput 属性。

为什么0.1秒?

我经过多次测试和实验,发现前1或2帧可能总是没有像素缓冲区。因此,首先1 / 30s,2 / 30s(对于30fps的视频)可能没有帧和像素缓冲区。但如果在0.1秒之后没有视频像素缓冲,则视频输出可能会破坏或出现问题。所以我们需要重新创建它。


5
2017-11-22 09:23



这对我有用。删除并向AVPlayerItem添加新输出似乎可以解决问题。 - Kazzin
这也为我修好了。非常感谢,在我找到这篇文章之前花了一段时间来对抗这个。 - crgt
我还必须在添加它之前重新创建输出以使我的工作。 - kleezy
我和swift以及iOS 9一起工作 - embinder
我希望我能给你不止一次投票。这个解决方案对我也有用。谢啦! - Eugene Alexeev


答案:


代码打击并没有解决我的问题,我仍然没有得到任何东西 [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: 调用。 重新创建你的 AVPlayerItemVideoOutput 如果没有0.1s的新像素缓冲区。

代码 [self configVideoOutput]; 只是重新创建一个新的 AVPlayerItemVideoOutput 替换当前 videoOutput 属性。

为什么0.1秒?

我经过多次测试和实验,发现前1或2帧可能总是没有像素缓冲区。因此,首先1 / 30s,2 / 30s(对于30fps的视频)可能没有帧和像素缓冲区。但如果在0.1秒之后没有视频像素缓冲,则视频输出可能会破坏或出现问题。所以我们需要重新创建它。


5
2017-11-22 09:23



这对我有用。删除并向AVPlayerItem添加新输出似乎可以解决问题。 - Kazzin
这也为我修好了。非常感谢,在我找到这篇文章之前花了一段时间来对抗这个。 - crgt
我还必须在添加它之前重新创建输出以使我的工作。 - kleezy
我和swift以及iOS 9一起工作 - embinder
我希望我能给你不止一次投票。这个解决方案对我也有用。谢啦! - Eugene Alexeev


确保这一点 AVPlayerItem.status 等于 AVPlayerItemStatusReadyToPlay 在打电话之前 - (void)addOutput:(AVPlayerItemOutput *)output 方法 AVPlayerItem

参考:看看depinxi在这个页面上的回复


3
2018-04-20 12:53





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

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

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

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

2
2017-08-25 10:28



这对我有用,谢谢。但我认为最好使用计时器,而不是计数器。我发现这种方法可以在1秒视频停止后使用。 - Paltr
这对我也有用。令人遗憾的是,似乎没有提供API来解决这个问题。 - moka