CGContextDrawImage падает
Код ниже:
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
CGContextRef context = ctx;
CGContextRetain(context);
CGContextSetInterpolationQuality(context, kCGInterpolationNone);
CGContextSetLineCap(context, kCGLineCapButt);
CGContextSetLineWidth(context, 1);
CGContextSetRGBStrokeColor(context, 0, 0, 0, 0.8);
// draw image
CGContextSaveGState(context);
CGAffineTransform flipVertical = CGAffineTransformMake(
1, 0, 0, -1, 0, layer.bounds.size.height
);
CGContextConcatCTM(context, flipVertical);
CGContextDrawImage(context, layer.bounds, imageRef);
CGContextRestoreGState(context);
// draw borders
CGContextAddRect(context, layer.bounds);
CGContextDrawPath(context, kCGPathStroke);
CGFloat apertureSize = scaleFactor * (2 * samplingLevel - 1) - 1;
CGFloat x = self.bounds.size.width / 2 - apertureSize / 2;
CGFloat y = self.bounds.size.height / 2 - apertureSize / 2;
CGRect apertureRect = CGRectMake(x, y, apertureSize, apertureSize);
// draw the aperture
CGContextSaveGState(context);
CGContextSetRGBStrokeColor(context, 0, 0, 0, 1);
CGContextSetShouldAntialias(context, NO);
CGContextStrokeRect(context, apertureRect);
CGContextRestoreGState(context);
CGContextRelease(context);
}
и он падает с:
(lldb) thread backtrace
* thread #1: tid = 0x1c03, 0x37537a5c CoreGraphics`argb32_image_mark_rgb32 + 800, stop reason = EXC_BAD_ACCESS (code=1, address=0x7314b0)
frame #0: 0x37537a5c CoreGraphics`argb32_image_mark_rgb32 + 800
frame #1: 0x3750e400 CoreGraphics`argb32_image + 5948
frame #2: 0x313c5894 libRIP.A.dylib`ripl_Mark + 16
frame #3: 0x313ca68a libRIP.A.dylib`ripl_BltImage + 998
frame #4: 0x313c2468 libRIP.A.dylib`ripc_RenderImage + 180
frame #5: 0x313be300 libRIP.A.dylib`ripc_DrawImage + 584
frame #6: 0x3750a928 CoreGraphics`CGContextDelegateDrawImage + 48
frame #7: 0x3750a794 CoreGraphics`CGContextDrawImage + 292
frame #8: 0x00166e34 MyApp`-[MyView drawLayer:inContext:] + 380 at MyView.m:43
frame #9: 0x33f054e4 QuartzCore`-[CALayer drawInContext:] + 116
frame #10: 0x33f04b3e QuartzCore`CABackingStoreUpdate_ + 1782
frame #11: 0x33f04334 QuartzCore`CA::Layer::display_() + 956
frame #12: 0x33f03f60 QuartzCore`CA::Layer::display() + 128
Кто-нибудь знает почему? Спасибо! Я предполагаю, что это вызвано CGImage или CGContext, но оба они не равны NULL при отладке. Изображение, которое я использовал для обновления вида, генерируется с захвата камеры.
3 ответа
Решение
Я использовал образцы кодов, предоставленные Apple ( AV Foundation Programming Guide) для создания imageRef
,
UIImage *imageFromSampleBuffer(CMSampleBufferRef sampleBuffer) {
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
// 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);
return image;
}
Обратите внимание на эту строку:
CGDataProviderRef dataProvider =
CGDataProviderCreateWithData(NULL, baseAddress, bufferSize, NULL);
CMSampleBuffer
используется непосредственно для создания CGImageRef
, так CGImageRef
станет недействительным после освобождения буфера.
Использование копии данных буфера решит эту проблему:
NSData *data = [NSData dataWithBytes:baseAddress length:bufferSize];
CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
Я столкнулся с той же проблемой, но проблема была связана с ARC и правильным выпуском CGImageRef. Убедитесь, что вызывается следующее:
CGImageRelease(imageRef);
Менять
CGDataProviderRef dataProvider =
CGDataProviderCreateWithData(NULL, baseAddress, bufferSize, NULL);
в
NSData *data = [NSData dataWithBytes:baseAddress length:bufferSize];
CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
действительно помогает.