【发布时间】:2020-04-24 02:07:54
【问题描述】:
尝试使用 ReplayKit 录制和保存音频/视频时,我不断收到错误消息。我正在使用
Xcode: Version 11.2.1
Swift 5
iOS 13
iPhone 7+ physical device
当我设置文件路径时,我已经在使用URL(fileURLWithPath: )。文件扩展名和AVFileType 都是.mp4。我检查该文件是否已存在于FileManager 中,如果存在,我将其删除:do { try FileManager.default.removeItem(at: videoURL) }。我试图将路径本身更改为“Library/Caches/”,就像@florianSAP answer 一样,但没有成功。
这里有 3 个错误:
// 1. from recording
if !self.assetWriter.startWriting() {
print("Can't write")
return
}
// 2. from recording
if self.assetWriter.status == AVAssetWriter.Status.failed {
print("StartCapture Error Occurred, Status = \(self.assetWriter.status.rawValue), \(self.assetWriter.error?.localizedDescription) \(self.assetWriter.error?.debugDescription)")
return
}
// 3. this one is when trying to save the url in the PHAssetChangeRequest.creationRequestForAssetFromVideo completionHandler
if let error = error {
print("PHAssetChangeRequest Video Error: \(error.localizedDescription)")
return
}
// 4. this isn't an error but inside the switch rpSampleBufferType { } statement "not a video sample" kept printing out
错误信息是:
StartCapture 发生错误,状态 = 3,无法执行该操作 已完成可选(错误域=AVFoundationErrorDomain 代码=-11800 “操作无法完成” UserInfo={NSLocalizedFailureReason=发生未知错误 (-17508), NSLocalizedDescription=操作无法完成, NSUnderlyingError=0x2833a93b0 {错误域=NSOSStatusErrorDomain 代码=-17508 "(null)"}})
PHAssetChangeRequest 视频错误:操作无法完成。 (PHPhotosErrorDomain 错误-1。)
我会在哪里出错?
开始录制
let recorder = RPScreenRecorder.shared()
var assetWriter: AVAssetWriter!
var videoURL: URL!
var videoInput: AVAssetWriterInput!
var audioMicInput: AVAssetWriterInput!
guard let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first else { return }
videoURL = URL(fileURLWithPath: documentsPath.appending(UUID().uuidString + ".mp4"))
guard let videoURL = videoURL else { return }
do {
try FileManager.default.removeItem(at: videoURL)
} catch {}
do {
try assetWriter = AVAssetWriter(outputURL: videoURL, fileType: .mp4) // AVAssetWriter(url: videoURL, fileType: .mp4) didn't make a difference
} catch {}
let videoSettings: [String : Any] = [
AVVideoCodecKey: AVVideoCodecType.h264,
AVVideoWidthKey: view.bounds.width,
AVVideoHeightKey: view.bounds.height
]
videoInput = AVAssetWriterInput(mediaType: .video, outputSettings: videoSettings)
videoInput.expectsMediaDataInRealTime = true
if assetWriter.canAdd(videoInput) {
assetWriter.add(videoInput)
}
let audioSettings: [String:Any] = [AVFormatIDKey : kAudioFormatMPEG4AAC,
AVNumberOfChannelsKey : 2,
AVSampleRateKey : 44100.0,
AVEncoderBitRateKey: 192000
]
audioMicInput = AVAssetWriterInput(mediaType: .audio, outputSettings: audioSettings)
audioMicInput.expectsMediaDataInRealTime = true
if assetWriter.canAdd(audioMicInput) {
assetWriter.add(audioMicInput)
}
guard recorder.isAvailable else { return }
recorder.startCapture(handler: { (cmSampleBuffer, rpSampleBufferType, err) in
if let err = err { return }
// I tried to check if this was ready and added the below code to it but it made no difference
// if CMSampleBufferDataIsReady(cmSampleBuffer) { ... the code below was put in here ... }
DispatchQueue.main.async {
switch rpSampleBufferType {
case .video:
if self.assetWriter.status == AVAssetWriter.Status.unknown {
if !self.assetWriter.startWriting() {
print("Can't write")
return
}
print("Starting writing")
self.assetWriter.startWriting()
self.assetWriter.startSession(atSourceTime: CMSampleBufferGetPresentationTimeStamp(cmSampleBuffer))
}
if self.assetWriter.status == AVAssetWriter.Status.failed {
print("StartCapture Error Occurred, Status = \(self.assetWriter.status.rawValue), \(self.assetWriter.error?.localizedDescription) \(self.assetWriter.error?.debugDescription)")
return
}
if self.assetWriter.status == AVAssetWriter.Status.writing {
if self.videoInput.isReadyForMoreMediaData {
if self.videoInput.append(cmSampleBuffer) == false {
print("problem writing video")
}
}
}
case .audioMic:
if self.audioMicInput.isReadyForMoreMediaData {
print("audioMic data added")
self.audioMicInput.append(cmSampleBuffer)
}
default:
print("not a video sample")
}
}
}
}, completionHandler: { (error) in
if let error = error { return }
})
停止录制:
recorder.stopCapture { (error) in
if let error = error { return }
guard let videoInput = self.videoInput else { return }
guard let audioMicInput = self.audioMicInput else { return }
guard let assetWriter = self.assetWriter else { return }
guard let videoURL = videoURL else { return }
videoInput.markAsFinished()
audioMicInput.markAsFinished()
assetWriter.finishWriting(completionHandler: {
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoUrl)
}) { (saved, error) in
if let error = error {
print("PHAssetChangeRequest Video Error: \(error.localizedDescription)")
return
}
if saved {
// ... show success message
}
}
})
}
永远不会被调用的 RPScreenRecorder 委托:
func screenRecorder(_ screenRecorder: RPScreenRecorder, didStopRecordingWith previewViewController: RPPreviewViewController?, error: Error?) {
if let error = error {
print(error.localizedDescription)
}
}
【问题讨论】:
标签: ios swift avassetwriter phasset replaykit