iOS Swift AVFoundation视频录制AVCaptureMovieFileOutput isRecording值每次为false [英] iOS Swift AVFoundation Video Recording AVCaptureMovieFileOutput isRecording value false every time

查看:103
本文介绍了iOS Swift AVFoundation视频录制AVCaptureMovieFileOutput isRecording值每次为false的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用带有前后摄像头的AVFoundation Framework录制和保存视频.我能够开始会话,但无法将视频记录保存在文档目录中. 我检查movieOutput.isRecording它每次给出false.因此,因此也不会调用委托输出方法.开始录制时甚至不会调用开始"委托.

I'm trying to record and save video using AVFoundation Framework with both front and rear camera. I'm able to start session but unable to save video recording in document directory. I check movieOutput.isRecording it gives false every time. Hence the delegate output method is also not called due to this. Even Start delegate is not called on start recording.

import UIKit
import Foundation
import AVKit
import AVFoundation

class AppVideoRecorder: NSObject {
    
    private var session = AVCaptureSession()
    private var movieOutput = AVCaptureMovieFileOutput()
    private var camera: AVCaptureDevice?
    private var activeInput: AVCaptureDeviceInput?
    private var previewLayer = AVCaptureVideoPreviewLayer()
    
    private var renderView: UIView!
    var isFrontCamera: Bool = false
    
    init(for view: UIView) {
        self.renderView = view
    }
    
    deinit {
        print("Called")
    }
    
    func setupSession() {
        
        self.session.sessionPreset = .high
       
        // Setup Camera
        self.camera = AVCaptureDevice.default(
            .builtInWideAngleCamera,
            for: .video,
            position: self.isFrontCamera ? .front : .back
        )
                
        if let camera = self.camera {
            do {
                let input = try AVCaptureDeviceInput(device: camera)
                if self.session.canAddInput(input) {
                    self.session.addInput(input)
                    self.activeInput = input
                }
            } catch {
                print(error)
            }
        }
        
        // Setup Microphone
        if let microphone = AVCaptureDevice.default(for: .audio) {
            do {
                let micInput = try AVCaptureDeviceInput(device: microphone)
                if self.session.canAddInput(micInput) {
                    self.session.addInput(micInput)
                }
            } catch {
                print(error)
            }
        }
        
        // Movie output
        if self.session.canAddOutput(self.movieOutput) {
            self.session.addOutput(self.movieOutput)
        }
    }
    
    func setupPreview() {
        // Configure previewLayer
        self.previewLayer = AVCaptureVideoPreviewLayer(session: self.session)
        self.previewLayer.frame = self.renderView.bounds
        self.previewLayer.videoGravity = .resizeAspectFill
        self.renderView.layer.addSublayer(self.previewLayer)
    }
    
    func startSession() {
        if self.session.isRunning { return }
        DispatchQueue.main.async {
            self.session.startRunning()
        }
    }
    
    func stopSession() {
        if self.session.isRunning {
            DispatchQueue.main.async {
                self.session.stopRunning()
            }
        }
    }
    
    func removeInput() {
        guard let input = self.activeInput else { return }
        self.session.removeInput(input)
    }
 
    func isCameraOn(completion: @escaping (Bool) -> Void) {
        if AVCaptureDevice.authorizationStatus(for: .video) == .authorized {
            completion(true)
        } else {
            AVCaptureDevice.requestAccess(for: .video,
                                          completionHandler: { (granted) in
                completion(granted)
            })
        }
    }
    
    func toggleCamera() {
        
        self.session.beginConfiguration()
                
        for input in self.session.inputs {
            if let inputObj = input as? AVCaptureDeviceInput {
                self.session.removeInput(inputObj)
            }
        }
        
        self.camera = AVCaptureDevice.default(
            .builtInWideAngleCamera,
            for: .video,
            position: self.isFrontCamera ? .front : .back
        )

        if let camera = self.camera {
            do {
                let input = try AVCaptureDeviceInput(device: camera)
                if self.session.canAddInput(input) {
                    self.session.addInput(input)
                    self.activeInput = input
                }
            } catch {
                print(error)
            }
        }

        self.session.commitConfiguration()
    }
    
}

extension AppVideoRecorder: AVCaptureFileOutputRecordingDelegate {
    
