【问题标题】:iOS Swift AVFoundation Video Recording AVCaptureMovieFileOutput isRecording value false every timeiOS Swift AVFoundation Video Recording AVCaptureMovieFileOutput isRecording value false 每次
【发布时间】:2020-07-22 06:51:39
【问题描述】:

我正在尝试使用带有前置和后置摄像头的 AVFoundation 框架来录制和保存视频。我可以开始会话,但无法将视频录制保存在文档目录中。 我检查movieOutput.isRecording 它每次都给出false。因此委托输出方法也不会因此而被调用。开始录制时甚至不会调用 Start delegate。

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)
}

}

这是我在视图控制器中的调用代码。 recordingViewUIView

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()
}

请告诉我我错过了什么。

【问题讨论】:

  • 似乎缺少的一件事是将 self 设置为电影输出的代表。
  • @vzsg:我已经在startRecording函数中添加了录制委托。让我知道代表我需要添加的任何其他内容。
  • 哦,对了。对不起,当时的噪音。我想您已经尝试过单步执行代码以查看没有警卫出差?
  • 是的,我也通过断点和日志检查过,守卫让条件工作正常
  • 您是否在plist中添加了访问相机和照片库的条目?

标签: ios swift avfoundation video-capture


【解决方案1】:

来自链接Starting video recording immediately with AVCaptureMovieFileOutput

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

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) {
    
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多