0

我对此感到非常沮丧。

我通过将 AVAssetReaderTrackOutput 实例连接到 AVAssetReader 来逐帧检查 AVAsset。

如果我使用此代码,一切正常,但存在内存泄漏:

while ([reader status] == AVAssetReaderStatusReading) {
    CMSampleBufferRef buffer = [trackOutput copyNextSampleBuffer];
    if(!buffer) break;
    if(/* some condition that alerts me I want to get the image for this frame  */) {

        CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(buffer);
        // Lock the base address of the pixel buffer.
        CVPixelBufferLockBaseAddress(imageBuffer,0);

        // Get the number of bytes per row for the pixel buffer.
        size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
        // Get the pixel buffer width and height.
        size_t width = CVPixelBufferGetWidth(imageBuffer);
        size_t height = CVPixelBufferGetHeight(imageBuffer);

        // Create a device-dependent RGB color space.
        static CGColorSpaceRef colorSpace = NULL;
        if (colorSpace == NULL) {
            colorSpace = CGColorSpaceCreateDeviceRGB();
        if (colorSpace == NULL) {
            // Handle the error appropriately.
            return nil;
            }
        }

        // Get the base address of the pixel buffer.
        void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);
        // Get the data size for contiguous planes of the pixel buffer.
        size_t bufferSize = CVPixelBufferGetDataSize(imageBuffer);

        // Create a Quartz direct-access data provider that uses data we supply.
        CGDataProviderRef dataProvider =
        CGDataProviderCreateWithData(NULL, baseAddress, bufferSize, NULL);
        // Create a bitmap image from data supplied by the data provider.
        CGImageRef cgImage =
        CGImageCreate(width, height, 8, 32, bytesPerRow,
                        colorSpace, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little,
                        dataProvider, NULL, true, kCGRenderingIntentDefault);
        CGDataProviderRelease(dataProvider);

        // Create and return an image object to represent the Quartz image.
        UIImage *image = [UIImage imageWithCGImage:cgImage];
        CGImageRelease(cgImage);

        CVPixelBufferUnlockBaseAddress(imageBuffer, 0);

        [/* array of UIImages */ addObject:image];
    }
    else CFRelease(buffer);
}

存在内存泄漏,因为如果我不想从中获取 UIImage,我只会释放 CMSampleBuffer。

但是,这段代码不会导致内存泄漏,但它会导致 UIImages 数组在全部结束时为空:

while ([reader status] == AVAssetReaderStatusReading) {
    CMSampleBufferRef buffer = [trackOutput copyNextSampleBuffer];
    if(!buffer) break;
    if(/* some condition that alerts me I want to get the image for this frame  */) {

        CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(buffer);
        // Lock the base address of the pixel buffer.
        CVPixelBufferLockBaseAddress(imageBuffer,0);

        // Get the number of bytes per row for the pixel buffer.
        size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
        // Get the pixel buffer width and height.
        size_t width = CVPixelBufferGetWidth(imageBuffer);
        size_t height = CVPixelBufferGetHeight(imageBuffer);

        // Create a device-dependent RGB color space.
        static CGColorSpaceRef colorSpace = NULL;
        if (colorSpace == NULL) {
            colorSpace = CGColorSpaceCreateDeviceRGB();
        if (colorSpace == NULL) {
            // Handle the error appropriately.
            return nil;
            }
        }

        // Get the base address of the pixel buffer.
        void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);
        // Get the data size for contiguous planes of the pixel buffer.
        size_t bufferSize = CVPixelBufferGetDataSize(imageBuffer);

        // Create a Quartz direct-access data provider that uses data we supply.
        CGDataProviderRef dataProvider =
        CGDataProviderCreateWithData(NULL, baseAddress, bufferSize, NULL);
        // Create a bitmap image from data supplied by the data provider.
        CGImageRef cgImage =
        CGImageCreate(width, height, 8, 32, bytesPerRow,
                        colorSpace, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little,
                        dataProvider, NULL, true, kCGRenderingIntentDefault);
        CGDataProviderRelease(dataProvider);

        // Create and return an image object to represent the Quartz image.
        UIImage *image = [UIImage imageWithCGImage:cgImage];
        CGImageRelease(cgImage);

        CVPixelBufferUnlockBaseAddress(imageBuffer, 0);

        [/* array of UIImages */ addObject:image];
    }
    CFRelease(buffer)
}

为什么在地球上释放 CMSampleBufferRef 会在我不释放它导致内存泄漏时搞砸一切?

4

0 回答 0