2013-04-05 8 views
9

Sto cercando di incorporare una visualizzazione semplice nella mia applicazione iPhone per scattare istantanee. Tutto funziona bene, ma sto affrontando alcuni problemi con il tempo di avvio delle telecamere. In un progetto di esempio Apple, il file -startRunning di AVCaptureSession non viene eseguito sul thread principale, cosa che sembra essere necessaria. Sto configurando la sessione di cattura durante l'inizializzazione della vista e l'avvio in un thread separato. Ora aggiungo lo AVCaptureVideoPreviewLayer in -didMoveToSuperview. Va tutto bene senza multithreading (l'interfaccia utente è bloccata per circa un secondo), ma con GCD l'interfaccia utente a volte funziona, a volte ci vuole troppo tempo perché l'interfaccia utente si sblocchi o l'anteprima venga mostrata.Come evitare di bloccare l'interfaccia utente quando si utilizza la fotocamera dell'iPhone tramite AVFoundation?

Come posso gestire il ritardo di avvio della videocamera in modo affidabile, senza bloccare il thread principale (il ritardo stesso non è il problema)?

spero che voi ragazzi capire il mio problema: D

Grazie in anticipo!

BTW: Ecco il mio proof-of-concept-progetto (senza GCD) ora sto riutilizzando per un'altra app: http://github.com/dariolass/QuickShotView

risposta

10

Così ho capito da solo. Questo codice funziona per me e produce meno di congelamento UI:

- (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

Grazie! La chiave per me era l'esecuzione di 'AvvioRunning' di AVCaptureSession' e' stopRunning' su un thread in background. – the4kman

-1

Penso che un altro modo per evitare è che si può mettere il codice di "start della macchina fotografica" in viewDidAppear, invece di metterli in viewWillAppear.

+0

Questo non risolve il problema di una funzione costosa eseguita sul thread principale. Puoi ancora eseguirlo in anticipo (cioè in 'viewWillAppear') e non bloccare i thread principali –