微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

AVSampleBufferDisplayLayer 挂起/冻结

如何解决AVSampleBufferDisplayLayer 挂起/冻结

我正在通过网络从另一台设备实时流式传输 H264 视频,并使用 AVSampleBufferdisplayLayer 渲染它以渲染 H264 帧。

更多背景信息:我已经计算了发出一个完整的 H264 帧所需的时间,平均为 14 毫秒

因为我想“实时”渲染这些帧,所以我没有设置自定义时基,也没有为每个 SampleTimingInfo 提供 CMSampleBuffer。相反,我将 kCMSampleAttachmentKey_displayImmediately 值设置为 true

let attachments:CFArray? = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer,createIfNecessary: true)
if let attachmentArray = attachments {
    let dic = unsafeBitCast(CFArrayGetValueAtIndex(attachmentArray,0),to: cfmutabledictionary.self)

    CFDictionarySetValue(dic,Unmanaged.passUnretained(kCMSampleAttachmentKey_displayImmediately).toOpaque(),Unmanaged.passUnretained(kcfBooleanTrue).toOpaque())
}

...然后我将框架enqueue变成AVSampleBufferdisplayLayer,如下所示:

if self.VideoLayer.isReadyForMoreMediaData
{
    self.VideoLayer?.enqueue(sampleBuffer)
    self.VideoLayer.setNeedsdisplay() // I've commented this line on/off
}
else
{
    print("not ready for more Metadata")
}

这段代码确实工作得很好,并尽快显示视频帧,我从来没有遇到过 self.VideoLayer.isReadyForMoreMediaData == false 情况。

但是,在某些条件下(每次都可重现),AVSampleBufferdisplayLayer 挂起。

如果我启动正在传输 H264 视频的服务器应用程序并将其“背景化”,则服务器应用程序运行速度会有点慢,并且传输 TCP 帧的速度也很慢。当我运行我的 Swift 应用时,它提供了 AVSampleBufferdisplayLayer“预热时间”以更低的 FPS(大约 5-6fps)流式传输帧。

然后,如果我等待几秒钟并将我的服务器应用程序置于前台,它将开始全速传输帧(14ms/60+fps 传输时间)。然后 AVSampleBufferdisplayLayer 现在能够处理更快的帧输入并很好地处理流,并且它继续运行良好。

但是,如果我在开始时不将我的服务器应用程序置于后台,并将其保持在前台,因此它始终以全速率传输,一旦我的 Swift 应用程序连接,AVSampleBufferdisplayLayer 将呈现一两帧然后完全冻结。

我尝试阅读以下 AVSampleBufferdisplayLayer 值以检查是否有问题,但没有显示任何类型的问题。我看过:

AVSampleBufferdisplayLayer.error = nil,AVSampleBufferdisplayLayer.isReadyForMoreMediaData = true,AVSampleBufferdisplayLayer.requiresFlushToResumeDecoding = false,AVSampleBufferdisplayLayer.status = AVQueuedSampleBufferRenderingStatus.rendering

它们都显示了预期值,就好像它正确渲染一样。 VTDecompressionSessionDecodeFrame 仍在接收新帧并正确解码(虽然我没有使用 VTDecompressionSessionDecodeFrameCVPixelBuffer,但我只是渲染了 CMSampleBuffer

我对这个问题的理论是,可能一开始 AVSampleBufferdisplayLayer 中的队列需要在 size 中建立,如果一开始我给它帧太快,某处的某些代码会出错,但是当我给它时间来预热并“缓慢”增加帧速率时,它能够建立其内部队列并处理和渲染帧。

然而,这个有趣的部分是 AVSampleBufferdisplayLayer.isReadyForMoreMediaData 始终是 true,因此队列永远不会填满。

我可以尝试做的另一件事是重新创建整个 AVSampleBufferdisplayLayer,如果我能检测到 AVSampleBufferdisplayLayer 已冻结,但我找不到任何属性让我知道它当前是否已冻结或不是。

我的问题是:

  1. 为什么 AVSampleBufferdisplayLayer 会冻结/我该如何解决
  2. 如果这不是一个简单的解决方法,我如何至少检测到冻结?

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。