Fix the memory leak in the video decoder

This commit is contained in:
Cameron Gutman 2014-10-20 12:55:23 -04:00
parent f909371a90
commit f14a2a66dd
2 changed files with 74 additions and 32 deletions

View File

@ -65,9 +65,8 @@ void DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit)
entry = entry->next; entry = entry->next;
} }
// This function will take our buffer
[renderer submitDecodeBuffer:data length:decodeUnit->fullLength]; [renderer submitDecodeBuffer:data length:decodeUnit->fullLength];
free(data);
} }
} }

View File

@ -46,38 +46,69 @@
OSStatus status; OSStatus status;
size_t oldOffset = CMBlockBufferGetDataLength(existingBuffer); size_t oldOffset = CMBlockBufferGetDataLength(existingBuffer);
// Append a 4 byte buffer to this block for the length prefix // If we're at index 1 (first NALU in frame), enqueue this buffer to the memory block
status = CMBlockBufferAppendMemoryBlock(existingBuffer, NULL, // so it can handle freeing it when the block buffer is destroyed
NAL_LENGTH_PREFIX_SIZE, if (offset == 1) {
kCFAllocatorDefault, NULL, 0, int dataLength = nalLength - NALU_START_PREFIX_SIZE;
NAL_LENGTH_PREFIX_SIZE, 0);
if (status != noErr) { // Pass the real buffer pointer directly (no offset)
NSLog(@"CMBlockBufferAppendMemoryBlock failed: %d", (int)status); // This will give it to the block buffer to free when it's released.
return; // All further calls to CMBlockBufferAppendMemoryBlock will do so
// at an offset and will not be asking the buffer to be freed.
status = CMBlockBufferAppendMemoryBlock(existingBuffer, data,
nalLength + 1, // Add 1 for the offset we decremented
kCFAllocatorDefault,
NULL, 0, nalLength + 1, 0);
if (status != noErr) {
NSLog(@"CMBlockBufferReplaceDataBytes failed: %d", (int)status);
return;
}
// Write the length prefix to existing buffer
const uint8_t lengthBytes[] = {(uint8_t)(dataLength >> 24), (uint8_t)(dataLength >> 16),
(uint8_t)(dataLength >> 8), (uint8_t)dataLength};
status = CMBlockBufferReplaceDataBytes(lengthBytes, existingBuffer,
oldOffset, NAL_LENGTH_PREFIX_SIZE);
if (status != noErr) {
NSLog(@"CMBlockBufferReplaceDataBytes failed: %d", (int)status);
return;
}
} }
else {
// Write the length prefix to the new buffer // Append a 4 byte buffer to this block for the length prefix
int dataLength = nalLength - NALU_START_PREFIX_SIZE; status = CMBlockBufferAppendMemoryBlock(existingBuffer, NULL,
const uint8_t lengthBytes[] = {(uint8_t)(dataLength >> 24), (uint8_t)(dataLength >> 16), NAL_LENGTH_PREFIX_SIZE,
(uint8_t)(dataLength >> 8), (uint8_t)dataLength}; kCFAllocatorDefault, NULL, 0,
status = CMBlockBufferReplaceDataBytes(lengthBytes, existingBuffer, NAL_LENGTH_PREFIX_SIZE, 0);
oldOffset, NAL_LENGTH_PREFIX_SIZE); if (status != noErr) {
if (status != noErr) { NSLog(@"CMBlockBufferAppendMemoryBlock failed: %d", (int)status);
NSLog(@"CMBlockBufferReplaceDataBytes failed: %d", (int)status); return;
return; }
}
// Write the length prefix to the new buffer
// Append the rest of the data by simply attaching a reference to the buffer int dataLength = nalLength - NALU_START_PREFIX_SIZE;
status = CMBlockBufferAppendMemoryBlock(existingBuffer, &data[offset+NALU_START_PREFIX_SIZE], const uint8_t lengthBytes[] = {(uint8_t)(dataLength >> 24), (uint8_t)(dataLength >> 16),
dataLength, (uint8_t)(dataLength >> 8), (uint8_t)dataLength};
kCFAllocatorNull, // Don't deallocate data on free status = CMBlockBufferReplaceDataBytes(lengthBytes, existingBuffer,
NULL, 0, dataLength, 0); oldOffset, NAL_LENGTH_PREFIX_SIZE);
if (status != noErr) { if (status != noErr) {
NSLog(@"CMBlockBufferReplaceDataBytes failed: %d", (int)status); NSLog(@"CMBlockBufferReplaceDataBytes failed: %d", (int)status);
return; return;
}
// Attach the buffer by reference to the block buffer
status = CMBlockBufferAppendMemoryBlock(existingBuffer, &data[offset+NALU_START_PREFIX_SIZE],
dataLength,
kCFAllocatorNull, // Don't deallocate data on free
NULL, 0, dataLength, 0);
if (status != noErr) {
NSLog(@"CMBlockBufferReplaceDataBytes failed: %d", (int)status);
return;
}
} }
} }
// This function must free data
- (void)submitDecodeBuffer:(unsigned char *)data length:(int)length - (void)submitDecodeBuffer:(unsigned char *)data length:(int)length
{ {
unsigned char nalType = data[FRAME_START_PREFIX_SIZE] & 0x1F; unsigned char nalType = data[FRAME_START_PREFIX_SIZE] & 0x1F;
@ -120,21 +151,25 @@
if (status != noErr) { if (status != noErr) {
NSLog(@"Failed to create format description: %d", (int)status); NSLog(@"Failed to create format description: %d", (int)status);
formatDesc = NULL; formatDesc = NULL;
return;
} }
} }
// Free the data buffer
free(data);
// No frame data to submit for these NALUs // No frame data to submit for these NALUs
return; return;
} }
if (formatDesc == NULL) { if (formatDesc == NULL) {
// Can't decode if we haven't gotten our parameter sets yet // Can't decode if we haven't gotten our parameter sets yet
free(data);
return; return;
} }
if (nalType != 0x1 && nalType != 0x5) { if (nalType != 0x1 && nalType != 0x5) {
// Don't submit parameter set data // Don't submit parameter set data
free(data);
return; return;
} }
@ -144,9 +179,10 @@
status = CMBlockBufferCreateEmpty(NULL, 0, 0, &blockBuffer); status = CMBlockBufferCreateEmpty(NULL, 0, 0, &blockBuffer);
if (status != noErr) { if (status != noErr) {
NSLog(@"CMBlockBufferCreateEmpty failed: %d", (int)status); NSLog(@"CMBlockBufferCreateEmpty failed: %d", (int)status);
free(data);
return; return;
} }
int lastOffset = -1; int lastOffset = -1;
for (int i = 0; i < length - FRAME_START_PREFIX_SIZE; i++) { for (int i = 0; i < length - FRAME_START_PREFIX_SIZE; i++) {
// Search for a NALU // Search for a NALU
@ -166,6 +202,8 @@
[self updateBufferForRange:blockBuffer data:data offset:lastOffset length:length - lastOffset]; [self updateBufferForRange:blockBuffer data:data offset:lastOffset length:length - lastOffset];
} }
// From now on, CMBlockBuffer owns the data pointer and will free it when it's dereferenced
CMSampleBufferRef sampleBuffer; CMSampleBufferRef sampleBuffer;
status = CMSampleBufferCreate(kCFAllocatorDefault, status = CMSampleBufferCreate(kCFAllocatorDefault,
@ -176,6 +214,7 @@
&sampleBuffer); &sampleBuffer);
if (status != noErr) { if (status != noErr) {
NSLog(@"CMSampleBufferCreate failed: %d", (int)status); NSLog(@"CMSampleBufferCreate failed: %d", (int)status);
CFRelease(blockBuffer);
return; return;
} }
@ -197,6 +236,10 @@
} }
[displayLayer enqueueSampleBuffer:sampleBuffer]; [displayLayer enqueueSampleBuffer:sampleBuffer];
// Dereference the buffers
CFRelease(blockBuffer);
CFRelease(sampleBuffer);
} }
@end @end