5

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.

Tom Pace
  • 2,347
  • 1
  • 24
  • 32

2 Answers2

2

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.

Bell App Lab
  • 818
  • 6
  • 14
0

The next step for this solution was to log all the data reported in the debugger using:

po imageDataSampleBuffer

this always produced a lot of details while the exception was being thrown, lots of info on the sample buffer. Then since posting this to SO, I commented out some code, then uncommented it, and now it is working. Nothing changed in my code, however, I did close some programs running on the mac. Perhaps it was a development machine bug. After this, I closed and reopened Xcode, and the exception has not been thrown.

Tom Pace
  • 2,347
  • 1
  • 24
  • 32