2017-06-18 11 views
2

Kann mir jemand eine Anleitung zur Verwendung von Warteschlangen in AVFoundation geben?AVAssetWriter Warteschlangenführung Swift 3

Später in meiner App möchte ich einige Verarbeitung für einzelne Frames tun, so muss ich AVCaptureVideoDataOutput verwenden.

Um zu beginnen, dachte ich, ich würde Bilder erfassen und sie dann (unverarbeitet) mit AVAssetWriter schreiben.

ich erfolgreich bin Streaming-Frames von der Kamera zum Bildvorschau durch eine AVCapture Sitzung Einrichtung wie folgt:

func initializeCameraAndMicrophone() { 

// set up the captureSession 
    captureSession = AVCaptureSession() 
    captureSession.sessionPreset = AVCaptureSessionPreset1280x720 // set resolution to Medium 

// set up the camera 
    let camera = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) 

    do { 
     let cameraInput = try AVCaptureDeviceInput(device: camera) 
     if captureSession.canAddInput(cameraInput){ 
      captureSession.addInput(cameraInput) 
     } 
    } catch { 
     print("Error setting device camera input: \(error)") 
     return 
    } 

    videoOutputStream.setSampleBufferDelegate(self, queue: DispatchQueue(label: "sampleBuffer", attributes: [])) 

    if captureSession.canAddOutput(videoOutputStream) 
    { 
     captureSession.addOutput(videoOutputStream) 
    } 

    captureSession.startRunning() 


} 

Jeder neuer Rahmen löst dann die captureOutput Delegierten:

func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) 
{ 

    let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) 
    let cameraImage = CIImage(cvPixelBuffer: pixelBuffer!) 
    let bufferImage = UIImage(ciImage: cameraImage) 

    DispatchQueue.main.async 
     { 

     // send captured frame to the videoPreview 
     self.videoPreview.image = bufferImage 


     // if recording is active append bufferImage to video frame 
     while (recordingNow == true){ 

      print("OK we're recording!") 

      /// Append images to video 
      while (writerInput.isReadyForMoreMediaData) { 

       let lastFrameTime = CMTimeMake(Int64(frameCount), videoFPS) 
       let presentationTime = frameCount == 0 ? lastFrameTime : CMTimeAdd(lastFrameTime, frameDuration) 

       pixelBufferAdaptor.append(pixelBuffer!, withPresentationTime: presentationTime) 


       frameCount += 1    
      } 
     } 
    } 
} 

Also dieser Rahmen-Streams zur Bildvorschau, bis ich die Record-Taste drücke, die die "startVideoRecording" -Funktion aufruft (wodurch AVAssetWriter eingerichtet wird). Ab diesem Zeitpunkt wird der Delegierte nie wieder angerufen!

func startVideoRecording() { 


    guard let assetWriter = createAssetWriter(path: filePath!, size: videoSize) else { 
     print("Error converting images to video: AVAssetWriter not created") 
     return 
    } 

    // AVAssetWriter exists so create AVAssetWriterInputPixelBufferAdaptor 
    let writerInput = assetWriter.inputs.filter{ $0.mediaType == AVMediaTypeVideo }.first! 


    let sourceBufferAttributes : [String : AnyObject] = [ 
     kCVPixelBufferPixelFormatTypeKey as String : Int(kCVPixelFormatType_32ARGB) as AnyObject, 
     kCVPixelBufferWidthKey as String : videoSize.width as AnyObject, 
     kCVPixelBufferHeightKey as String : videoSize.height as AnyObject, 
     ] 

    let pixelBufferAdaptor = AVAssetWriterInputPixelBufferAdaptor(assetWriterInput: writerInput, sourcePixelBufferAttributes: sourceBufferAttributes) 

    // Start writing session 
    assetWriter.startWriting() 
    assetWriter.startSession(atSourceTime: kCMTimeZero) 
    if (pixelBufferAdaptor.pixelBufferPool == nil) { 
     print("Error converting images to video: pixelBufferPool nil after starting session") 

     assetWriter.finishWriting{ 
      print("assetWritter stopped!") 
     } 
     recordingNow = false 

     return 
    } 

    frameCount = 0 

    print("Recording started!") 

} 

Ich bin neu in AVFoundation aber ich vermute, ich bin Verschrauben irgendwo meine Warteschlangen:

AVAssetWriter wie folgt eingerichtet wird. Ich habe das seit Stunden angeguckt, so dass jede Hilfe oder Hinweise sehr geschätzt werden!

Antwort

1

Sie müssen eine separate serielle Warteschlange für die Aufnahme von Video/Audio verwenden.

  1. Fügen Sie diese Warteschlange Eigenschaft Ihrer Klasse:

    let captureSessionQueue: DispatchQueue = DispatchQueue(label: "sampleBuffer", attributes: []) 
    
  2. die Sitzung auf captureSessionQueue starten

    nach den Apple-docs: Die startRunning() -Methode ist ein blockierender Aufruf, die eine gewisse Zeit in Anspruch nehmen Daher sollten Sie die Sitzungskonfiguration in einer seriellen Warteschlange durchführen, damit die Hauptwarteschlange nicht blockiert wird (wodurch die Benutzeroberfläche reaktionsfähig bleibt).

    captureSessionQueue.async { 
        captureSession.startRunning() 
    } 
    
  3. auf Ihre Capture-Ausgabepixelpuffer Delegat Setzen Sie diese Warteschlange:

    videoOutputStream.setSampleBufferDelegate(self, queue: captureSessionQueue) 
    
  4. Anruf startVideoRecording innen captureSessionQueue:

    captureSessionQueue.async { 
        startVideoRecording() 
    } 
    
  5. Im captureOutput Delegatmethode alle Anrufe AVFoundation Methoden setzen in captureSessionQueue.async:

    DispatchQueue.main.async 
        { 
    
        // send captured frame to the videoPreview 
        self.videoPreview.image = bufferImage 
    
        captureSessionQueue.async { 
         // if recording is active append bufferImage to video frame 
         while (recordingNow == true){ 
    
          print("OK we're recording!") 
    
          /// Append images to video 
          while (writerInput.isReadyForMoreMediaData) { 
    
           let lastFrameTime = CMTimeMake(Int64(frameCount), videoFPS) 
           let presentationTime = frameCount == 0 ? lastFrameTime : CMTimeAdd(lastFrameTime, frameDuration) 
    
           pixelBufferAdaptor.append(pixelBuffer!, withPresentationTime: presentationTime) 
    
    
           frameCount += 1    
          } 
         } 
        } 
    }