我正在使用VTDecompressionSession解码.h264流。解码器按预期工作,我得到正确解码的缓冲区。但是,我看到XCode工具“分配”中的“创建且持久”分配逐渐增加。如屏幕截图所示,这些可以归因于解码器在内部分配的IOSurface缓冲区,即使在释放VTDecompressionSession之后也不会释放这些缓冲区。我在同步解码和异步回调decompressionSessionDecodeFrameCallback中都看到了这些情况。剩余的帧数在发生和时间上是随机的。这些缓冲区的大小完全等于解码帧的大小。在使解码器会话无效之前,我确实调用了VTDecompressionSessionWaitForAsynchronousFrames,但是这些分配不会消失。 在解码器会话结束时是否可以释放这些IOSurface缓冲区?
这是我的解码器运行的概述。 创建解码器会话
const void *values[] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &v) };
attrs = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
VTDecompressionOutputCallbackRecord callBackRecord;
callBackRecord.decompressionOutputCallback = decompressionSessionDecodeFrameCallback;
callBackRecord.decompressionOutputRefCon = (__bridge void *)self;
VTDecompressionSessionCreate(kCFAllocatorDefault,
_decoderFormatDescription,
NULL,
attrs,
&callBackRecord,
&_decoderSession);
在NALU数据包准备就绪时调用进行解码
CMSampleBufferRef sampleBuffer = nil;
const size_t sampleSizeArray[] = {packetLen};
CMSampleTimingInfo sampleTimeinfo ={CMTimeMake(1,FPS), CMTimeMake(presentationTS, 1000000), kCMTimeInvalid};
CMSampleBufferCreateReady(kCFAllocatorDefault, blockBuffer, _decoderFormatDescription ,
1, 1, &sampleTimeinfo, 1, sampleSizeArray, &sampleBuffer);
flags = kVTDecodeFrame_EnableAsynchronousDecompression;
VTDecompressionSessionDecodeFrame(_decoderSession,
sampleBuffer,
flags,
&sampleBuffer,
&flagOut);
回调
void decompressionSessionDecodeFrameCallback{
CVPixelBufferLockBaseAddress(imageBuffer,0);
....
send to display
....
CVPixelBufferUnlockBaseAddress(imageBuffer,0);
}
结束解码器会话
VTDecompressionSessionWaitForAsynchronousFrames(_decoderSession);
VTDecompressionSessionInvalidate(_decoderSession);
CFRelease(_decoderSession);
答案 0 :(得分:0)
那是不正常的,您的代码中肯定存在泄漏。
这与释放decompressionSession无关,这种内存泄漏是不同的,这在关闭和打开流时变得很明显。
我注意到您在调用中引用了sampleBuffer作为sourceFrameRefCon:
VTDecompressionSessionDecodeFrame(_decoderSession,
sampleBuffer,
flags,
&sampleBuffer, //here
&flagOut);
这是错误的,除非您希望在其中提供一个指针以能够引用框架本身(而不是缓冲区),否则将此值保留为NULL。这很可能是您的问题。
由于我们只能看到部分代码,因此我将指出通常会发生类似此问题的其他地方。
如果您致电:
CVBufferRetain(imageBuffer);
或
CFRetain(imageBuffer);
然后,您还必须致电:
CVBufferRelease(imageBuffer);
或
CFRelease(imageBuffer);
之后。
请确保接收缓冲区的播放器不会以任何方式保留缓冲区,接收缓冲区后,应立即将缓冲区复制到其自己的缓冲区中,无论如何(除非您使用金属缓冲区直接提供)显示机制的缓冲区,在这种情况下,应在显示后释放缓冲区)。