gpt4 book ai didi

ios - 开始录制视频时 Swift 文件 URL 为零

转载 作者:搜寻专家 更新时间:2023-11-01 06:49:59 25 4
gpt4 key购买 nike

它抛出 Unexpectedly found nil while implicitly unwrapping an Optional value: file 当我开始录制视频时。相机和麦克风权限已启用并包含在 Info.plist 中。

/// UIViewController which displays create screen, camera preview.
class CreateViewController: UIViewController {

/// Delegate which will receive calls on create view controller camera changes.
var delegate: CreateViewControllerDelegate?

private weak var flashlightCameraButton: UIImageView!
private weak var recordingCameraButton: UIImageView!
private weak var switchCamerasCameraButton: UIImageView!

var viewModel: CreateViewModel?

// MARK: - Camera

private var captureSession: AVCaptureSession!
private weak var previewLayer: CALayer!
private weak var captureCamera: AVCaptureDevice!
private weak var audioDevice: AVCaptureDevice!
private weak var videoOutput: AVCaptureMovieFileOutput!
private var isFlashlightOn = false
private var isRecording = false
private var isFrontCamera = false

/// The URL of the challenge video
var challengeVideoURL: URL?

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

override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if isRecording {
videoOutput.stopRecording()
}
}

private func setUp() {
setUpMainView()
setUpCamera()
setUpCameraButtons()
}

private func setUpMainView() {
let appWindow = UIApplication.shared.keyWindow
guard let window = appWindow else { return }
view = UIView(frame: CGRect(x: 0, y: 0, width: window.frame.width, height: window.frame.height))
}

private func setUpCamera() {
let captureSession = AVCaptureSession()
self.captureSession = captureSession
captureSession.sessionPreset = .iFrame1280x720
setUpCameraSide(front: isFrontCamera)
let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
self.previewLayer = previewLayer
view.layer.addSublayer(previewLayer)
previewLayer.frame = view.layer.frame
let videoOutput = AVCaptureMovieFileOutput()
if captureSession.canAddOutput(videoOutput) {
captureSession.addOutput(videoOutput)
}
captureSession.startRunning()
}

private func setUpCameraSide(front: Bool) {
captureSession.beginConfiguration()
if let inputs = captureSession.inputs as? [AVCaptureDeviceInput] {
for input in inputs {
self.captureSession.removeInput(input)
}
}
guard let availableDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: front ? .front : .back) else { return }
// Prepare visual
self.captureCamera = availableDevice
do {
let captureDeviceInput = try AVCaptureDeviceInput(device: captureCamera)
captureSession.addInput(captureDeviceInput)
} catch let error {
// - TODO: display the error
}
// Prepare audio
guard let audioDevice = AVCaptureDevice.default(for: .audio) else { return }
self.audioDevice = audioDevice
do {
let audioDeviceInput = try AVCaptureDeviceInput(device: audioDevice)
captureSession.addInput(audioDeviceInput)
} catch let error {
// - TODO: display the error
}

captureSession.commitConfiguration()
}

private func setUpCameraButtons() {
let flashlightCameraButton = UIImageView()
self.flashlightCameraButton = flashlightCameraButton
view.addSubview(flashlightCameraButton)
flashlightCameraButton.image = UIImage(named: "camera_flashlight")
let flashlightTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(turnOnFlashlight))
flashlightCameraButton.isUserInteractionEnabled = true
flashlightCameraButton.addGestureRecognizer(flashlightTapGestureRecognizer)
flashlightCameraButton.snp.makeConstraints { make in
make.left.equalToSuperview().inset(25)
make.bottom.equalToSuperview().inset(25)
make.height.width.equalTo(50)
}

let recordingCameraButton = UIImageView()
self.recordingCameraButton = recordingCameraButton
view.addSubview(recordingCameraButton)
recordingCameraButton.image = UIImage(named: "camera_record")
let recordingTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(recording))
recordingCameraButton.isUserInteractionEnabled = true
recordingCameraButton.addGestureRecognizer(recordingTapGestureRecognizer)
recordingCameraButton.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.bottom.equalToSuperview().inset(25)
make.height.width.equalTo(70)
}

let switchCamerasCameraButton = UIImageView()
self.switchCamerasCameraButton = switchCamerasCameraButton
view.addSubview(switchCamerasCameraButton)
switchCamerasCameraButton.image = UIImage(named: "camera_switch_camera")
let switchCameraTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(switchCamera))
switchCamerasCameraButton.isUserInteractionEnabled = true
switchCamerasCameraButton.addGestureRecognizer(switchCameraTapGestureRecognizer)
switchCamerasCameraButton.snp.makeConstraints { make in
make.right.equalToSuperview().inset(25)
make.bottom.equalToSuperview().inset(25)
make.height.width.equalTo(50)
}
}

@objc private func turnOnFlashlight() {
isFlashlightOn = !isFlashlightOn
if !isRecording {
if !isFrontCamera, captureCamera.hasTorch {
do {
try captureCamera.lockForConfiguration()
captureCamera.torchMode = captureCamera.isTorchActive ? .on : .off
captureCamera.unlockForConfiguration()
} catch let error {
// - TODO: handle error here
}
}
}
}

@objc private func recording() {
if !isRecording {
delegate?.didStartRecording(self)
NotificationCenter.default.post(name: .recordingStartedNotification, object: nil)
if !captureSession.isRunning {
return
}
let paths = FileManager.default.urls(for: .moviesDirectory, in: .userDomainMask)
let fileURL = paths[0].appendingPathComponent("challenge.mov")
try? FileManager.default.removeItem(at: fileURL)
challengeVideoURL = fileURL
videoOutput.startRecording(to: fileURL, recordingDelegate: self)
} else {
videoOutput.stopRecording()
}
isRecording = !isRecording
}

@objc private func switchCamera() {
isFrontCamera = !isFrontCamera
setUpCameraSide(front: isFrontCamera)
}

private func setUpTimer() {

}
}

// MARK: - Challenge is recorded

extension CreateViewController: AVCaptureFileOutputRecordingDelegate {
func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
guard error == nil else { return }
viewModel?.challengeVideoUrl = outputFileURL
UISaveVideoAtPathToSavedPhotosAlbum(outputFileURL.path, nil, nil, nil)

delegate?.didStopRecording(self)
NotificationCenter.default.post(name: .recordingStoppedNotification, object: nil)
// - TODO: after receiving this call moves user to challenge preview
}
}

fatal error 出现在这一行:videoOutput.startRecording(to: fileURL, recordingDelegate: self)。问题的原因可能是什么?拒绝访问照片库是存储权限吗?

最佳答案

每次你在 Swift 中使用 ! 都会死一只小猫:-)。您的代码具有预期的行为。

您声明:

private weak var videoOutput: AVCaptureMovieFileOutput!

不确定为什么在这里使用 weak,因为此类拥有该对象并且应该保持强引用。

然后在 setUpCamera() 中实例化一个 local 版本的 videoOutput:

let videoOutput = AVCaptureMovieFileOutput()

但永远不要将其分配给实例属性 videoOutput。因此 videoOutputnil 并且你在“

videoOutput.startRecording(to: …) 

要么在 setUpCamera() 添加到捕获 session 后分配属性。

self.videoOutput = videoOutput

或者更好的做法是在类声明中创建实例。

private var videoOutput: AVCaptureMovieFileOutput = AVCaptureMovieFileOutput()

关于ios - 开始录制视频时 Swift 文件 URL 为零,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58183295/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com