2013-04-05 5 views
9

Ich versuche, eine einfache Ansicht in meine iPhone-Anwendung einzubetten, um schnelle Schnappschüsse zu machen. Alles funktioniert gut, aber ich habe einige Probleme mit der Startzeit der Kameras. In einem Apple-Beispielprojekt wird AVCaptureSessions -startRunning nicht auf dem Hauptthread ausgeführt, was notwendig scheint. Ich richte die Capture-Sitzung während der Initialisierung der Ansicht ein und starte sie in einem separaten Thread. Jetzt füge ich die AVCaptureVideoPreviewLayer in -didMoveToSuperview hinzu. Alles ist in Ordnung, ohne Multithreading (die Benutzeroberfläche ist für etwa eine Sekunde blockiert), aber mit GCD funktioniert die Benutzeroberfläche manchmal, manchmal dauert es viel zu lange für die Benutzeroberfläche "zu entfrieren" oder die Vorschau angezeigt werden.Wie verhindert man die Blockierung der Benutzeroberfläche bei der Verwendung der iPhone-Kamera über AVFoundation?

Wie kann ich mit der Startverzögerung der Kamera zuverlässig umgehen, ohne den Haupt-Thread zu blockieren (die Verzögerung selbst ist nicht das Problem)?

Ich hoffe, ihr mein Problem verstehen: D

Vielen Dank im Voraus!

BTW: Hier ist meine Proof-of-Concept-Projekt (ohne GCD) ich jetzt für eine andere App bin Wiederverwendung: http://github.com/dariolass/QuickShotView

Antwort

10

Also habe ich es selbst herausgefunden. Dieser Code funktioniert für mich und die geringsten UI Einfrieren:

- (void)willMoveToSuperview:(UIView *)newSuperview { 
    //capture session setup 
    AVCaptureDeviceInput *newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:self.rearCamera error:nil]; 
    AVCaptureStillImageOutput *newStillImageOutput = [[AVCaptureStillImageOutput alloc] init]; 
    NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys: 
          AVVideoCodecJPEG, AVVideoCodecKey, 
          nil]; 
    [newStillImageOutput setOutputSettings:outputSettings]; 

    AVCaptureSession *newCaptureSession = [[AVCaptureSession alloc] init]; 

    if ([newCaptureSession canAddInput:newVideoInput]) { 
     [newCaptureSession addInput:newVideoInput]; 
    } 

    if ([newCaptureSession canAddOutput:newStillImageOutput]) { 
     [newCaptureSession addOutput:newStillImageOutput]; 
     self.stillImageOutput = newStillImageOutput; 
     self.captureSession = newCaptureSession; 
    } 
    // -startRunning will only return when the session started (-> the camera is then ready) 
    dispatch_queue_t layerQ = dispatch_queue_create("layerQ", NULL); 
    dispatch_async(layerQ, ^{ 
     [self.captureSession startRunning]; 
     AVCaptureVideoPreviewLayer *prevLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:self.captureSession]; 
      prevLayer.frame = self.previewLayerFrame; 
      prevLayer.masksToBounds = YES; 
      prevLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; 
      prevLayer.cornerRadius = PREVIEW_LAYER_EDGE_RADIUS; 
     //to make sure were not modifying the UI on a thread other than the main thread, use dispatch_async w/ dispatch_get_main_queue 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      [self.layer insertSublayer:prevLayer atIndex:0]; 
     }); 
    }); 
} 
+0

Danke! Der Schlüssel für mich war, 'AVCaptureSession's' startRunning' und 'stopRunning' auf einem Hintergrund-Thread auszuführen. – the4kman

-1

denke ich, eine andere Art und Weise zu vermeiden, ist, dass Sie Ihre „Start Kamera“ setzen können Code in viewDidAppear, anstatt sie in viewWillAppear setzen.

+0

Dies behandelt nicht das Problem einer kostspieligen Funktion, die auf dem Haupt-Thread ausgeführt wird. Sie können dies immer noch früh ausführen (dh in 'viewWillAppear') und die Hauptthreads nicht blockieren –