2017-05-29 3 views
2

Configurez une caméra personnalisée à l'aide de AVCapturePhotoOutput. Configuration de l'AVCapturePhotoOutput pour fournir un tampon d'aperçu (vignette) en plus du tampon JPEG principal.AVCapturePhotoOutput ne fournit pas de tampon d'aperçu

Le problème est que je ne reçois le tampon de prévisualisation qu'une seule fois (première capture) et que je reçois ensuite une seconde fois (le photoSampleBuffer principal est toujours reçu correctement).

Voilà comment je configurer la capture:

func capturePhoto() { 

    guard let videoPreviewLayerOrientation = deviceOrientation.videoOrientation else { return } 

    sessionQueue.async { 
     if let photoOutputConnection = self.photoOutput.connection(withMediaType: AVMediaTypeVideo) { 
      photoOutputConnection.videoOrientation = videoPreviewLayerOrientation 
     } 

     // each photo captured requires a brand new setting object and capture delegate 
     let photoSettings = AVCapturePhotoSettings() 

     // Capture a JPEG photo with flash set to auto and high resolution photo enabled. 
     photoSettings.isHighResolutionPhotoEnabled = true 

     //configure to receive a preview image (thumbnail) 
     if let previewPixelType = photoSettings.availablePreviewPhotoPixelFormatTypes.first { 
      let previewFormat = [kCVPixelBufferPixelFormatTypeKey as String : previewPixelType, 
           kCVPixelBufferWidthKey as String : NSNumber(value: 160), 
           kCVPixelBufferHeightKey as String : NSNumber(value: 160)] 
      photoSettings.previewPhotoFormat = previewFormat 
     } 

     // TODO: photoSettings.flashMode = .auto 

     // Use a separate object for the photo capture delegate to isolate each capture life cycle. 
     let photoCaptureDelegate = PhotoCaptureDelegate(with: photoSettings, willCapturePhotoAnimation: { [unowned self] in 
      // show shutter animation 
      self.shutterAnimation() 
      }, completed: { [unowned self] (photoCaptureDelegate, photoData, previewThumbnail) in 

       self.captureCompleted(photoCaptureDelegate: photoCaptureDelegate, data: photoData, thumbnail: previewThumbnail) 
      } 
     ) 
     // The Photo Output keeps a weak reference to the photo capture delegate so we store it in an array 
     // to maintain a strong reference to this object until the capture is completed. 
     self.inProgressPhotoCaptureDelegates[photoCaptureDelegate.requestedPhotoSettings.uniqueID] = photoCaptureDelegate 
     self.photoOutput.capturePhoto(with: photoSettings, delegate: photoCaptureDelegate) 
    } 
} 

Dans mon PhotoCaptureDelegate (qui met en œuvre AVCapturePhotoCaptureDelegate):

func capture(_ captureOutput: AVCapturePhotoOutput, didFinishProcessingPhotoSampleBuffer photoSampleBuffer: CMSampleBuffer?, previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Error?) { 

    if let photoBuffer = photoSampleBuffer { 
     photoData = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: photoBuffer, previewPhotoSampleBuffer: nil) 
    } 


    if let previewBuffer = previewPhotoSampleBuffer { 
     if let pixelBuffer = CMSampleBufferGetImageBuffer(previewBuffer) { 
      photoThumbnail = CIImage(cvPixelBuffer: pixelBuffer) 
     } 

    } 
} 

Ce qui se passe est que la première fois que je capture que je reçois à la fois la photoSampleBuffer & previewPhotoSampleBuffer. 2ème fois et je ne reçois photoSampleBuffer et previewPhotoSampleBuffer = nil bien que quand je vérifie resolvedSettings.previewDimensions je reçois: CMVideoDimensions(width: 160, height: 120)

Si je passe la caméra (avant vers l'arrière) par une nouvelle configuration de la session de capture la première capture est ensuite sur OK, puis à nouveau pas aperçu tampon. le paramètre error dans les rappels de délégué est toujours nul.

testé sur iPhone 6 fonctionnant sous iOS 10.3.1

Répondre

0

Trouvé ce que la solution est, mais ne comprend pas très bien comment il provoque le problème initial.

J'ai modifié ma conversion de la mémoire tampon d'aperçu dans le délégué de capture de photos pour convertir un objet CIContext en un UIImage. Auparavant, j'ai simplement créé un CIImage et l'ai envoyé à l'interface utilisateur (thread différent) et il semble que le CIImage détient une ref au tampon d'origine et le traitement de l'interface utilisateur fait plus tard sur les dégâts avec la capture suivante (encore une fois ne comprends pas pourquoi).

Le nouveau code crée une nouvelle copie bitmap de l'image (via cgImage), puis l'envoie à l'interface utilisateur -> donc pas de traitement sur le tampon d'origine.

func capture(_ captureOutput: AVCapturePhotoOutput, didFinishProcessingPhotoSampleBuffer photoSampleBuffer: CMSampleBuffer?, previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Error?) { 

    if let photoBuffer = photoSampleBuffer { 
     photoData = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: photoBuffer, previewPhotoSampleBuffer: nil) 
    } 

    let previewWidth = Int(resolvedSettings.previewDimensions.width) 
    let previewHeight = Int(resolvedSettings.previewDimensions.height) 

    if let previewBuffer = previewPhotoSampleBuffer { 
     if let imageBuffer = CMSampleBufferGetImageBuffer(previewBuffer) { 
      let ciImagePreview = CIImage(cvImageBuffer: imageBuffer) 
      let context = CIContext() 
      if let cgImagePreview = context.createCGImage(ciImagePreview, from: CGRect(x: 0, y: 0, width:previewWidth , height:previewHeight)) { 
       photoThumbnail = UIImage(cgImage: cgImagePreview) 
      } 
     } 
    } 
}