繁体   English   中英

Swift IOS 使用 AVFoundation 录制视频和音频

[英]Swift IOS Record Video and Audio with AVFoundation

我能够通过在此处解决此问题来成功获取录制的视频

基本上

  1. 继承自AVCaptureFileOutputRecordingDelegate原型
  2. 循环访问可用设备
  3. 使用相机创建会话
  4. 开始录音
  5. 停止录音
  6. 通过实现上述原型的方法获取录制视频

但该文件不附带音频。

根据这个问题,我必须单独录制音频并使用提到的类合并视频和音频

但我不知道如何同时实现视频和音频录制。

for device in devices {
    // Make sure this particular device supports video
    if (device.hasMediaType(AVMediaTypeVideo)) {
        // Finally check the position and confirm we've got the back camera
        if(device.position == AVCaptureDevicePosition.Back) {
            captureDevice = device as? AVCaptureDevice
            if captureDevice != nil {
                print("Capture device found")

                beginSession()
            }
        }
    }
}

在这个循环中,只有可用的设备类型是 .Front 和 .Back

以下是使用 AVFoundation 框架录制带音频视频的方法。 步骤是:

1. 准备会议:

self.captureSession = AVCaptureSession()

2. 准备可用的视频和音频设备:

let session = AVCaptureDevice.DiscoverySession.init(deviceTypes:[.builtInWideAngleCamera, .builtInMicrophone], mediaType: AVMediaType.video, position: AVCaptureDevice.Position.unspecified)
        
let cameras = (session.devices.compactMap{$0})
        
for camera in cameras {
    if camera.position == .front {
        self.frontCamera = camera
    }
    if camera.position == .back {
        self.rearCamera = camera

        try camera.lockForConfiguration()
        camera.focusMode = .continuousAutoFocus
        camera.unlockForConfiguration()
    }
}

3. 准备会话输入:

guard let captureSession = self.captureSession else {
    throw CameraControllerError.captureSessionIsMissing
}

if let rearCamera = self.rearCamera {
    self.rearCameraInput = try AVCaptureDeviceInput(device: rearCamera)
    if captureSession.canAddInput(self.rearCameraInput!) {
        captureSession.addInput(self.rearCameraInput!)
        self.currentCameraPosition = .rear
    } else {
        throw CameraControllerError.inputsAreInvalid
    }
} else if let frontCamera = self.frontCamera {
    self.frontCameraInput = try AVCaptureDeviceInput(device: frontCamera)
    if captureSession.canAddInput(self.frontCameraInput!) {
        captureSession.addInput(self.frontCameraInput!)
        self.currentCameraPosition = .front
    } else {
        throw CameraControllerError.inputsAreInvalid
    }
} else {
    throw CameraControllerError.noCamerasAvailable
}

// Add audio input
if let audioDevice = self.audioDevice {
    self.audioInput = try AVCaptureDeviceInput(device: audioDevice)
    if captureSession.canAddInput(self.audioInput!) {
        captureSession.addInput(self.audioInput!)
    } else {
        throw CameraControllerError.inputsAreInvalid
    }
}

4. 准备输出:

self.videoOutput = AVCaptureMovieFileOutput()
if captureSession.canAddOutput(self.videoOutput!) {
    captureSession.addOutput(self.videoOutput!)
}
captureSession.startRunning()

5. 开始录音:

func recordVideo(completion: @escaping (URL?, Error?) -> Void) {
    guard let captureSession = self.captureSession, captureSession.isRunning else {
        completion(nil, CameraControllerError.captureSessionIsMissing)
        return
    }
    let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    let fileUrl = paths[0].appendingPathComponent("output.mp4")
    try? FileManager.default.removeItem(at: fileUrl)
    videoOutput!.startRecording(to: fileUrl, recordingDelegate: self)
    self.videoRecordCompletionBlock = completion
}

6.停止录音:

func stopRecording(completion: @escaping (Error?) -> Void) {
    guard let captureSession = self.captureSession, captureSession.isRunning else {
        completion(CameraControllerError.captureSessionIsMissing)
        return
    }
    self.videoOutput?.stopRecording()
}

7. 实现委托:

func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
    if error == nil {
        //do something
    } else {
        //do something
    }
}

我从这里得到了想法: https : //www.appcoda.com/avfoundation-swift-guide/

这是完整的项目https://github.com/rubaiyat6370/iOS-Tutorial/

找到答案,此答案与代码一致

它可以简单地通过

  1. 声明另一个捕获设备变量
  2. 循环遍历设备并初始化相机和音频捕获设备变量
  3. 将音频输入添加到会话

代码

var captureDevice : AVCaptureDevice?
var captureAudio :AVCaptureDevice?

循环设备和初始化捕获设备

var captureDeviceVideoFound: Bool = false
var captureDeviceAudioFound:Bool = false

// Loop through all the capture devices on this phone
for device in devices {
// Make sure this particular device supports video
    if (device.hasMediaType(AVMediaTypeVideo)) {
// Finally check the position and confirm we've got the front camera
        if(device.position == AVCaptureDevicePosition.Front) {

            captureDevice = device as? AVCaptureDevice //initialize video
            if captureDevice != nil {
                print("Capture device found")
                captureDeviceVideoFound = true; 
            }
        }
    }
    if(device.hasMediaType(AVMediaTypeAudio)){
        print("Capture device audio init")
        captureAudio = device as? AVCaptureDevice //initialize audio
        captureDeviceAudioFound = true
    }
}
if(captureDeviceAudioFound && captureDeviceVideoFound){
    beginSession() 
}