    private var currentVideoOrientation: AVCaptureVideoOrientation {
         var orientation: AVCaptureVideoOrientation

         switch UIDevice.current.orientation {
         case .portrait:
             orientation = AVCaptureVideoOrientation.portrait
         case .landscapeRight:
             orientation = AVCaptureVideoOrientation.landscapeLeft
         case .portraitUpsideDown:
             orientation = AVCaptureVideoOrientation.portraitUpsideDown
         default:
             orientation = AVCaptureVideoOrientation.landscapeRight
         }

         return orientation
     }
    
    func recordVideo() {
        if self.movieOutput.isRecording { // FALSE EVERY TIME
           self.stopRecording()
        } else {
            self.startRecording()
        }
    }
    
    private func startRecording() {
        
        guard let connection = self.movieOutput.connection(with: .video),
            let device = self.activeInput?.device else { return }
        // handle return error

        if connection.isVideoOrientationSupported {
            connection.videoOrientation = self.currentVideoOrientation
        }
        
        if connection.isVideoStabilizationSupported {
            connection.preferredVideoStabilizationMode = .auto
        }

        if device.isSmoothAutoFocusSupported {
            do {
                try device.lockForConfiguration()
                device.isSmoothAutoFocusEnabled = false
                device.unlockForConfiguration()
            } catch {
                print("Error setting configuration: \(error)")
            }
            
        }
        
        let paths = FileManager.default.urls(for: .documentDirectory,
                                             in: .userDomainMask)
        guard let path = paths.first else { return }
        let fileUrl = path.appendingPathComponent("celeb_video.mp4")
        try? FileManager.default.removeItem(at: fileUrl)
        
        self.movieOutput.startRecording(to: fileUrl, recordingDelegate: self)
    }
    
    private func stopRecording() {
        self.movieOutput.stopRecording()
    }
    
    func fileOutput(_ output: AVCaptureFileOutput,
                    didFinishRecordingTo outputFileURL: URL,
                    from connections: [AVCaptureConnection],
                    error: Error?) {
        print("DELEGATE CALL BACK")
        if let error = error {
            //do something
            print(error)
        } else {
            //do something
            print(outputFileURL.path)
            //            UISaveVideoAtPathToSavedPhotosAlbum(outputFileURL.path, nil, nil, nil)
        }
    }

    func fileOutput(_ output: AVCaptureFileOutput,
                didStartRecordingTo fileURL: URL,
                from connections: [AVCaptureConnection]) {
    print("didStartRecordingTo CALL BACK:", fileURL.path)
}

}

这是我在视图控制器中的调用代码. recordingView UIView

Here is my calling code in view controller. recordingView is UIView

private lazy var recorder: AppVideoRecorder = {
    return AppVideoRecorder(for: self.recordingView)
}()

@IBAction func recordingAction(_ sender: UIButton) {
    sender.isSelected.toggle()
    if sender.isSelected {
        self.recorder.setupSession()
        self.recorder.setupPreview()
        self.recorder.startSession()
        self.recorder.recordVideo()
    } else {
        self.recorder.recordVideo()
        self.recorder.removeInput()
        self.recorder.stopSession()
    }
}

@IBAction func swapCameraAction(_ sender: UIButton) {
    sender.isSelected.toggle()
    self.recorder.isFrontCamera = sender.isSelected
    self.recorder.toggleCamera()
}

请让我知道我错过了什么.

Please let me know what I missed.

推荐答案

从链接立即使用AVCaptureMovieFileOutput开始录制视频

我已经添加了通知,现在它开始工作了,因为它需要一些时间才能开始.

I have added notifications, now it is working as it takes time to start.

private func setupNotifications() {
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(sessionDidStartRunning(_:)),
                                           name: .AVCaptureSessionDidStartRunning,
                                           object: nil)
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(sessionDidStopRunning(_:)),
                                           name: .AVCaptureSessionDidStopRunning,
                                           object: nil)
}

@objc
private func sessionDidStartRunning(_ notification: NSNotification) {
    self.startRecording()
}

@objc
private func sessionDidStopRunning(_ notification: NSNotification) {
    
}

这篇关于iOS Swift AVFoundation视频录制AVCaptureMovieFileOutput isRecording值每次为false的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