录制iOS 14时切换相机时的AVFoundation帧同步

问题描述

我一直在尝试寻找一种解决方案,以便在使用AVFoundation切换摄像机时允许连续记录。还有其他关于此问题的帖子,没有得到公认的答案,我已经尝试了所有这些方法,但是似乎都没有用。似乎没有太多滞后是可能的,即:(Snapchat,Facebook)。我尝试将 AVAssetWriter 与多个 AVCaptureVideoDataOutput AVCaptureAudioDataOutput 输出结合使用,但这只会导致在切换相机后关闭视频和音频时序。我也尝试过在2个捕获会话之间切换单个输出,但这会导致相同的问题。理想情况下,我需要在捕获后尽快提供视频输出

当前,我正在尝试使用 CMBufferQueue 来收集示例缓冲区,然后将它们返回到AVAssetWriter。但是我的输出显示了几个样本,然后冻结了。

希望得到任何帮助

我当前的一些代码

    var vIsFinished = false
    var aIsFinished = false
    self.videoWriter.startSession(atSourceTime: self.vQueue!.firstPresentationTimeStamp)
    self.videoWriterInput.requestMediaDataWhenReady(on: .init(label: "com.jzyla.CameraTest")) {
        while self.videoWriterInput!.isReadyForMoreMediaData {
            if let buffer = self.vQueue?.dequeueIfDataReady() {
                print("append")
                self.videoWriterInput.append(buffer as! CMSampleBuffer)
            }
            if self.vQueue!.isEmpty {
                self.videoWriterInput.markAsFinished()
                vIsFinished = true
                if vIsFinished && aIsFinished {
                    self.returnVideo()
                    break
                }
            }
        }
    }
    self.audioWriterInput.requestMediaDataWhenReady(on: .init(label: "com.jzyla.CameraTest2")) {
        while self.audioWriterInput!.isReadyForMoreMediaData {
            if let buffer = self.aQueue?.dequeueIfDataReady() {
                print("append")
                self.audioWriterInput.append(buffer as! CMSampleBuffer)
            }
            if self.aQueue!.isEmpty {
                self.audioWriterInput.markAsFinished()
                aIsFinished = true
                if vIsFinished && aIsFinished {
                    self.returnVideo()
                    break
                }
            }
        }
    }

    public func captureOutput(_ output: AVCaptureOutput,didOutput sampleBuffer: CMSampleBuffer,from connection: AVCaptureConnection) {
        if canWrite() {
            if output == self.videoOutput || output == self.videoOutput2 {
                print("vid buffer")
                let timestamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
                if sessionAtSourceTime == nil {
                    sessionAtSourceTime = timestamp
                    self.lastFrameSourceTime = timestamp
                }
            } else if output == self.audioOutput || output == self.audioOutput2 {
                // write audio buffer
                if sessionAtSourceTime != nil {
                    try! self.aQueue?.enqueue(sampleBuffer)
                }
            }

        }
    }

   func setup() {
            self.videoWriterInput.expectsMediaDataInRealTime = false
            if self.videoWriter.canAdd(self.videoWriterInput) {
                self.videoWriter.add(self.videoWriterInput)
            }
            // add audio input
            self.audioWriterInput = AVAssetWriterInput.init(mediaType: .audio,outputSettings: nil)

            self.audioWriterInput.expectsMediaDataInRealTime = false

            if self.videoWriter.canAdd(self.audioWriterInput!) {
                self.videoWriter.add(self.audioWriterInput!)
            }
            self.videoOutput.setSampleBufferDelegate(self,queue: .init(label: "com.jzyla.videoCaptureQueue"))
            self.audioOutput.setSampleBufferDelegate(self,queue: .init(label: "com.jzyla.audioCaptueQueue"))
            self.videoOutput2.setSampleBufferDelegate(self,queue: .init(label: "com.jzyla.videoCaptureQueue2"))
            self.audioOutput2.setSampleBufferDelegate(self,queue: .init(label: "com.jzyla.audioCaptueQueue2"))
            self.vQueue = try .init(capacity: 0,handlers: .outputPTSSortedSampleBuffers)
            self.aQueue = try .init(capacity: 0,handlers: .outputPTSSortedSampleBuffers)
            self.videoWriter.startWriting()
    }
func setSessionActive(old: AVCaptureSession,new: AVCaptureSession,completion: @escaping () -> Void) {
    dispatchQueue.global(qos: .userInitiated).async {
        print("set session active",self.currentCamera.rawValue)
        old.stopRunning()
        new.stopRunning()
        new.startRunning()
        print("session started")
        dispatchQueue.main.async {
            completion()
        }
    }
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)