SwiftUI通过实时预览录制视频

试图制作一个允许用户使用30秒计时器录制视频的屏幕,然后将其发送到服务器。问题在于未调用委托方法(请参见第二代码部分)。

我所做的是 PreviewView 作为UIView,时间和会话设置。即使当我检查 captureSession.isRecording 时,它也会显示 false

已更新

ViewRepresentable

struct VideoRecordingView: UIViewRepresentable {

    @Binding var timeLeft: Int
    @Binding var onComplete: Bool
    @Binding var recording: Bool
    func makeUIView(context: UIViewRepresentableContext<VideoRecordingView>) -> PreviewView {
        let recordingView = PreviewView()
        recordingView.onComplete = {
            self.onComplete = true
        }

        recordingView.onRecord = { timeLeft,totalShakes in
            self.timeLeft = timeLeft
            self.recording = true
        }

        recordingView.onReset = {
            self.recording = false
            self.timeLeft = 30
        }
        return recordingView
    }

    func updateUIView(_ uiViewController: PreviewView,context: UIViewRepresentableContext<VideoRecordingView>) {

    }
}

查看

extension PreviewView: AVCaptureFileOutputRecordingDelegate{
    func fileOutput(_ output: AVCaptureFileOutput,didFinishRecordingTo outputFileURL: URL,from connections: [AVCaptureConnection],error: Error?) {
        print(outputFileURL.absoluteString) // Not called
    }
}

class PreviewView: UIView {
    private var captureSession: AVCaptureSession?
       private var shakeCountDown: Timer?
       let videoFileOutput = AVCaptureMovieFileOutput()
       var recordingDelegate:AVCaptureFileOutputRecordingDelegate!
       var recorded = 0
       var secondsToReachgoal = 30

       var onRecord: ((Int,Int)->())?
       var onReset: (() -> ())?
       var onComplete: (() -> ())?

    init() {
        super.init(frame: .zero)

        var allowedaccess = false
        let blocker = DispatchGroup()
        blocker.enter()
        AVCaptureDevice.requestaccess(for: .video) { flag in
            allowedaccess = flag
            blocker.leave()
        }
        blocker.wait()

        if !allowedaccess {
            print("!!! NO accESS TO CAMERA")
            return
        }

        // setup session
        let session = AVCaptureSession()
        session.beginconfiguration()

        let videoDevice = AVCaptureDevice.default(.builtInWideAngleCamera,for: .video,position: .front)
        guard videoDevice != nil,let videoDeviceInput = try? AVCaptureDeviceInput(device: videoDevice!),session.canAddInput(videoDeviceInput) else {
            print("!!! NO CAMERA DETECTED")
            return
        }
        session.addInput(videoDeviceInput)
        session.commitConfiguration()
        self.captureSession = session
    }

    override class var layerClass: AnyClass {
        AVCaptureVideoPreviewLayer.self
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    var videoPreviewLayer: AVCaptureVideoPreviewLayer {
        return layer as! AVCaptureVideoPreviewLayer
    }

    override func didmoveToSuperview() {
        super.didmoveToSuperview()
        recordingDelegate = self
        startTimers()
        startRecording()
        if nil != self.superview {
            self.videoPreviewLayer.session = self.captureSession
            self.videoPreviewLayer.videoGravity = .resizeAspect
            self.captureSession?.startRunning()
        } else {
            self.captureSession?.stopRunning()
        }
    }

    private func onTimerFires(){
        print("? RECORDING \(videoFileOutput.isRecording)")
        secondsToReachgoal -= 1
        recorded += 1
        onRecord?(secondsToReachgoal,recorded)

        if(secondsToReachgoal == 0){
            stopRecording()
            shakeCountDown?.invalidate()
            shakeCountDown = nil
            onComplete?()
            videoFileOutput.stopRecording()
        }
    }

    func startTimers(){
        if shakeCountDown == nil {
            shakeCountDown = Timer.scheduledTimer(withTimeInterval: 1,repeats: true) { [weak self] (timer) in
                self?.onTimerFires()
            }
        }
    }

    func startRecording(){
        captureSession?.addOutput(videoFileOutput)

        let documentsURL = FileManager.default.urls(for: .documentDirectory,in: .userDomainmask)[0]
        let filePath = documentsURL.appendingPathComponent("tempPZDC")

        videoFileOutput.startRecording(to: filePath,recordingDelegate: recordingDelegate)
    }

    func stopRecording(){
        videoFileOutput.stopRecording()
        print("? RECORDING \(videoFileOutput.isRecording)")
    }
}
h286700143game 回答:SwiftUI通过实时预览录制视频

您需要在致电self.captureSession?.startRunning()之前致电startRecording()

,

这是一个录音的实际例子。点击Toggle Completion停止录制。

import SwiftUI
import AVKit


struct RecordingView: View {
    @State private var timer = 5
    @State private var onComplete = false
    @State private var recording = false
    
