【问题标题】:Save Video Using AVFoundation Swift使用 AVFoundation Swift 保存视频
【发布时间】:2016-09-10 23:10:18
【问题描述】:

您好,我学习了 Jared Davidson 的课程,使用 AVFoundation 创建自定义相机视图并保存图片。 https://www.youtube.com/watch?v=w0O3ZGUS3pk

但是,我想录制和保存视频而不是图像。有人可以在这里帮助我吗?我确信它很简单,但苹果的文档是用 Objective-C 编写的,我无法破译它。

这是我的代码。谢谢。

import UIKit
import AVFoundation

class ViewController: UIViewController {

    var captureSession = AVCaptureSession()
    var sessionOutput = AVCaptureStillImageOutput()
    var previewLayer = AVCaptureVideoPreviewLayer()


    @IBOutlet var cameraView: UIView!

    override func viewWillAppear(animated: Bool) {

        let devices = AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo)
        for device in devices {
            if device.position == AVCaptureDevicePosition.Front{


                do{

                    let input = try AVCaptureDeviceInput(device: device as! AVCaptureDevice)

                    if captureSession.canAddInput(input){

                        captureSession.addInput(input)
                        sessionOutput.outputSettings = [AVVideoCodecKey : AVVideoCodecJPEG]

                        if captureSession.canAddOutput(sessionOutput){

                            captureSession.addOutput(sessionOutput)
                            captureSession.startRunning()

                            previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
                            previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
                            previewLayer.connection.videoOrientation = AVCaptureVideoOrientation.Portrait
                            cameraView.layer.addSublayer(previewLayer)

                            previewLayer.position = CGPoint(x: self.cameraView.frame.width / 2, y: self.cameraView.frame.height / 2)
                            previewLayer.bounds = cameraView.frame


                        }

                    }

                }
                catch{

                    print("Error")
                }

            }
        }    

    }


    @IBAction func TakePhoto(sender: AnyObject) {

        if let videoConnection = sessionOutput.connectionWithMediaType(AVMediaTypeVideo){

            sessionOutput.captureStillImageAsynchronouslyFromConnection(videoConnection, completionHandler: {
                buffer, error in

                let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer)
                UIImageWriteToSavedPhotosAlbum(UIImage(data: imageData)!, nil, nil, nil)

            })

        }

    }

}

