我试图记录和保存视频使用AVFoundation框架与前后摄像头。我能够启动会话,但无法将视频记录保存在文档目录中。我每次都检查movieOutput.isRecording
,它给了false
。因此,也没有调用委托输出方法。即使在开始记录时也不调用开始委托。
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
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()
}
请告诉我我错过了什么。
发布于 2020-07-22 09:57:04
来自链接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) {
}
https://stackoverflow.com/questions/63028486
复制相似问题