Search code examples
iosxcodevideo-captureavcaptureoutput

CVPixelBufferUnlockBaseAddress - Block UI


i'm struggling to debug a weird problem. In a captureOutput:didOutputSampleBuffer:fromConnection: right after CVPixelBufferUnlockBaseAddress(imageBuffer,0); the entire UI stops responding to touches. The camera preview works but all my buttons stop responding and i even added a UITapGesture and also would not work. I tried putting it into a dispatch but still with no success.

- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
       fromConnection:(AVCaptureConnection *)connection
{
    if (state != CAMERA) {
        return;
    }

    if (self.state != CAMERA_DECODING)
    {
        self.state = CAMERA_DECODING;
    }


    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    //Lock the image buffer
    CVPixelBufferLockBaseAddress(imageBuffer,0);
    //Get information about the image
    baseAddress = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer,0);

    int pixelFormat = CVPixelBufferGetPixelFormatType(imageBuffer);
    switch (pixelFormat) {
        case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:

            //NSLog(@"Capture pixel format=NV12");
            bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer,0);
            width = bytesPerRow;//CVPixelBufferGetWidthOfPlane(imageBuffer,0);
            height = CVPixelBufferGetHeightOfPlane(imageBuffer,0);
            break;
        case kCVPixelFormatType_422YpCbCr8:


            //NSLog(@"Capture pixel format=UYUY422");
            bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer,0);
            width = CVPixelBufferGetWidth(imageBuffer);
            height = CVPixelBufferGetHeight(imageBuffer);
            int len = width*height;
            int dstpos=1;
            for (int i=0;i<len;i++){
                baseAddress[i]=baseAddress[dstpos];
                dstpos+=2;
            }

            break;
        default:
            //  NSLog(@"Capture pixel format=RGB32");
            break;
    }

    unsigned char *pResult=NULL;

    int resLength = MWB_scanGrayscaleImage(baseAddress,width,height, &pResult);

    CVPixelBufferUnlockBaseAddress(imageBuffer,0);

Solution

  • Probably its happening because you are running all the operations on the main thread.
    Creating the output for the session you have the opportunity to run the callback on another queue:

    AVCaptureVideoDataOutput * dataOutput = [[AVCaptureVideoDataOutput alloc] init];
                [dataOutput setAlwaysDiscardsLateVideoFrames:YES];
                [dataOutput setVideoSettings:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey]];
    dispatch_queue_t queue = dispatch_queue_create("it.CloudInTouchLabs.avsession", DISPATCH_QUEUE_SERIAL);
                [dataOutput setSampleBufferDelegate:(id)self queue:queue];
                if ([captureSession_ canAddOutput:dataOutput]) {
                    [captureSession_ addOutput:dataOutput];
                }
    

    In this sample I create a serial queue.