内部会议

try captureSession.addInput(AVCaptureDeviceInput(device: captureDevice))
try captureSession.addInput(AVCaptureDeviceInput(device: captureAudio))

这将输出带有音频的视频文件。 无需合并音频或做任何事情。

这个苹果文档有帮助

我也有这个问题,但是当我分组添加视频输入和声音输入后,音频工作正常。 这是我添加输入的代码。

if (cameraSession.canAddInput(deviceInput) == true && cameraSession.canAddInput(audioDeviceInput) == true) {//detects if devices can be added
    cameraSession.addInput(deviceInput)//adds video
    cameraSession.addInput(audioDeviceInput)//adds audio
}

另外我发现你必须先有视频输入,否则不会有音频。 我最初将它们放在两个 if 语句中,但我发现将它们放在一个中可以让视频和音频一起录制。 希望这可以帮助。

按照@Mumu 的回答,但它对我不起作用,因为调用 AVCaptureDevice.DiscoverySession.init 只返回视频设备。

这是我在 iOS 14、Swift 5 上运行的版本:

var captureSession: AVCaptureSession? = nil
var camera: AVCaptureDevice? = nil
var microphone: AVCaptureDevice? = nil
var videoOutput: AVCaptureFileOutput? = nil
var previewLayer: AVCaptureVideoPreviewLayer? = nil

func findDevices() {
    camera = nil
    microphone = nil

    //Search for video media type and we need back camera only
    let session = AVCaptureDevice.DiscoverySession.init(deviceTypes:[.builtInWideAngleCamera],
            mediaType: AVMediaType.video, position: AVCaptureDevice.Position.back)
    var devices = (session.devices.compactMap{$0})
    //Search for microphone
    let asession = AVCaptureDevice.DiscoverySession.init(deviceTypes:[.builtInMicrophone],
            mediaType: AVMediaType.audio, position: AVCaptureDevice.Position.unspecified)
    //Combine all devices into one list
    devices.append(contentsOf: asession.devices.compactMap{$0})
    for device in devices {
        if device.position == .back {
            do {
                try device.lockForConfiguration()
                device.focusMode = .continuousAutoFocus
                device.flashMode = .off
                device.whiteBalanceMode = .continuousAutoWhiteBalance
                device.unlockForConfiguration()
                camera = device
            } catch {
            }
        }
        if device.hasMediaType(.audio) {
            microphone = device
        }
    }
}

func initVideoRecorder()->Bool {
    captureSession = AVCaptureSession()
    guard let captureSession = captureSession else {return false}

    captureSession.sessionPreset = .hd4K3840x2160
    findDevices()

    guard let camera = camera else { return false}
    do {
        let cameraInput = try AVCaptureDeviceInput(device: camera)
        captureSession.addInput(cameraInput)
    } catch {
        self.camera = nil
        return false
    }

    if let audio = microphone {
        do {
            let audioInput = try AVCaptureDeviceInput(device: audio)
            captureSession.addInput(audioInput)
        } catch {
        }
    }

    videoOutput = AVCaptureMovieFileOutput()
    if captureSession.canAddOutput(videoOutput!) {
        captureSession.addOutput(videoOutput!)
        captureSession.startRunning()
        videoOutput?.connection(with: .video)?.videoOrientation = .landscapeRight
        previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        previewLayer?.videoGravity = .resizeAspect
        previewLayer?.connection?.videoOrientation = .landscapeRight
        return true
    }

    return false
}

func startRecording()->Bool {
    guard let captureSession = captureSession, captureSession.isRunning else {return false}
    let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    let fileUrl = paths[0].appendingPathComponent(getVideoName())
    try? FileManager.default.removeItem(at: fileUrl)
    videoOutput?.startRecording(to: fileUrl, recordingDelegate: self)
    return true
}

用音频录制视频

//获取视频设备

if let devices = AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo) as? [AVCaptureDevice] {
    for device in devices {
        if device.hasMediaType(AVMediaTypeVideo) {
            if device.position == AVCaptureDevicePosition.back {
                videoCaptureDevice = device
            }
        }
    }
    if videoCaptureDevice != nil {
        do {
            // Add Video Input
            try self.captureSession.addInput(AVCaptureDeviceInput(device: videoCaptureDevice))
            // Get Audio Device
            let audioInput = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeAudio)
            //Add Audio Input
            try self.captureSession.addInput(AVCaptureDeviceInput(device: audioInput))
            self.previewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession)
            previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
            previewLayer.connection.videoOrientation = AVCaptureVideoOrientation.portrait
            self.videoView.layer.addSublayer(self.previewLayer)
            //Add File Output
            self.captureSession.addOutput(self.movieOutput)
            captureSession.startRunning()
        } catch {
            print(error)
        }
    }
}

有关更多详细信息,请参阅此链接:

https://medium.com/@santhosh3386/ios-avcapturesession-record-video-with-audio-23c8f8c9a8f8

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM