gpt4 book ai didi

ios - Replaykit Assets 编写器状态随机失败

转载 作者:搜寻专家 更新时间:2023-10-31 23:08:40 26 4
gpt4 key购买 nike

用例

我正在使用 iOS 11 Replaykit 框架来尝试记录来自屏幕的帧,以及来自应用程序和麦克风的音频。

问题

随机地,当我调用我的 .append(sampleBuffer) 时得到 AVAssetWriterStatus.failed 并显示 AssetWriter.Error

Error Domain=AVFoundationErrorDomain Code=-11823 "Cannot Save"UserInfo={NSLocalizedRecoverySuggestion=Try saving again., NSLocalizedDescription=Cannot Save, NSUnderlyingError=0x1c044c360 {Error Domain=NSOSStatusErrorDomain Code=-12412 "(null)"}}

附带问题:我在应用录制时重复播放声音以尝试验证是否录制了音频,但当我开始录制时声音停止了,即使视频和外部音频麦克风正在工作。

如果您需要更多信息,我也可以将其他代码上传到 GitHub。

想法

由于有时会保存录制内容(我可以导出到照片应用程序并重播视频),我认为这一定是异步问题导致我无法按顺序加载内容。如果你看到任何东西,请告诉我!

我想我会尝试的一个方法是保存到/Documents 中我自己的文件夹,而不是直接保存到/Documents,以防出现奇怪的权限错误。虽然我相信这会导致一致的错误,而不仅仅是有时会中断。

我的代码

func startRecording() {
guard let firstDocumentDirectoryPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first else { return }

let directoryContents = try! FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: firstDocumentDirectoryPath), includingPropertiesForKeys: nil, options: [])
print(directoryContents)

videoURL = URL(fileURLWithPath: firstDocumentDirectoryPath.appending("/\(arc4random()).mp4"))

print(videoURL.absoluteString)

assetWriter = try! AVAssetWriter(url: videoURL, fileType: AVFileType.mp4)

let compressionProperties:[String:Any] = [...]
let videoSettings:[String:Any] = [...]
let audioSettings:[String:Any] = [...]

videoInput = AVAssetWriterInput(mediaType: .video, outputSettings: videoSettings)
audioMicInput = AVAssetWriterInput(mediaType: .audio, outputSettings: audioSettings)
audioAppInput = AVAssetWriterInput(mediaType: .audio, outputSettings: audioSettings)

guard let assetWriter = assetWriter else { return }
guard let videoInput = videoInput else { return }
guard let audioAppInput = audioAppInput else { return }
guard let audioMicInput = audioMicInput else { return }

videoInput.mediaTimeScale = 60
videoInput.expectsMediaDataInRealTime = true
audioMicInput.expectsMediaDataInRealTime = true
audioAppInput.expectsMediaDataInRealTime = true

if assetWriter.canAdd(videoInput) {
assetWriter.add(videoInput)
}

if assetWriter.canAdd(audioAppInput) {
assetWriter.add(audioAppInput)
}

if assetWriter.canAdd(audioMicInput) {
assetWriter.add(audioMicInput)
}

assetWriter.movieTimeScale = 60

RPScreenRecorder.shared().startCapture(handler: recordingHandler(sampleBuffer:sampleBufferType:error:)) { (error:Error?) in
if error != nil {
print("RPScreenRecorder.shared().startCapture: \(error.debugDescription)")
} else {
print("start capture complete")
}
}
}

func recordingHandler (sampleBuffer:CMSampleBuffer, sampleBufferType:RPSampleBufferType, error:Error?){
if error != nil {
print("recordingHandler: \(error.debugDescription)")
}

if CMSampleBufferDataIsReady(sampleBuffer) {
guard let assetWriter = assetWriter else { return }
guard let videoInput = videoInput else { return }
guard let audioAppInput = audioAppInput else { return }
guard let audioMicInput = audioMicInput else { return }

if assetWriter.status == AVAssetWriterStatus.unknown {
print("AVAssetWriterStatus.unknown")
if !assetWriter.startWriting() {
return
}
assetWriter.startSession(atSourceTime: CMSampleBufferGetPresentationTimeStamp(sampleBuffer))
}

if assetWriter.status == AVAssetWriterStatus.failed {
print("AVAssetWriterStatus.failed")
print("assetWriter.error: \(assetWriter.error.debugDescription)")
return
}

if sampleBufferType == RPSampleBufferType.video {
if videoInput.isReadyForMoreMediaData {
print("=appending video data")
videoInput.append(sampleBuffer)
}
}

if sampleBufferType == RPSampleBufferType.audioApp {
if audioAppInput.isReadyForMoreMediaData {
print("==appending app audio data")
audioAppInput.append(sampleBuffer)
}
}

if sampleBufferType == RPSampleBufferType.audioMic {
if audioMicInput.isReadyForMoreMediaData {
print("===appending mic audio data")
audioMicInput.append(sampleBuffer)
}
}
}
}

func stopRecording() {
RPScreenRecorder.shared().stopCapture { (error) in
guard let assetWriter = self.assetWriter else { return }
guard let videoInput = self.videoInput else { return }
guard let audioAppInput = self.audioAppInput else { return }
guard let audioMicInput = self.audioMicInput else { return }

if error != nil {
print("recordingHandler: \(error.debugDescription)")
} else {
videoInput.markAsFinished()
audioMicInput.markAsFinished()
audioAppInput.markAsFinished()

assetWriter.finishWriting(completionHandler: {
print(self.videoURL)
self.saveToCameraRoll(URL: self.videoURL)
})
}
}
}

最佳答案

我让它工作了。我相信这确实是一个异步问题。问题是,出于某种原因,您必须确保

assetWriter.startWriting()
assetWriter.startSession(atSourceTime: CMSampleBufferGetPresentationTimeStamp(sampleBuffer))

严格按顺序发生。

从此更改您的代码:

if assetWriter.status == AVAssetWriterStatus.unknown {
print("AVAssetWriterStatus.unknown")
if !assetWriter.startWriting() {
return
}
assetWriter.startSession(atSourceTime: CMSampleBufferGetPresentationTimeStamp(sampleBuffer))
}

为此:

DispatchQueue.main.async { [weak self] in
if self?.assetWriter.status == AVAssetWriterStatus.unknown {
print("AVAssetWriterStatus.unknown")
if !self?.assetWriter.startWriting() {
return
}
self?.assetWriter.startSession(atSourceTime: CMSampleBufferGetPresentationTimeStamp(sampleBuffer))
}
}

或者甚至更好,整个 block 都在 CMSampleBufferDataIsReady 中,即。

if CMSampleBufferDataIsReady(sampleBuffer) {
DispatchQueue.main.async { [weak self] in
...
...
}
}

让我知道它是否有效!

关于ios - Replaykit Assets 编写器状态随机失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46774237/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com