CGContextDrawImage 崩溃

Posted

技术标签:

【中文标题】CGContextDrawImage 崩溃【英文标题】:CGContextDrawImage Crash 【发布时间】:2012-12-07 17:06:09 【问题描述】:

我正在尝试从 CGImage 创建 CVPixelBufferRef 所以这里是方法:

- (CVPixelBufferRef) pixelBufferFromCGImage: (CGImageRef) image

    CGImageRetain(image);
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
                             [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey,
                             nil];
    CVPixelBufferRef pxbuffer = NULL;

    CVPixelBufferCreate(kCFAllocatorDefault, CGImageGetWidth(image),
                        CGImageGetHeight(image), kCVPixelFormatType_32ARGB, (CFDictionaryRef) options,
                        &pxbuffer);

    CVPixelBufferLockBaseAddress(pxbuffer, 0);
    void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pxdata, CGImageGetWidth(image),
                                                 CGImageGetHeight(image), 8, 4*CGImageGetWidth(image), rgbColorSpace,
                                                 kCGImageAlphaNoneSkipFirst);
    CGContextRetain(context);
    CGContextConcatCTM(context, CGAffineTransformMakeRotation(0));
    CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image),
                                               CGImageGetHeight(image)), image);
    CGColorSpaceRelease(rgbColorSpace);
    CGContextRelease(context);
    CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
    CGContextRelease(context);
    CGImageRelease(image);
    return pxbuffer;

我经常调用这个方法,它用于生成视频帧,25fps。 这在大多数情况下都可以正常工作,但在某些时候它会在这行代码中崩溃:

 CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image),
                                                   CGImageGetHeight(image)), image);

我已经测试了内存使用和内存泄漏,一切都很好,但仍然会出现崩溃。

崩溃堆栈: 线程 6 崩溃:

0   ImageIO                         0x39270806 CGImageReadGetBytesAtOffset + 34
1   ImageIO                         0x392707d6 CGImageReadSessionGetBytes + 22
2   ImageIO                         0x39280c3c fill_input_buffer + 148
3   ImageIO                         0x3928003a read_markers + 154
4   ImageIO                         0x3927fd82 consume_markers + 34
5   ImageIO                         0x3927fbd2 _cg_jpeg_consume_input + 66
6   ImageIO                         0x3927fb62 _cg_jpeg_read_header + 38
7   ImageIO                         0x39292782 copyImageBlockSetJPEG + 2346
8   ImageIO                         0x3928953e ImageProviderCopyImageBlockSetCallback + 510
9   CoreGraphics                    0x38e0b9d6 CGImageProviderCopyImageBlockSetWithOptions + 158
10  CoreGraphics                    0x38e0b66a img_blocks_create + 370
11  CoreGraphics                    0x38e07a98 img_data_lock + 1488
12  CoreGraphics                    0x38e06d2a CGSImageDataLock + 126

【问题讨论】:

像这样:[***.com/questions/10774392/…尝试保留像素数据[1]:***.com/questions/10774392/cgcontextdrawimage-crashes 【参考方案1】:

从崩溃堆栈中,看起来您的图像本身已在其他线程上释放,可能在您调用 CGImageRetain() 之前。您在此处致电CGImageRetain() 的事实表明您对此有所期待。但如果是这种情况,则保留是不够的,因为它会产生竞争条件。在您尝试保留它之前,该图像可能已被破坏。因此,CGImageRetain 要么是不必要的,要么是不够的。在任何情况下都不应该在这里(也不是它的平衡CGImageRelease)。

这表明在其他线程上使用此图像非常危险,这表明您正在奇怪地调用此方法,或者您让线程变得过于复杂。例如,如果你直接使用NSThread,你可能让它变得太复杂了。

我会审核您对该图像的其他保留和释放,并确保它们不会在调用此方法的过程中发生。我很确定这就是正在发生的事情。

附注:您有多余的 CGContextRetain/CGContextRelease 不需要。当您调用CGBitmapContextCreate() 时,其中包含一个保留(名称中包含“创建”)。也就是说,这只是一个小性能问题;你已经适当地平衡了它们。但这表明您在其他地方的内存管理也可能很奇怪,因此您应该对其进行审核。

【讨论】:

按照您的建议,我尝试复制图像: - (CVPixelBufferRef) pixelBufferFromCGImage: (CGImageRef) imageInput CGImageRef image = CGImageCreateCopy(imageInput); . .但崩溃仍然存在。如果问题是线程,这需要解决吗? 在第一行复制并不会改变竞争条件(它在内存方面与保留相同)。听起来您在没有保留图像的时候调用了这个方法。也许你已经调用了image.CGImage,然后发布了image。也许您使用了从其他地方传递过来的 CGImage,然后在另一个线程上使用它而不保留它。但是你必须在切换线程之前解决这个问题。几乎可以肯定,问题不在此方法范围内。当人们手动使用NSThread 线程时,这些错误最常见。

以上是关于CGContextDrawImage 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

vImageAlphaBlend 崩溃

巨大的内存峰值 - CGContextDrawImage

CGContextDrawImage 画大图很模糊

Swift 3 和 CGContextDrawImage

-[UIImage drawInRect:] / CGContextDrawImage() 不释放内存?

CGContextDrawImage 的优化替代方案