1

我正在使用 VTDecompressionSession 来解码 .h264 流。解码器按预期工作,我得到正确解码的缓冲区。但是,我看到 XCode 工具“Allocations”中的“Created And Persistent”分配逐渐增加。如屏幕截图所示,这些可以归因于解码器内部分配的 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);

在此处输入图像描述

4

1 回答 1

0

这是不正常的,您的代码中肯定存在泄漏。

这不是释放 decompressionSession 的问题,这样的内存泄漏是不同的,在关闭和打开流时会变得很明显。

我注意到您在调用中引用了 sampleBuffer 作为 sourceFrameRefCon:

VTDecompressionSessionDecodeFrame(_decoderSession,
                                          sampleBuffer,
                                          flags,
                                          &sampleBuffer, //here
                                          &flagOut);

这是错误的,除非您想在此处提供一个能够引用帧本身(而不是缓冲区)的指针,否则将此值保留为 NULL。这很可能是你的问题。

由于我们只能看到您的一部分代码,因此我将指出通常会出现此类问题的其他问题。

如果你曾经打电话:

CVBufferRetain(imageBuffer);

或者

CFRetain(imageBuffer);

然后你还必须调用:

CVBufferRelease(imageBuffer);

或者

CFRelease(imageBuffer);

之后,分别。

确保接收缓冲区的播放器不会以任何方式保留缓冲区,在接收缓冲区时,它应该立即将缓冲区复制到自己的缓冲区,无论可能是什么(除非您使用金属缓冲区直接将缓冲区提供给显示机制,在这种情况下,您应该在显示后释放缓冲区)。

于 2020-05-09T01:39:32.090 回答