Home > Blockchain >  AVCaptureFileOutput start recording can't call the delegate
AVCaptureFileOutput start recording can't call the delegate

Time:06-24

I try to write a simple demo to record video by reading the apple's document It has no error but when I call startRecording() method and pass the delegate, the function in the delegate(didstartrecording,didfinishrecording) won't be executed for some how

class Delegate:NSObject,AVCaptureFileOutputRecordingDelegate{
    func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
        func cleanup(){
            let path = outputFileURL.path
            if(FileManager.default.fileExists(atPath: path)){
                do{
                    try FileManager.default.removeItem(atPath: path)
                }
                catch{
                    print("error")
                }
            }
        }
            if error != nil {
                print("error")
            }
            PHPhotoLibrary.requestAuthorization(for: .readWrite){
                status in
                if status == .authorized{
                    PHPhotoLibrary.shared().performChanges{
                        let option = PHAssetResourceCreationOptions()
                        option.shouldMoveFile=true
                        let createrequset = PHAssetCreationRequest.forAsset()
                        createrequset.addResource(with: .video, fileURL: outputFileURL, options: option)
                        
                    }
                completionHandler:{ a,b in
                    if !a {
                        print("error")
                    }
                    cleanup()

                }
                
            }
                else{cleanup()}
        }
    }
    func fileOutput(_ output: AVCaptureFileOutput, didStartRecordingTo fileURL: URL, from connections: [AVCaptureConnection]) {
        print("didstart")
    }
    
    
}
struct ContentView: View {
    private var movieFileOutput: AVCaptureMovieFileOutput = AVCaptureMovieFileOutput()
    private let sessionQueue = DispatchQueue(label: "session queue")
    let a = AVCaptureSession()
    var body: some View {
        ZStack {
            CameraPreview(session: a)
                .ignoresSafeArea()
                .onAppear{
                    let status = AVCaptureDevice.authorizationStatus(for: .video)
                    switch status {
                    case .notDetermined:
                        AVCaptureDevice.requestAccess(for: .video){test in
                            if test {
                                print("settingup")
                                setUpCamera()
                            }
                        }
                    case .restricted:
                        return
                    case .denied:
                        fatalError()
                    case .authorized:
                        setUpCamera()
                        print("settingup")
                        a.startRunning()
                    @unknown default:
                            fatalError()
                        
                    }
            }
            Button("record"){
                record()
            }
        }
            
     }
    func record(){
        sessionQueue.async {
        if movieFileOutput.isRecording == false{
            let movieOutputConnetion = movieFileOutput.connection(with: .video)!
            movieOutputConnetion.videoOrientation = .portrait
            movieFileOutput.setOutputSettings([AVVideoCodecKey:AVVideoCodecType.h264], for: movieOutputConnetion)
            movieOutputConnetion.videoOrientation = .portrait
            let outputFileName = UUID().uuidString
            let outputFilePath = (NSTemporaryDirectory() as NSString).appendingPathComponent((outputFileName as NSString).appendingPathExtension("mov")!)
            print("starting")
            print(movieFileOutput.connections)
            movieFileOutput.startRecording(to: URL(fileURLWithPath: outputFilePath), recordingDelegate: Delegate())
        }
        else {movieFileOutput.stopRecording()}
        }
    }
    func setUpCamera(){
        
        a.beginConfiguration()
        let device = AVCaptureDevice.default(.builtInTelephotoCamera,for:.video,position: .unspecified)
        guard let videoDeviceInput = try? AVCaptureDeviceInput(device:device!),
              a.canAddInput(videoDeviceInput)
        else {return}
        print("added")
        a.addInput(videoDeviceInput)
        let vedio = AVCaptureVideoDataOutput()
        guard a.canAddOutput(vedio)else{return}
        a.sessionPreset = .hd4K3840x2160
        a.addOutput(movieFileOutput)
        print(a.connections)
        a.commitConfiguration()
        
    }
}

I found that apple official code conbine all of them in a Class, is it necessary for this to work?

CodePudding user response:

You don’t hold a reference for the delegate. Try have it as a property on the view for example. Like the session. You can define a ‘deinit’ on the delegate. And see that the ’ AVCaptureMovieFileOutput’ you are using is holding a weak reference to it. And it is probably being removed from the memory right away. As no object holds a reference to it.

The delegate name should indicate a weak reference (i.e the ARC will not increase the reference count for the object) when passed/assigned. Hence as no other object holds a reference to the Delegate() object you have just initialized. Its reference count will zero once you are out of the function context and the ARC will deinit the object and remove from memory.

  • Related