iOS Swift AVFoundation Video Recording Значение AVCaptureMovieFileOutput isRecording false каждый раз

Я пытаюсь записать и сохранить видео с помощью AVFoundation Framework как с передней, так и с задней камерой. Я могу начать сеанс, но не могу сохранить видеозапись в каталоге документов. Я проверяю movieOutput.isRecording, каждый раз выдает false. Следовательно, метод вывода делегата также не вызывается из-за этого. Даже делегат Start не вызывается при начале записи.

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

Пожалуйста, дайте мне знать, что я пропустил.


person Abhishek Thapliyal    schedule 22.07.2020    source источник
comment
Одна вещь, которая, кажется, отсутствует, — это установка себя в качестве делегата вывода фильма.   -  person vzsg    schedule 22.07.2020
comment
@vzsg: я уже добавил в функцию startRecording запись делегата. Дайте мне знать, что еще делегат мне нужно добавить.   -  person Abhishek Thapliyal    schedule 22.07.2020
comment
О, верно. Извините за шум тогда. Полагаю, вы уже пробовали пройтись по коду и убедиться, что никто из охранников не споткнулся?   -  person vzsg    schedule 22.07.2020
comment
Да, я проверил через точку останова и журналы, условия защиты работают нормально   -  person Abhishek Thapliyal    schedule 22.07.2020
comment
Вы добавили записи в plist для доступа к камере и библиотеке фотографий?   -  person MLBDG    schedule 22.07.2020
comment
что я первым добавил   -  person Abhishek Thapliyal    schedule 22.07.2020


Ответы (1)


По ссылке Немедленный запуск записи видео с помощью 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) {
    
}
person Abhishek Thapliyal    schedule 22.07.2020