从另一个队列AVFoundation调度委托回调到主队列

时间:2017-03-06 20:57:51

标签: ios multithreading avfoundation

我正在处理一个包含在基本viewController中的摄像头,带有一个用于回调的委托样式接口,所以我作为客户端所做的只是摄像机视图控制器的子类,实现委托方法,并添加UI按钮。 我的问题是关于录制视频。视频录制在独特的后台任务上启动,以确保可以将录制内容写入临时文件。这是在我的 private let sessionQueue = DispatchQueue(label: "com.andrewferrarone.sessionQueue")会话队列:

public func startRecording()
{
    guard let movieFileOutput = self.movieFileOutput else { return }

    //get video preview layer's video orientation on main queue
    guard let videoPreviewLayerOrientation = self.previewView.videoPreviewLayer?.connection.videoOrientation else {
        print("handleRecord: videoPreviewLayer is nil")
        return
    }

    self.sessionQueue.async {

        if !movieFileOutput.isRecording {
            if UIDevice.current.isMultitaskingSupported {

                self.backgroundRecordingID = UIApplication.shared.beginBackgroundTask(expirationHandler: nil)
        }

        //update orientation on the movie file output video connection before recording
        let movieFileOutputConnection = self.movieFileOutput?.connection(withMediaType: AVMediaTypeVideo)
            movieFileOutputConnection?.videoOrientation = videoPreviewLayerOrientation

        //start recording to a temporary file:
        let outputFileName = UUID().uuidString
        let outputFilePath = (NSTemporaryDirectory() as NSString).appendingPathComponent((outputFileName as NSString).appendingPathExtension("mov")!)
            movieFileOutput.startRecording(toOutputFileURL: URL(fileURLWithPath: outputFilePath), recordingDelegate: self)
        }
    }
}

所以录制设置为调派到self.sessionQueue的后台任务。当我停止录制时,我收到AVCaptureFileOutputRecordingDelegate方法。在这个方法中,我想用filepath回调我的委托,然后清理。如何在清除发生并删除临时文件之前,如何确保委托可以从临时文件路径中保留记录?

 public func capture(_ captureOutput: AVCaptureFileOutput!, didFinishRecordingToOutputFileAt outputFileURL: URL!, fromConnections connections: [Any]!, error: Error!)
{
    //cleanup func for later
    func cleanup()
    {
        let path = outputFileURL.path

        if FileManager.default.fileExists(atPath: path) {
            do {
                try FileManager.default.removeItem(atPath: path)
            }
            catch let error {
                print("Could not remove file at url: \(outputFileURL), error: \(error.localizedDescription)")
            }
        }

        if let currentBackgroundRecordingID = self.backgroundRecordingID {
            self.backgroundRecordingID = UIBackgroundTaskInvalid

            if currentBackgroundRecordingID != UIBackgroundTaskInvalid {
                UIApplication.shared.endBackgroundTask(currentBackgroundRecordingID)
            }
        }
    }

    var success = true

    if error != nil {
        print("Movie file finishing error: \(error)")
        success = ((error as NSError).userInfo[AVErrorRecordingSuccessfullyFinishedKey] as AnyObject).boolValue
    }

    DispatchQueue.main.async {
        self.delegate?.camera(self, didFinishRecordingToOutputFileAt: outputFileURL, success: success)
    }

    cleanup()
}

所以我使用结果将我的委托调回主队列,但是在调用我的委托后,我是否应该在主队列上调用cleanup()?这样安全吗?或者如果我按照它现在的方式离开它,那么我们就在self.sessionQueue,我不确定在委托方法实现有时间保持记录之前是否会发生cleanup()。如果有人能给我一些有关正在发生的事情以及在这里做什么最安全的事情,那就太棒了。根据apple,文档说不要假设在特定线程上调用AVCaptureFileOutputRecordingDelegate didFinishRecordingToOutputFileAt方法。感谢您的时间和帮助!

1 个答案:

答案 0 :(得分:1)

怎么样:

DispatchQueue.main.async {
    self.delegate?.camera(self, didFinishRecordingToOutputFileAt: outputFileURL, success: success)
    self.sessionQueue.async {
        cleanup()
    }
}

我认为这是处理这种情况的标准方法。委托方法完成后,您假定代理已完成该文件(或将其复制到其他位置)。