题 使用AVCaptureVideoDataOutput或AVCaptureMovieFileOutput使用Swift捕获视频


我需要一些关于如何捕获视频的指导,而不必使用 UIImagePicker。视频需要在按钮单击时启动和停止,然后将此数据保存到 NSDocumentDirectory。我是swift的新手,所以任何帮助都会有用。

我需要帮助的代码部分是启动和停止视频会话并将其转换为数据。我创建了一个运行版本的图片 captureStillImageAsynchronouslyFromConnection 并将此数据保存到 NSDocumentDirectory。我已经设置了一个视频捕获会话,并准备好代码保存数据,但不知道如何从会话中获取数据。

var previewLayer : AVCaptureVideoPreviewLayer?
var captureDevice : AVCaptureDevice?
var videoCaptureOutput = AVCaptureVideoDataOutput()

let captureSession = AVCaptureSession()

override func viewDidLoad() {
    super.viewDidLoad()

    captureSession.sessionPreset = AVCaptureSessionPreset640x480
    let devices = AVCaptureDevice.devices()

    for device in devices {
        if (device.hasMediaType(AVMediaTypeVideo)) {
            if device.position == AVCaptureDevicePosition.Back {
                captureDevice = device as? AVCaptureDevice
                if captureDevice != nil {
                    beginSession()
                }
            }   
        }
    }
}

func beginSession() {
    var err : NSError? = nil
    captureSession.addInput(AVCaptureDeviceInput(device: captureDevice, error: &err))

    if err != nil {
        println("Error: \(err?.localizedDescription)")
    }

    videoCaptureOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey:kCVPixelFormatType_32BGRA]
    videoCaptureOutput.alwaysDiscardsLateVideoFrames = true

    captureSession.addOutput(videoCaptureOutput)

    previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
    self.view.layer.addSublayer(previewLayer)
    previewLayer?.frame = CGRectMake(0, 0, screenWidth, screenHeight)
    captureSession.startRunning()

    var startVideoBtn = UIButton(frame: CGRectMake(0, screenHeight/2, screenWidth, screenHeight/2))
        startVideoBtn.addTarget(self, action: "startVideo", forControlEvents: UIControlEvents.TouchUpInside)
        self.view.addSubview(startVideoBtn)

    var stopVideoBtn = UIButton(frame: CGRectMake(0, 0, screenWidth, screenHeight/2))
        stopVideoBtn.addTarget(self, action: "stopVideo", forControlEvents: UIControlEvents.TouchUpInside)
        self.view.addSubview(stopVideoBtn)
}

如果需要,我可以提供更多代码或解释。


14
2017-12-22 15:47


起源




答案:


为获得最佳效果,请阅读 静止和视频媒体捕获 来自的部分 AV基础编程指南

处理来自的帧 AVCaptureVideoDataOutput,你需要一个采用的代表 AVCaptureVideoDataOutputSampleBufferDelegate 协议。代表的 captureOutput 只要写入新帧,就会调用该方法。设置输出的委托时,还必须提供应在其上调用回调的队列。它看起来像这样:

let cameraQueue = dispatch_queue_create("cameraQueue", DISPATCH_QUEUE_SERIAL)
videoCaptureOutput.setSampleBufferDelegate(myDelegate, queue: cameraQueue)
captureSession.addOutput(videoCaptureOutput)

注意: 如果您只想将电影保存到文件中,您可能更喜欢 AVCaptureMovieFileOutput 而不是 AVCaptureVideoDataOutput。在这种情况下,您将不需要队列。但是你仍然需要一个代表,这次采用了 AVCaptureFileOutputRecordingDelegate 协议代替。 (相关方法仍然被称为 captureOutput。)

这是关于部分的一个摘录 AVCaptureMovieFileOutput 从链接到上面的指南:

开始录制

您开始使用录制QuickTime电影 startRecordingToOutputFileURL:recordingDelegate:。你需要提供一个   基于文件的URL和委托。 URL不得标识现有的URL   文件,因为电影文件输出不会覆盖现有的   资源。您还必须具有写入指定的权限   位置。代表必须符合    AVCaptureFileOutputRecordingDelegate 协议,并且必须实现    captureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error:   方法。

AVCaptureMovieFileOutput *aMovieFileOutput = <#Get a movie file output#>;
NSURL *fileURL = <#A file URL that identifies the output location#>;
[aMovieFileOutput startRecordingToOutputFileURL:fileURL recordingDelegate:<#The delegate#>];

在执行中    captureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error:,   代表可能会将生成的电影写入相机胶卷相册。   它还应检查可能发生的任何错误。


13
2018-05-10 15:57



请注意cameraQueue的两个可能的更新。首先,更新为swift 3.其次,将qos提升到userInteractive避免丢帧 DispatchQueue(label: "com.myApp.cameraQueue", attributes: [], target: DispatchQueue.global(qos: .userInteractive)) - Glavid