Как правильно очистить AVCaptureSession и AVCaptureVideoPreviewLayer - PullRequest
7 голосов
/ 23 марта 2011

Я использую API AVFoundation для создания предварительного просмотра камеры, и у меня возникают проблемы с очисткой после того, как я закончу.

Лучший ответ, который я нашел на эту проблему, заключается в этой SO ветке , спасибо Codo.

Однако он не решает проблему освобождения слоя AVCaptureVideoPreviewLayer, и именно здесь у меня возникают проблемы.

В моем классе контроллера представления у меня есть некоторый код инициализации в методе startCameraCapture. Слушая ответ Кодо, я использую dispatch_set_finalizer_f(_captureQueue, capture_cleanup); для регистрации обратного вызова, который будет вызываться, когда очередь действительно закрыта. Я также сохраняю себя, чтобы убедиться, что мой объект не исчезнет до того, как очередь завершит вызов моего объекта. Затем я использую обратный вызов capture_cleanup для освобождения себя.

-(void) startCameraCapture {
    _camSession = [[AVCaptureSession alloc] init];
    if (_previewLayer == nil) {
        _previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:_camSession];
    }
    _previewLayer.frame = self.compView.bgView.frame;   
    [self.compView.bgView.layer addSublayer:_previewLayer];

    // Get the default camera device
    AVCaptureDevice* camera = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    // Create a AVCaptureInput with the camera device
    NSError *error=nil;
    AVCaptureInput* cameraInput = [[AVCaptureDeviceInput alloc] initWithDevice:camera error:&error];
    if (cameraInput == nil) {
        NSLog(@"Error to create camera capture:%@",error);

    }

    AVCaptureVideoDataOutput* videoOutput = [[[AVCaptureVideoDataOutput alloc] init] autorelease];

    // create a queue to run the capture on
    _captureQueue=dispatch_queue_create("captureQueue", NULL);
    dispatch_set_context(_captureQueue, self);
    dispatch_set_finalizer_f(_captureQueue, capture_cleanup);

    // setup our delegate
    [videoOutput setSampleBufferDelegate:self queue:_captureQueue];

    dispatch_release(_captureQueue);

    // retain self as a workouround a queue finalization bug in apples's sdk 
    // per Stackoverflow answer /3036874/kak-pravilno-vypustit-avcapturesession
    [self retain];

    // configure the pixel format
    videoOutput.videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA], (id)kCVPixelBufferPixelFormatTypeKey,
                                 nil];

    // and the size of the frames we want
    [_camSession setSessionPreset:AVCaptureSessionPresetMedium];

    // Add the input and output
    [_camSession addInput:cameraInput];
    [_camSession addOutput:videoOutput];

    [cameraInput release];

    // Start the session
    [_camSession startRunning];     
}

Здесь обратный вызов capture_cleanup:

 static void capture_cleanup(void* p)
    {
        LiveCompViewController* ar = (LiveCompViewController*)p;
        [ar release];  // releases capture session if dealloc is called
    }

Тогда мой код очистки выглядит так:

-(void) stopCameraCapture {
[_camSession stopRunning];
    [_camSession release];
    _camSession=nil;    

    // Remove the layer in order to release the camSession
    [_previewLayer removeFromSuperlayer];
    _previewLayer = nil;

}

Проблема, с которой я столкнулся, заключается в том, что удаление _previewLayer из суперслоя в stopCameraCapture вызывает следующую ошибку консоли:

"... изменение слоя, который завершается ..."

Но мне нужно удалить слой, чтобы он был освобожден и освобожден для освобождения _camSession, который, в свою очередь, освобождает dispatch_queue, а затем, наконец, вызывает мой обратный вызов capture_cleanup, который, наконец, освобождает себя.

Я не понимаю, почему я получаю ошибку консоли и как ее исправить. Почему Слой завершается в то время, когда я звоню [_previewLayer removeFromSuperlayer], если self.dealloc не был вызван.

Примечание: self - это viewController, и я еще не добавил его, поэтому он сохраняется NavigationContoller.

1 Ответ

3 голосов
/ 16 октября 2013

Попробуйте остановить сеанс перед выпуском:

[captureSession stopRunning];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...