【问题讨论】:

    标签: ios swift swift2 avfoundation


    【解决方案1】:

    您可以通过创建AVCaptureMovieFileOutput 并将其添加到您的捕获会话,并使您的ViewController 符合AVCaptureFileOutputRecordingDelegate 来将录制的视频保存到文件中。

    此示例将 5 秒的视频录制到应用程序的 Documents 目录中名为“output.mov”的文件中。

    class ViewController: UIViewController, AVCaptureFileOutputRecordingDelegate {
    
        var captureSession = AVCaptureSession()
        var sessionOutput = AVCaptureStillImageOutput()
        var movieOutput = AVCaptureMovieFileOutput()
        var previewLayer = AVCaptureVideoPreviewLayer()
    
        @IBOutlet var cameraView: UIView!
    
        override func viewWillAppear(animated: Bool) {
            self.cameraView = self.view
    
            let devices = AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo)
            for device in devices {
                if device.position == AVCaptureDevicePosition.Front{
    
    
                    do{
    
                        let input = try AVCaptureDeviceInput(device: device as! AVCaptureDevice)
    
                        if captureSession.canAddInput(input){
    
                            captureSession.addInput(input)
                            sessionOutput.outputSettings = [AVVideoCodecKey : AVVideoCodecJPEG]
    
                            if captureSession.canAddOutput(sessionOutput){
    
                                captureSession.addOutput(sessionOutput)
    
                                previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
                                previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
                                previewLayer.connection.videoOrientation = AVCaptureVideoOrientation.Portrait
                                cameraView.layer.addSublayer(previewLayer)
    
                                previewLayer.position = CGPoint(x: self.cameraView.frame.width / 2, y: self.cameraView.frame.height / 2)
                                previewLayer.bounds = cameraView.frame
    
    
                            }
    
                            captureSession.addOutput(movieOutput)
    
                            captureSession.startRunning()
    
                            let paths = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
                            let fileUrl = paths[0].URLByAppendingPathComponent("output.mov")
                            try? NSFileManager.defaultManager().removeItemAtURL(fileUrl)
                            movieOutput.startRecordingToOutputFileURL(fileUrl, recordingDelegate: self)
    
                            let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(5 * Double(NSEC_PER_SEC)))
                            dispatch_after(delayTime, dispatch_get_main_queue()) {
                                print("stopping")
                                self.movieOutput.stopRecording()
                            }
                        }
    
                    }
                    catch{
    
                        print("Error")
                    }
    
                }
            }
    
        }
    
        func captureOutput(captureOutput: AVCaptureFileOutput!, didFinishRecordingToOutputFileAtURL outputFileURL: NSURL!, fromConnections connections: [AnyObject]!, error: NSError!) {
            print("FINISHED \(error)")
            // save video to camera roll
            if error == nil {
                UISaveVideoAtPathToSavedPhotosAlbum(outputFileURL.path!, nil, nil, nil)
            }
        }
    
    }
    

    【讨论】:

    • 您可以在 Xcode > Devices > iPhone > app name > Download Container 中从设备下载 Documents 目录。您可以通过从didFinishRecordingToOutputFileAtURL 委托方法调用UISaveVideoAtPathToSavedPhotosAlbum() 将视频保存到相机胶卷。如果您的问题得到解答,请接受此答案。
    • 哈哈非常感谢!希望这也对其他人有所帮助,因为我看到很多人都在问。
    【解决方案2】:

    谢谢你。这对我很有帮助。这是 Rhythmic Fistman 的答案的一个版本,它使用所需的导入语句和委托方法移植到 Swift 3。

    import UIKit
    import AVFoundation
    
    class ViewController: UIViewController,
    AVCaptureFileOutputRecordingDelegate {
    
    var captureSession = AVCaptureSession()
    var sessionOutput = AVCaptureStillImageOutput()
    var movieOutput = AVCaptureMovieFileOutput()
    var previewLayer = AVCaptureVideoPreviewLayer()
    
    @IBOutlet var cameraView: UIView!
    
    override func viewWillAppear(_ animated: Bool) {
        self.cameraView = self.view
    
        let devices = AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo)
        for device in devices! {
            if (device as AnyObject).position == AVCaptureDevicePosition.front{
    
    
                do{
    
                    let input = try AVCaptureDeviceInput(device: device as! AVCaptureDevice)
    
                    if captureSession.canAddInput(input){
    
                        captureSession.addInput(input)
                        sessionOutput.outputSettings = [AVVideoCodecKey : AVVideoCodecJPEG]
    
                        if captureSession.canAddOutput(sessionOutput){
    
                            captureSession.addOutput(sessionOutput)
    
                            previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
                            previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
                            previewLayer.connection.videoOrientation = AVCaptureVideoOrientation.portrait
                            cameraView.layer.addSublayer(previewLayer)
    
                            previewLayer.position = CGPoint(x: self.cameraView.frame.width / 2, y: self.cameraView.frame.height / 2)
                            previewLayer.bounds = cameraView.frame
    
    
                        }
    
                        captureSession.addOutput(movieOutput)
    
                        captureSession.startRunning()
    
                        let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
                        let fileUrl = paths[0].appendingPathComponent("output.mov")
                        try? FileManager.default.removeItem(at: fileUrl)
                        movieOutput.startRecording(toOutputFileURL: fileUrl, recordingDelegate: self)
    
                        let delayTime = DispatchTime.now() + 5
                        DispatchQueue.main.asyncAfter(deadline: delayTime) {
                            print("stopping")
                            self.movieOutput.stopRecording()
                        }
                    }
    
                }
                catch{
    
                    print("Error")
                }
    
            }
        }
    
    }
    
    
    //MARK: AVCaptureFileOutputRecordingDelegate Methods
    
    func capture(_ captureOutput: AVCaptureFileOutput!, didStartRecordingToOutputFileAt fileURL: URL!, fromConnections connections: [Any]!) {
    
    }
    
    func capture(_ captureOutput: AVCaptureFileOutput!, didFinishRecordingToOutputFileAt outputFileURL: URL!, fromConnections connections: [Any]!, error: Error!) {
        print("FINISHED \(error)")
        // save video to camera roll
        if error == nil {
            UISaveVideoAtPathToSavedPhotosAlbum(outputFileURL.path, nil, nil, nil)
        }
    }
    
    }
    

    【讨论】:

    • 视频正在录制并保存在库中,但没有录制声音。请帮帮我。
    【解决方案3】:

    您可以使用此代码将视频保存在照片库中,您必须提供以下参数,其中最重要的是 OutputURL.path,它是要保存到相机胶卷相册的电影文件的文件系统路径, 对于其余参数,您可以传递各自的值,也可以根据需要分配 nil

    func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
    
    if (error != nil) {
            print("Error recording movie: \(error!.localizedDescription)")
        } else {
    
    
            UISaveVideoAtPathToSavedPhotosAlbum(outputFileURL.path, nil, #selector(CameraController.video(_:didFinishSavingWithError:contextInfo:)), nil)
    
        }
        outputURL = nil
    
    }
    

    【讨论】:

    • 您好,请避免仅使用代码回答。为您的答案添加解释,谢谢
    【解决方案4】:

    if (device as AnyObject).position == AVCaptureDevicePosition.front{之后

    添加

    // Audio Input
                    let audioInputDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeAudio)
    
                    do
                    {
                        let audioInput = try AVCaptureDeviceInput(device: audioInputDevice)
    
                        // Add Audio Input
                        if captureSession.canAddInput(audioInput)
                        {
                            captureSession.addInput(audioInput)
                        }
                        else
                        {
                            NSLog("Can't Add Audio Input")
                        }
                    }
                    catch let error
                    {
                        NSLog("Error Getting Input Device: \(error)")
                    }
    

    谢谢

    【讨论】:

      【解决方案5】:

      关于录音问题,

      在创建 captureSession 时添加此代码

      askMicroPhonePermission(completion: { (isMicrophonePermissionGiven) in

                  if isMicrophonePermissionGiven {
                      do {
                          try self.captureSession.addInput(AVCaptureDeviceInput(device: self.captureAudio))
                      } catch {
                          print("Error creating the database")
                      }
                  }
              })
      

      /////////////////////////////////////// ////////////////

      askMicroPhonePermission 函数如下

      func askMicroPhonePermission(completion: @escaping (_ success: Bool)-> Void) {
          switch AVAudioSession.sharedInstance().recordPermission() {
          case AVAudioSessionRecordPermission.granted:
              completion(true)
          case AVAudioSessionRecordPermission.denied:
              completion(false) //show alert if required
          case AVAudioSessionRecordPermission.undetermined:
              AVAudioSession.sharedInstance().requestRecordPermission({ (granted) in
                  if granted {
                      completion(true)
                  } else {
                      completion(false) // show alert if required
                  }
              })
          default:
              completion(false)
          }
      }
      

      你必须在 info.plist 文件中添加 NSMicrophoneUsageDescription 键值。

      【讨论】:

        【解决方案6】:
        func getCurrentFrame(url:String) -> UIImage? {
           let asset = AVAsset(url: URL(string: url)!)
            let assetImgGenerate = AVAssetImageGenerator(asset: asset)
            assetImgGenerate.appliesPreferredTrackTransform = true
            //Can set this to improve performance if target size is known before hand
            //assetImgGenerate.maximumSize = CGSize(width,height)
            let time = CMTimeMakeWithSeconds(1.0, preferredTimescale: 600)
            do {
                let img = try assetImgGenerate.copyCGImage(at: time, actualTime: nil)
                let thumbnail = UIImage(cgImage: img)
                return thumbnail
            } catch {
              print(error.localizedDescription)
              return nil
            }
        }
        

        【讨论】:

          【解决方案7】:

          对于没有调用委托的人来说只有一个小提示:(我在 Xcode 12.x / iOS 14.5 下)

          假设你有一个 f。打开本地 dest。 URL(上一个示例中的代码...文档目录..)

          如果你这样做:

          DispatchQueue.global(qos: .userInitiated).async { //[weak self] in
                              self.captureSession.startRunning()
                              self.addDest()    
                          }
          

          有效,

          但如果你交换:

          DispatchQueue.global(qos: .userInitiated).async { //[weak self] in
                              **self.addDest()**
                              self.captureSession.startRunning()   
          
                          }
          

          委托未被调用。

          设置输出后调用“startRunning”:

          if captureSession.canAddInput(input!) && captureSession.canAddOutput(stillImageOutput) {
                      captureSession.addInput(input!)
                      captureSession.addOutput(stillImageOutput)
                      setupLivePreview()
                      self.videoPreviewLayer.frame = self.previewView.bounds
                      
                      if addVideoOutput(){
                          DispatchQueue.global(qos: .userInitiated).async { //[weak self] in
                              self.captureSession.startRunning()
                              
                              self.addDest()
          
                          }
                          
                      }
          

          ...

          在哪里

           func addVideoOutput() -> Bool{
                  movieOutput = AVCaptureMovieFileOutput()
                  if captureSession.canAddOutput(movieOutput){
                      captureSession.addOutput(movieOutput)
                      return true
                  }
                  return false
              }
            
          

          【讨论】:

            猜你喜欢
            • 2016-05-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-01-13
            • 1970-01-01
            • 1970-01-01
            • 2016-01-19
            • 2017-06-01
            相关资源
            最近更新 更多