2016-04-20 8 views
2

Illustration of what I'm trying to doNehmen Sie Platz Video AVFoundation mit und Wasserzeichen hinzufügen

Ich versuche, die folgendes zu tun:

  • Musik spielen
  • Nehmen Sie ein Quadrat Video (Ich habe einen Container in der Ansicht, die zeigt, was du aufzeichnest)
  • Fügen Sie ein Label am oberen Rand und das App-Symbol & Name in der linken unteren Ecke des Square-Video.

Bis zu diesem Punkt, den ich es geschafft, die Musik zu spielen, zeigen die AVCaptureVideoPreviewLayer in einem quadratischen Behälter in einer anderen Ansicht und das Video auf der Kamerarolle speichern.

Die Sache ist, dass ich kaum ein paar vage Tutorials über die Verwendung von AVFoundation finden kann und das ist meine erste App, macht die Dinge ziemlich hart.

Ich habe es geschafft, diese Dinge zu tun, aber ich verstehe immer noch nicht, wie AVFoundation funktioniert. Die Dokumentation ist vage für einen Anfänger und ich habe kein Tutorial für das gefunden, was ich wirklich will und das Zusammenstellen mehrerer Tutorials (und in Obj C geschrieben) macht dies unmöglich. Meine Probleme sind folgende:

  1. Das Video wird nicht als Quadrat gespeichert. (Erwähnen, dass die App keine Querformat-Orientierung unterstützt)
  2. Das Video hat kein Audio. (Ich denke, ich sollte eine andere Art von Audio-Eingang als das Video hinzufügen)
  3. Wie die Wasserzeichen zu dem Video hinzufügen?
  4. Ich habe einen Fehler: Ich erstellte eine Ansicht (messageView; siehe im Code) mit einem Text & Bild, wodurch der Benutzer wissen, dass das Video in der Kamera gespeichert wurde. Wenn ich jedoch das zweite Mal aufnehme, wird die Ansicht angezeigt, während das Video aufgenommen wird, nicht NACH der Aufnahme. Ich vermute, dass es damit zusammenhängt, jedes Video gleich zu benennen.

Also mache ich die Vorbereitungen:

override func viewDidLoad() { 
     super.viewDidLoad() 

     // Preset For High Quality 
     captureSession.sessionPreset = AVCaptureSessionPresetHigh 

     // Get available devices capable of recording video 
     let devices = AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo) as! [AVCaptureDevice] 

     // Get back camera 
     for device in devices 
     { 
      if device.position == AVCaptureDevicePosition.Back 
      { 
       currentDevice = device 
      } 
     } 

     // Set Input 
     let captureDeviceInput: AVCaptureDeviceInput 
     do 
     { 
      captureDeviceInput = try AVCaptureDeviceInput(device: currentDevice) 
     } 
     catch 
     { 
      print(error) 
      return 
     } 

     // Set Output 
     videoFileOutput = AVCaptureMovieFileOutput() 

     // Configure Session w/ Input & Output Devices 
     captureSession.addInput(captureDeviceInput) 
     captureSession.addOutput(videoFileOutput) 

     // Show Camera Preview 
     cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession) 
     view.layer.addSublayer(cameraPreviewLayer!) 
     cameraPreviewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill 
     let width = view.bounds.width*0.85 
     cameraPreviewLayer?.frame = CGRectMake(0, 0, width, width) 

     // Bring Record Button To Front 
     view.bringSubviewToFront(recordButton) 
     captureSession.startRunning() 

//  // Bring Message To Front 
//  view.bringSubviewToFront(messageView) 
//  view.bringSubviewToFront(messageText) 
//  view.bringSubviewToFront(messageImage) 
    } 

Dann, wenn ich die Taste Aufzeichnung drücken:

@IBAction func capture(sender: AnyObject) { 
    if !isRecording 
    { 
     isRecording = true 

     UIView.animateWithDuration(0.5, delay: 0.0, options: [.Repeat, .Autoreverse, .AllowUserInteraction], animations: {() -> Void in 
      self.recordButton.transform = CGAffineTransformMakeScale(0.5, 0.5) 
      }, completion: nil) 

     let outputPath = NSTemporaryDirectory() + "output.mov" 
     let outputFileURL = NSURL(fileURLWithPath: outputPath) 
     videoFileOutput?.startRecordingToOutputFileURL(outputFileURL, recordingDelegate: self) 
    } 
    else 
    { 
     isRecording = false 

     UIView.animateWithDuration(0.5, delay: 0, options: [], animations: {() -> Void in 
      self.recordButton.transform = CGAffineTransformMakeScale(1.0, 1.0) 
      }, completion: nil) 
     recordButton.layer.removeAllAnimations() 
     videoFileOutput?.stopRecording() 
    } 
} 

