我有一个项目,需要从实时网络流中解码h264视频,并最终得到一个可以在iOS设备上的另一个框架(Unity3D)中显示的纹理。我可以使用VTDecompressionSession成功地解码视频,然后使用CVMetalTextureCacheCreateTextureFromImage(或OpenGL变体)抓取纹理。当我使用低延迟编码器并且图像缓冲区按显示顺序出现时,它工作得很好,但是当我使用常规编码器时,图像缓冲区不按显示顺序出现,重新排序图像缓冲区比我预期的要困难得多。
第一次尝试是使用kVTDecodeFrame_EnableAsynchronousDecompression和kVTDecodeFrame_EnableTemporalProcessing设置VTDecodeFrameFlags。但是,事实证明VTDecompressionSession可以选择忽略标志并做任何它想做的事情。在我的情况下,它选择忽略标志并仍然以编码器顺序输出缓冲区(而不是显示顺序)。基本上是无用的。
下一步尝试是将图像缓冲区与呈现时间戳相关联,并将它们扔进一个向量中,这样当我创建纹理时就可以抓取我需要的图像缓冲区了。问题似乎是进入VTDecompressionSession的图像缓冲区(与时间戳相关联)不再是出现的相同缓冲区,从本质上讲,时间戳无用。
例如,进入解码器...
在回调方面...
第一次尝试是使用kVTDecodeFrame_EnableAsynchronousDecompression和kVTDecodeFrame_EnableTemporalProcessing设置VTDecodeFrameFlags。但是,事实证明VTDecompressionSession可以选择忽略标志并做任何它想做的事情。在我的情况下,它选择忽略标志并仍然以编码器顺序输出缓冲区(而不是显示顺序)。基本上是无用的。
下一步尝试是将图像缓冲区与呈现时间戳相关联,并将它们扔进一个向量中,这样当我创建纹理时就可以抓取我需要的图像缓冲区了。问题似乎是进入VTDecompressionSession的图像缓冲区(与时间戳相关联)不再是出现的相同缓冲区,从本质上讲,时间戳无用。
例如,进入解码器...
VTDecodeFrameFlags flags = kVTDecodeFrame_EnableAsynchronousDecompression;
VTDecodeInfoFlags flagOut;
// Presentation time stamp to be passed with the buffer
NSNumber *nsPts = [NSNumber numberWithDouble:pts];
VTDecompressionSessionDecodeFrame(_decompressionSession, sampleBuffer, flags,
(void*)CFBridgingRetain(nsPts), &flagOut);
在回调方面...
void decompressionSessionDecodeFrameCallback(void *decompressionOutputRefCon, void *sourceFrameRefCon, OSStatus status, VTDecodeInfoFlags infoFlags, CVImageBufferRef imageBuffer, CMTime presentationTimeStamp, CMTime presentationDuration)
{
// The presentation time stamp...
// No longer seems to be associated with the buffer that it went in with!
NSNumber* pts = CFBridgingRelease(sourceFrameRefCon);
}
当订购时,回调端的时间戳以预期速率单调递增,但缓冲区顺序不正确。有人看到我在这里犯了什么错误吗?或者知道如何确定回调端的缓冲区顺序吗?目前为止,我已尝试了几乎我所能想到的一切。