问题描述
我正在通过网络从另一台设备实时流式传输 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
仍在接收新帧并正确解码(虽然我没有使用 VTDecompressionSessionDecodeFrame
的 CVPixelBuffer
,但我只是渲染了 CMSampleBuffer
。
我对这个问题的理论是,可能一开始 AVSampleBufferdisplayLayer
中的队列需要在 size
中建立,如果一开始我给它帧太快,某处的某些代码会出错,但是当我给它时间来预热并“缓慢”增加帧速率时,它能够建立其内部队列并处理和渲染帧。
然而,这个有趣的部分是 AVSampleBufferdisplayLayer.isReadyForMoreMediaData
始终是 true
,因此队列永远不会填满。
我可以尝试做的另一件事是重新创建整个 AVSampleBufferdisplayLayer
,如果我能检测到 AVSampleBufferdisplayLayer
已冻结,但我找不到任何属性让我知道它当前是否已冻结或不是。
我的问题是:
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)