Und nachdem das Video aufgezeichnet wurde:

func captureOutput(captureOutput: AVCaptureFileOutput!, didFinishRecordingToOutputFileAtURL outputFileURL: NSURL!, fromConnections connections: [AnyObject]!, error: NSError!) { 
    let outputPath = NSTemporaryDirectory() + "output.mov" 
    if UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(outputPath) 
    { 
     UISaveVideoAtPathToSavedPhotosAlbum(outputPath, self, nil, nil) 
     // Show Success Message 
     UIView.animateWithDuration(0.4, delay: 0, options: [], animations: { 
      self.messageView.alpha = 0.8 
      }, completion: nil) 
     UIView.animateWithDuration(0.4, delay: 0, options: [], animations: { 
      self.messageText.alpha = 1.0 
      }, completion: nil) 
     UIView.animateWithDuration(0.4, delay: 0, options: [], animations: { 
      self.messageImage.alpha = 1.0 
      }, completion: nil) 
     // Hide Message 
     UIView.animateWithDuration(0.4, delay: 1, options: [], animations: { 
      self.messageView.alpha = 0 
      }, completion: nil) 
     UIView.animateWithDuration(0.4, delay: 1, options: [], animations: { 
      self.messageText.alpha = 0 
      }, completion: nil) 
     UIView.animateWithDuration(0.4, delay: 1, options: [], animations: { 
      self.messageImage.alpha = 0 
      }, completion: nil) 
    } 
} 

Was muss ich das reparieren? Ich suchte weiter und schaute über Tutorials, aber ich kann es nicht herausfinden ... Ich las über das Hinzufügen von Wasserzeichen und ich sah, dass es etwas damit zu tun hat, CALayers oben auf dem Video hinzuzufügen. Aber natürlich kann ich das nicht machen, da ich nicht einmal weiß, wie man das Video quadratisch macht und Audio hinzufügt.

+0

willst du die Wasserzeichen-Post-Aufnahme hinzufügen AKA das Video aufnehmen, dann bearbeiten und Wasserzeichen hinzufügen oder während der Aufnahme hinzufügen? – SeanLintern88

+0

Ich möchte die Wasserzeichenpostaufnahme hinzufügen. Also Video aufnehmen (Quadrat auf UI) mit Audio -> Aufnahme beenden -> Videoquadrat erstellen -> Wasserzeichen hinzufügen – Lawrence413

+0

Mit der Nachbearbeitung müssen Sie AVMutableComposition mit avassexportsession verwenden. Es gibt eine WWDC-Sitzung, aber ich kann mich nicht erinnern, welches Jahr, es auf Videobearbeitung – SeanLintern88

Antwort

3

Ein paar Dinge:

Soweit Audio geht, sind Sie ein Video (Kamera) Eingang hinzufügen, aber keine Audio-Eingang. Also tu das, um Sound zu bekommen.

let audioInputDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeAudio) 

    do { 
     let input = try AVCaptureDeviceInput(device: audioInputDevice) 

     if sourceAVFoundation.captureSession.canAddInput(input) { 
      sourceAVFoundation.captureSession.addInput(input) 
     } else { 
      NSLog("ERROR: Can't add audio input") 
     } 
    } catch let error { 
     NSLog("ERROR: Getting input device: \(error)") 
    } 

Um den Video Platz zu machen, wirst du mit AVAssetWriter statt AVCaptureFileOutput zu suchen. Das ist komplexer, aber Sie bekommen mehr "Power".Sie haben eine AVCaptureSession bereits geschaffen, die groß ist, die AssetWriter zu anschließen, werden Sie so etwas wie dies tun müssen:

