0

The code is below:

- (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);
}

and it crashes with:

(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

Anyone knows why? Thanks! I guess it is caused by either CGImage or CGContext, but both of them are Non-null when debugging. The image I used to update the view is generated from camera capturing.

wtl
  • 312
  • 3
  • 13
  • What was the nature of the crash? `EXC_BAD_ACCESS`? If so, did it show what address it was trying to access? The most likely culprit would be that `imageRef` is NULL. – Ken Thomases May 27 '12 at 14:20
  • The `imageRef` did have an value, so I'm wondering if this image is valid? But I have no idea of how to check a `CGImageRef`. – wtl May 27 '12 at 14:29
  • 1
    Well, it could be a garbage pointer value. If it points to a real, extent `CGImageRef`, it should be valid unless you have smashed the heap. Do a Build and Analyze and resolve any issues it identifies. Beyond that, you'll probably need to show where `imageRef` is declared and all of the code which touches that variable. (Oh, and I see my first comment was dumb. The crash details were there but scrolled off to the right where I didn't see them.) – Ken Thomases May 27 '12 at 14:48
  • Thanks @Ken, you are right, the problem lies in `imageRef`. I've found out the solution and written it down. – wtl May 29 '12 at 12:36

3 Answers3

4

I used sample codes provided by apple (AV Foundation Programming Guide) to create 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;
}

Note this line:

CGDataProviderRef dataProvider =
        CGDataProviderCreateWithData(NULL, baseAddress, bufferSize, NULL);

CMSampleBuffer is used directly to create a CGImageRef, so CGImageRef will become invalid once the buffer is released.

Use copy of the buffer data will resolve this problem:

NSData *data = [NSData dataWithBytes:baseAddress length:bufferSize];
CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
wtl
  • 312
  • 3
  • 13
3

I encountered the same issue, but the problem was related to ARC and releasing the CGImageRef properly. Make sure the following is called:

CGImageRelease(imageRef);
Matthew Purland
  • 290
  • 3
  • 5
  • My app kept crashing or having memory issues when trying to rotate a captured image, across 3 different method implementations and nothing worked. This quick little comment by you just fixed everything! Thank you! – user3344977 Mar 14 '14 at 07:05
0

change

CGDataProviderRef dataProvider =
    CGDataProviderCreateWithData(NULL, baseAddress, bufferSize, NULL);

to

NSData *data = [NSData dataWithBytes:baseAddress length:bufferSize];
CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);

really helps.

zengcity
  • 21
  • 1