    var body: some View {
        ZStack {
            VideoRecordingView(timeLeft: $timer,onComplete: $onComplete,recording: $recording)
            VStack {
                Button(action: {
                    self.recording.toggle()
                },label: {
                    Text("Toggle Recording")
                })
                    .foregroundColor(.white)
                    .padding()
                Button(action: {
                    self.timer -= 1
                    print(self.timer)
                },label: {
                    Text("Toggle timer")
                })
                    .foregroundColor(.white)
                    .padding()
                Button(action: {
                    self.onComplete.toggle()
                },label: {
                    Text("Toggle completion")
                })
                    .foregroundColor(.white)
                    .padding()
            }
        }
    }
    
}

struct RecordingView_Previews: PreviewProvider {
    static var previews: some View {
        RecordingView()
    }
}


struct VideoRecordingView: UIViewRepresentable {
    
    @Binding var timeLeft: Int
    @Binding var onComplete: Bool
    @Binding var recording: Bool
    func makeUIView(context: UIViewRepresentableContext<VideoRecordingView>) -> PreviewView {
        let recordingView = PreviewView()
        recordingView.onComplete = {
            self.onComplete = true
        }
        
        recordingView.onRecord = { timeLeft,totalShakes in
            self.timeLeft = timeLeft
            self.recording = true
        }
        
        recordingView.onReset = {
            self.recording = false
            self.timeLeft = 30
        }
        return recordingView
    }
    
    func updateUIView(_ uiViewController: PreviewView,context: UIViewRepresentableContext<VideoRecordingView>) {
        
    }
}

extension PreviewView: AVCaptureFileOutputRecordingDelegate{
    func fileOutput(_ output: AVCaptureFileOutput,didFinishRecordingTo outputFileURL: URL,from connections: [AVCaptureConnection],error: Error?) {
        print(outputFileURL.absoluteString)
    }
}

class PreviewView: UIView {
    private var captureSession: AVCaptureSession?
    private var shakeCountDown: Timer?
    let videoFileOutput = AVCaptureMovieFileOutput()
    var recordingDelegate:AVCaptureFileOutputRecordingDelegate!
    var recorded = 0
    var secondsToReachGoal = 30
    
    var onRecord: ((Int,Int)->())?
    var onReset: (() -> ())?
    var onComplete: (() -> ())?
    
    init() {
        super.init(frame: .zero)
        
        var allowedAccess = false
        let blocker = DispatchGroup()
        blocker.enter()
        AVCaptureDevice.requestAccess(for: .video) { flag in
            allowedAccess = flag
            blocker.leave()
        }
        blocker.wait()
        
        if !allowedAccess {
            print("!!! NO ACCESS TO CAMERA")
            return
        }
        
        // setup session
        let session = AVCaptureSession()
        session.beginConfiguration()
        
        let videoDevice = AVCaptureDevice.default(.builtInWideAngleCamera,for: .video,position: .front)
        guard videoDevice != nil,let videoDeviceInput = try? AVCaptureDeviceInput(device: videoDevice!),session.canAddInput(videoDeviceInput) else {
            print("!!! NO CAMERA DETECTED")
            return
        }
        session.addInput(videoDeviceInput)
        session.commitConfiguration()
        self.captureSession = session
    }
    
    override class var layerClass: AnyClass {
        AVCaptureVideoPreviewLayer.self
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    var videoPreviewLayer: AVCaptureVideoPreviewLayer {
        return layer as! AVCaptureVideoPreviewLayer
    }
    
    override func didMoveToSuperview() {
        super.didMoveToSuperview()
        recordingDelegate = self
        startTimers()
        if nil != self.superview {
            self.videoPreviewLayer.session = self.captureSession
            self.videoPreviewLayer.videoGravity = .resizeAspect
            self.captureSession?.startRunning()
            self.startRecording()
        } else {
            self.captureSession?.stopRunning()
        }
    }
    
    private func onTimerFires(){
        print("? RECORDING \(videoFileOutput.isRecording)")
        secondsToReachGoal -= 1
        recorded += 1
        onRecord?(secondsToReachGoal,recorded)
        
        if(secondsToReachGoal == 0){
            stopRecording()
            shakeCountDown?.invalidate()
            shakeCountDown = nil
            onComplete?()
            videoFileOutput.stopRecording()
        }
    }
    
    func startTimers(){
        if shakeCountDown == nil {
            shakeCountDown = Timer.scheduledTimer(withTimeInterval: 1,repeats: true) { [weak self] (timer) in
                self?.onTimerFires()
            }
        }
    }
    
    func startRecording(){
        captureSession?.addOutput(videoFileOutput)
        
        let documentsURL = FileManager.default.urls(for: .documentDirectory,in: .userDomainMask)[0]
        let filePath = documentsURL.appendingPathComponent("tempPZDC")
        
        videoFileOutput.startRecording(to: filePath,recordingDelegate: recordingDelegate)
    }
    
    func stopRecording(){
        videoFileOutput.stopRecording()
        print("? RECORDING \(videoFileOutput.isRecording)")
    }
}
本文链接:https://www.f2er.com/2470345.html

大家都在问