let fileManager = NSFileManager.defaultManager() 
    let urls = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask) 
    guard let documentDirectory: NSURL = urls.first else { 
     print("Video Controller: getAssetWriter: documentDir Error") 
     return nil 
    } 

    let local_video_name = NSUUID().UUIDString + ".mp4" 
    self.videoOutputURL = documentDirectory.URLByAppendingPathComponent(local_video_name) 

    guard let url = self.videoOutputURL else { 
     return nil 
    } 


    self.assetWriter = try? AVAssetWriter(URL: url, fileType: AVFileTypeMPEG4) 

    guard let writer = self.assetWriter else { 
     return nil 
    } 

    //TODO: Set your desired video size here! 
    let videoSettings: [String : AnyObject] = [ 
     AVVideoCodecKey : AVVideoCodecH264, 
     AVVideoWidthKey : captureSize.width, 
     AVVideoHeightKey : captureSize.height, 
     AVVideoCompressionPropertiesKey : [ 
      AVVideoAverageBitRateKey : 200000, 
      AVVideoProfileLevelKey : AVVideoProfileLevelH264Baseline41, 
      AVVideoMaxKeyFrameIntervalKey : 90, 
     ], 
    ] 

    assetWriterInputCamera = AVAssetWriterInput(mediaType: AVMediaTypeVideo, outputSettings: videoSettings) 
    assetWriterInputCamera?.expectsMediaDataInRealTime = true 
    writer.addInput(assetWriterInputCamera!) 

    let audioSettings : [String : AnyObject] = [ 
     AVFormatIDKey : NSInteger(kAudioFormatMPEG4AAC), 
     AVNumberOfChannelsKey : 2, 
     AVSampleRateKey : NSNumber(double: 44100.0) 
    ] 

    assetWriterInputAudio = AVAssetWriterInput(mediaType: AVMediaTypeAudio, outputSettings: audioSettings) 
    assetWriterInputAudio?.expectsMediaDataInRealTime = true 
    writer.addInput(assetWriterInputAudio!) 

Sobald Sie die AssetWriter Setup haben ... dann einige Ausgaben für die Haken Video und Audio

let bufferAudioQueue = dispatch_queue_create("audio buffer delegate", DISPATCH_QUEUE_SERIAL) 
    let audioOutput = AVCaptureAudioDataOutput() 
    audioOutput.setSampleBufferDelegate(self, queue: bufferAudioQueue) 
    captureSession.addOutput(audioOutput) 

    // Always add video last... 
    let videoOutput = AVCaptureVideoDataOutput() 
    videoOutput.setSampleBufferDelegate(self, queue: bufferVideoQueue) 
    captureSession.addOutput(videoOutput) 
    if let connection = videoOutput.connectionWithMediaType(AVMediaTypeVideo) { 
     if connection.supportsVideoOrientation { 
      // Force recording to portrait 
      connection.videoOrientation = AVCaptureVideoOrientation.Portrait 
     } 

     self.outputConnection = connection 
    } 


    captureSession.startRunning() 

Schließlich müssen Sie die Puffer und Verfahren zu erfassen, die stopfen ... stellen Sie sicher, dass Ihre Klasse ein Delegierter von AVCaptureVideoDataOutputSampleBufferDelegate und AVCaptureAudioDataOutputSampleBufferDelegate

//MARK: Implementation for AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAudioDataOutputSampleBufferDelegate 
func captureOutput(captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, fromConnection connection: AVCaptureConnection!) { 

    if !self.isRecordingStarted { 
     return 
    } 

    if let audio = self.assetWriterInputAudio where connection.audioChannels.count > 0 && audio.readyForMoreMediaData { 

     dispatch_async(audioQueue!) { 
      audio.appendSampleBuffer(sampleBuffer) 
     } 
     return 
    } 

    if let camera = self.assetWriterInputCamera where camera.readyForMoreMediaData { 
     dispatch_async(videoQueue!) { 
      camera.appendSampleBuffer(sampleBuffer) 
     } 
    } 
} 
machen

Es gibt ein paar fehlende Teile, aber hoffentlich ist das genug für Sie, um es zusammen mit der Dokumentation herauszufinden.

Schließlich, wenn Sie das Wasserzeichen hinzufügen möchten, gibt es viele Möglichkeiten, wie dies in Echtzeit getan werden kann, aber eine Möglichkeit besteht darin, den SampleBuffer zu ändern und das Wasserzeichen in das Bild zu schreiben. Sie werden andere Fragen zu StackOverflow finden, die sich damit befassen.

+0

Ich ging mit AVCaptureFileOutput und es funktionierte. Aber danke für die Hilfe zum Hinzufügen von Audio! – Lawrence413

+0

gibt es wirklich so viel Zeug in Ihrem Code fehlt ... versuchen, es herauszufinden, wie eine Stunde –

+0

gibt es wie 20-30 Variablen als 'Selbst erklärt. keine Ahnung, was diese für den Code bedeuten ... unmöglich so ... –