Swift中如何录制4K 60FPS至内部存储?遇ProRes录制异常
解决方案:用AVAssetWriter替代AVCaptureMovieFileOutput实现内部存储ProRes录制
系统的AVCaptureMovieFileOutput对高码率ProRes格式的内部存储录制有硬性限制,但Blackmagic Cam这类应用是通过手动捕获视频帧并使用AVAssetWriter写入文件的方式绕过了这个限制。以下是具体实现步骤:
1. 替换输出组件,配置AVCaptureVideoDataOutput
移除原有的AVCaptureMovieFileOutput,改用AVCaptureVideoDataOutput获取原始视频帧数据,并指定ProRes编码格式:
// 配置视频数据输出 let videoOutput = AVCaptureVideoDataOutput() videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoQueue")) // 设置ProRes编码参数(根据设备支持的格式调整) guard let videoSettings = [ AVVideoCodecKey: AVVideoCodecType.proRes422HQ, // 可替换为其他ProRes格式 AVVideoWidthKey: 1920, AVVideoHeightKey: 1080 ] as [String: Any] else { fatalError("Invalid video settings") } videoOutput.videoSettings = videoSettings // 添加到捕获会话 if captureSession.canAddOutput(videoOutput) { captureSession.addOutput(videoOutput) }
2. 初始化AVAssetWriter用于写入内部存储
在开始录制时,初始化AVAssetWriter并指定内部存储的文件路径:
var assetWriter: AVAssetWriter? var videoInput: AVAssetWriterInput? func startRecording() { let outputFileName = UUID().uuidString let outputFilePath = (NSTemporaryDirectory() as NSString).appendingPathComponent("\(outputFileName).mov") let outputURL = URL(fileURLWithPath: outputFilePath) do { assetWriter = try AVAssetWriter(outputURL: outputURL, fileType: .mov) // 配置视频输入,匹配ProRes格式和分辨率 let videoInputSettings = [ AVVideoCodecKey: AVVideoCodecType.proRes422HQ, AVVideoWidthKey: 1920, AVVideoHeightKey: 1080, AVVideoCompressionPropertiesKey: [ AVVideoAverageBitRateKey: 380_000_000 // 根据需求调整码率 ] ] as [String: Any] videoInput = AVAssetWriterInput(mediaType: .video, outputSettings: videoInputSettings) videoInput?.expectsMediaDataInRealTime = true if let input = videoInput, assetWriter?.canAdd(input) == true { assetWriter?.add(input) } assetWriter?.startWriting() assetWriter?.startSession(atSourceTime: CMTime.zero) } catch { print("Failed to initialize asset writer: \(error)") } }
3. 实现代理方法写入帧数据
通过AVCaptureVideoDataOutputSampleBufferDelegate处理捕获到的视频帧,写入到AVAssetWriter:
extension YourViewController: AVCaptureVideoDataOutputSampleBufferDelegate { func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { guard let assetWriter = assetWriter, let videoInput = videoInput, videoInput.isReadyForMoreMediaData else { return } if assetWriter.status == .writing { videoInput.append(sampleBuffer) } } }
4. 停止录制的收尾处理
func stopRecording() { videoInput?.markAsFinished() assetWriter?.finishWriting(completionHandler: { switch self.assetWriter?.status { case .completed: print("Recording saved to: \(self.assetWriter?.outputURL ?? URL(fileURLWithPath: ""))") case .failed: print("Recording failed: \(self.assetWriter?.error?.localizedDescription ?? "Unknown error")") default: break } }) }
关键说明
- 系统的
AVCaptureMovieFileOutput受限于Apple的存储保护策略,禁止高码率ProRes格式写入内部存储,但手动使用AVAssetWriter直接处理帧数据可以绕过这个限制,这也是Blackmagic Cam等应用的核心实现方式。 - 需提前验证设备支持的ProRes格式和分辨率,可通过
AVCaptureDevice的formats属性查询。 - 确保已获取相机、存储权限,同时注意后台录制的兼容性。
内容的提问来源于stack exchange,提问作者Utkarsh
相关产品推荐
相关产品推荐

