Search code examples
iosiphoneavfoundationavassetwriter

Why a method works perfectly but crashes if I put it inside a dispatch_async?


I have this camera app.

I take the image from the camera, process it with a filter and at some point inside captureOutput:didOutputSampleBuffer:fromConnection: I take the final image and write it to a file using this:

    CFRetain(sampleBuffer);
    [myself writeToVideoImage:resultadoFinal
             withSampleBuffer:sampleBuffer];
     CFRelease(sampleBuffer);

works wonderfully but If I put this inside a queue, like this:

    CFRetain(sampleBuffer);        
    dispatch_async(_writeToVideoQueue, ^{
      [myself writeToVideoImage:resultadoFinal 
               withSampleBuffer:sampleBuffer];
      CFRelease(sampleBuffer);
    });

it crashes on the line

[_assetWriter startSessionAtSourceTime:presentationTime];

of

- (void)writeToVideoImage:(CIImage *)resultadoFinal
         withSampleBuffer:(CMSampleBufferRef)sampleBuffer
{

  CFRetain(sampleBuffer);
  CMTime presentationTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);

  CGRect extent = [resultadoFinal extent];

  if (!_readyToWriteVideo) {
    _readyToWriteVideo = [self setupAssetWriterVideoInputWithSize:extent.size];
    return;
  }
  else if (_videoWritingStarted) {
    _videoWritingStarted = NO;
    // ***** CRASHES HERE ************
    [_assetWriter startSessionAtSourceTime:presentationTime]; 
  }


  CVPixelBufferRef renderedOutputPixelBuffer = NULL;

  OSStatus err = CVPixelBufferPoolCreatePixelBuffer(NULL,
                                                    _pixelBufferAdaptor.pixelBufferPool,
                                                    &renderedOutputPixelBuffer);
  if (err) return;

  [_ciContext render:resultadoFinal
     toCVPixelBuffer:renderedOutputPixelBuffer
              bounds:extent
          colorSpace:_sDeviceRgbColorSpace];

  [self writeToFile:renderedOutputPixelBuffer
      comSampleTime:presentationTime
               size:extent.size];
  CFRelease(renderedOutputPixelBuffer);
  CFRelease(sampleBuffer);
}

I don't have a clue of what is going on.

It appears to be something deallocating. I first suspected sampleBuffer was deallocating but I am retaining it inside and outside the function, just in case. I have also tried to create a copy of resultadoFinal inside the block, before calling the method, with no success.

Xcode shows the error

[AVAssetWriter startSessionAtSourceTime:] Cannot call method when status is 0'

There are questions on SO about that. I have tried all suggestions without success.

Any ideas?


Solution

  • The error "Cannot call method when status is 0" sounds like something isn't initialized properly - remember when you use dispatch_async you are running on a different thread, so you need to initialize your AVAssetWriter on that thread.