VTDecompressionSession - распределение IOS-поверхности постепенно увеличивается

Я использую 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 ответов

Это ненормально, в вашем коде определенно есть утечка.

Это не проблема с выпуском decopressionSession, такая утечка памяти отличается, что становится очевидным при закрытии и открытии потоков.

Я заметил, что вы ссылались на sampleBuffer как на sourceFrameRefCon в вызове:

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

Это неверно, если вы не хотите указать там указатель, чтобы иметь возможность ссылаться на сам фрейм (а не на буфер), оставьте это значение как NULL. Это вполне может быть вашей проблемой.

Поскольку мы можем видеть только часть вашего кода, я укажу, где обычно возникают другие проблемы, подобные этой.

Если вы когда-нибудь позвоните:

CVBufferRetain(imageBuffer);

или

CFRetain(imageBuffer);

Тогда вы также должны позвонить:

CVBufferRelease(imageBuffer);

или

CFRelease(imageBuffer);

после соответственно.

Убедитесь, что игрок, получающий буфер, никоим образом не сохраняет его, при получении буфера он должен немедленно скопировать буфер в свой собственный буфер, каким бы он ни был (если вы не используете металлический буфер для непосредственного предоставления буфера для механизм отображения, и в этом случае вы должны освободить буфер после отображения).

Другие вопросы по тегам