【问题标题】:Hold Button to record a video with AVFoundation, Swift 3按住按钮以使用 AVFoundation、Swift 3 录制视频
【发布时间】:2017-07-20 14:37:03
【问题描述】:

我想弄清楚如何在 Swift 中使用 AVFoundation 录制视频。我已经创建了一个自定义相机,但我只知道如何用它拍摄静态照片,我不知道如何录制视频。希望你能帮我解决这个问题。

我想按住 takePhotoButton 录制视频,然后在我预览当前静态照片的地方进行预览。您的帮助将真正帮助我继续我的项目。非常感谢!

import UIKit
import AVFoundation

@available(iOS 10.0, *)
class CameraViewController: UIViewController,AVCaptureVideoDataOutputSampleBufferDelegate {

let photoSettings = AVCapturePhotoSettings()
    var audioPlayer = AVAudioPlayer()
    var captureSession = AVCaptureSession()
    var videoDeviceInput: AVCaptureDeviceInput!
    var previewLayer = AVCaptureVideoPreviewLayer()
    var frontCamera: Bool = false
    var captureDevice:AVCaptureDevice!
    var takePhoto = false

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        prepareCamera()
    }

    func prepareCamera() {
        captureSession.sessionPreset = AVCaptureSessionPresetPhoto

        if let availableDevices = AVCaptureDeviceDiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaTypeVideo, position: .back).devices {
            captureDevice = availableDevices.first
            beginSession()
        } 
    }

    func frontCamera(_ front: Bool){
        let devices = AVCaptureDevice.devices()

        do{
            try captureSession.removeInput(AVCaptureDeviceInput(device:captureDevice!)) 
        }catch{
            print("Error")
        }

        for device in devices!{
            if((device as AnyObject).hasMediaType(AVMediaTypeVideo)){
                if front{
                    if (device as AnyObject).position == AVCaptureDevicePosition.front {
                        captureDevice = device as? AVCaptureDevice

                        do{
                            try captureSession.addInput(AVCaptureDeviceInput(device: captureDevice!))
                        }catch{}
                        break
                    }
                }else{
                    if (device as AnyObject).position == AVCaptureDevicePosition.back {
                        captureDevice = device as? AVCaptureDevice

                        do{
                            try captureSession.addInput(AVCaptureDeviceInput(device: captureDevice!))
                        }catch{}
                        break
                    }
                }
            }
        }
    }

    func beginSession () {
        do {
            let captureDeviceInput = try AVCaptureDeviceInput(device: captureDevice)
            if let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) {
            self.previewLayer = previewLayer
            containerView.layer.addSublayer(previewLayer as? CALayer ?? CALayer())
            self.previewLayer.frame = self.view.layer.frame
            self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
            previewLayer.connection.videoOrientation = AVCaptureVideoOrientation.portrait
            captureSession.startRunning()

            let dataOutput = AVCaptureVideoDataOutput()
            dataOutput.videoSettings = [(kCVPixelBufferPixelFormatTypeKey as NSString):NSNumber(value:kCVPixelFormatType_32BGRA)]

            dataOutput.alwaysDiscardsLateVideoFrames = true

            if captureSession.canAddOutput(dataOutput) {
                captureSession.addOutput(dataOutput)

                photoSettings.isHighResolutionPhotoEnabled = true
                photoSettings.isAutoStillImageStabilizationEnabled = true
            }

            captureSession.commitConfiguration()

            let queue = DispatchQueue(label: "com.NightOut.captureQueue")
            dataOutput.setSampleBufferDelegate(self, queue: queue) 
        }
    }
        @IBAction func takePhoto(_ sender: Any) {
            takePhoto = true

            photoSettings.isHighResolutionPhotoEnabled = true
            photoSettings.isAutoStillImageStabilizationEnabled = true
    }

    func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
        if takePhoto {
            takePhoto = false
            if let image = self.getImageFromSampleBuffer(buffer: sampleBuffer) {
                let photoVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PhotoVC") as! PhotoPreviewViewController

                photoVC.takenPhoto = image

                DispatchQueue.main.async {
                    self.present(photoVC, animated: true, completion: {
                        self.stopCaptureSession()
                    })
                }
            }  
        }
    }

    func getImageFromSampleBuffer (buffer:CMSampleBuffer) -> UIImage? {
        if let pixelBuffer = CMSampleBufferGetImageBuffer(buffer) {
            let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
            let context = CIContext()

            let imageRect = CGRect(x: 0, y: 0, width: CVPixelBufferGetWidth(pixelBuffer), height: CVPixelBufferGetHeight(pixelBuffer))

            if let image = context.createCGImage(ciImage, from: imageRect) {
                return UIImage(cgImage: image, scale: UIScreen.main.scale, orientation: .leftMirrored)
            }
    }
        return nil
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        self.captureSession.stopRunning()
    }

    func stopCaptureSession () {
        self.captureSession.stopRunning()

        if let inputs = captureSession.inputs as? [AVCaptureDeviceInput] {
            for input in inputs {
                self.captureSession.removeInput(input)
            }
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    @IBAction func DismissButtonAction(_ sender: UIButton) {

        UIView.animate(withDuration: 0.1, animations: {
            self.DismissButton.transform = CGAffineTransform.identity.scaledBy(x: 0.8, y: 0.8)
        }, completion: { (finish) in
            UIView.animate(withDuration: 0.1, animations: {
                self.DismissButton.transform = CGAffineTransform.identity
            })
        })
        performSegue(withIdentifier: "Segue", sender: nil)
    }
}

【问题讨论】:

    标签: ios swift video avfoundation video-capture


    【解决方案1】:

    要识别按住按钮并释放它,可以通过不同的方式完成。最简单的方法是为UIControlEvents.TouchUpInsideUIControlEvents.TouchDown 添加一个目标,用于捕获按钮,如下所示。

    aButton.addTarget(self, action: Selector("holdRelease:"), forControlEvents: UIControlEvents.TouchUpInside);
    aButton.addTarget(self, action: Selector("HoldDown:"), forControlEvents: UIControlEvents.TouchDown)
    
    //target functions   
    func HoldDown(sender:UIButton)
    {
           // Start recording the video
    }
    
    func holdRelease(sender:UIButton)
    {
           // Stop recording the video
    }
    

    还有其他方法,例如向按钮或视图添加长按手势识别器,并根据识别器状态启动/停止。更多信息可以在这里找到另一个 SO 答案UIButton with hold down action and release action

    视频录制

    您需要将AVCaptureMovieFileOutput 添加到您的捕获会话并使用startRecordingToOutputFileURL 方法开始视频录制。

    注意事项

    • 实现AVCaptureFileOutputRecordingDelegate 方法来识别开始和完成录制
    • 文件路径应该有意义,这意味着您应该提供您的应用可以访问的正确文件路径。

    HoldDown()方法中有这段代码开始录制

     let videoFileOutput = AVCaptureMovieFileOutput()
                    self.captureSession?.addOutput(videoFileOutput)
     let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as URL
     let filePath = documentsURL.appendingPathComponent("tempMovie")
     videoFileOutput.startRecording(toOutputFileURL: filePath, recordingDelegate: self)
    

    停止录制使用vidoeFileOutput.stopRecording()

    【讨论】:

    • 这是一个非常详细和漂亮的答案,但是你能帮我一个代码sn-p吗?我不明白如何实现委托和苹果文件没有那么有帮助/我没有正确理解它们。对不起,我还在学习。谢谢
    • @RandomGeek 我有一个基于 Github 的 Swift 相机代码库,用于我的中型博客文章教程。我最近添加了录制视频功能。看看这个 Github repo branch 了解更多关于如何实现录制视频和回放的信息。希望这会有所帮助
    • 谢谢 :) 我会调查的。
    • 我不能单独做到这一点:(无论我尝试什么我的应用程序崩溃并且我无法实现它,我都需要帮助匹配它...
    【解决方案2】:

    您需要使用AVCaptureMovieFileOutput。使用addOutput(_:)AVCaptureMovieFileOutput 添加到捕获会话

    开始录制

    您开始使用录制 QuickTime 电影 startRecording(to:recordingDelegate:)。您需要提供一个 基于文件的 URL 和委托。 URL 不得标识现有的 文件,因为电影文件输出不会覆盖现有的 资源。您还必须有权写入指定的 地点。委托人必须符合 AVCaptureFileOutputRecordingDelegate 协议,并且必须实现 fileOutput(_:didFinishRecordingTo:from:error:) 方法。

    请参阅docs 了解更多信息。

    【讨论】:

    • 你能帮我把它添加到我现有的代码中吗?谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-19
    相关资源
    最近更新 更多