Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does jpegStillImageNSDataRepresentation throw an exception when sample buffer is NOT null?

Tags:

ios

avcapture

In iOS, I am using code to capture from AVCaptureStillImageOutput thus:

[_captureStillOutput captureStillImageAsynchronouslyFromConnection: _captureConnection completionHandler: asyncCaptureCompletionHandler];

for simplicity to boil down my code, my asyncCaptureCompletionHandler block looks like this:

void(^asyncCaptureCompletionHandler)(CMSampleBufferRef imageDataSampleBuffer, NSError *error) = 
^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
    if (CMSampleBufferIsValid(imageDataSampleBuffer)) {
        NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
        UIImage *image = [[UIImage alloc] initWithData:imageData];                                                                 
    }
}

I have been through all my code and cross referencing with stack overflow, and have not found any suggestion why a valid sample buffer would be captured without being a proper JPEG.

_captureStillOutput = [[AVCaptureStillImageOutput alloc] init];
_captureStillOutput.outputSettings = 
        [NSDictionary dictionaryWithObjectsAndKeys:
         AVVideoCodecJPEG, AVVideoCodecKey,
         nil];

if ([session canAddOutput:_captureStillOutput]) {
            [session addOutput:_captureStillOutput];
}

There is supplemental info in the debugger: * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* +[AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:] - Not a jpeg sample buffer.'

Searches in google and stack overflow both for "Not a jpeg sample buffer" produced zero results. I'm stuck. bah.

like image 485
Tom Pace Avatar asked Nov 03 '22 16:11

Tom Pace


1 Answers

This question is old but gold. I come from the future and can confirm that this still happens in 2015. I tried to go through the same steps to fix the issue, but to no avail. However, this question made me realize that the CMSampleBufferRef imageDataSampleBuffer behaves oddly when it's dealt with outside of the captureStillImageAsynchronouslyFromConnection's completion handler.

In a nutshell:

[self.stillImageOutput captureStillImageAsynchronouslyFromConnection:connection
                                                       completionHandler:^( CMSampleBufferRef imageDataSampleBuffer, NSError *error )
    {
        //call another method to handle the sample buffer causes weird behaviour
        //maybe the buffer is not being safely referenced by AVFoundation?
        [self handleBufferSomewhereElse:imageDataSampleBuffer]; //will behave strangely
        //even more so if you move to another thread
    }];

Prefer doing this instead:

[self.stillImageOutput captureStillImageAsynchronouslyFromConnection:connection
                                                       completionHandler:^( CMSampleBufferRef imageDataSampleBuffer, NSError *error )
    {
        //handle the buffer right here
        NSData *data = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer]; 
        //works better
    }]; 

Hope this helps someone.

like image 101
Bell App Lab Avatar answered Nov 15 '22 07:11

Bell App Lab