You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用AVAssetWriter二次录制视频时抛出异常问题咨询

解决AVAssetWriter重复录制抛出异常的问题

问题根源

AVAssetWriter是一次性生命周期对象:一旦你调用了finishWriting(不管是带回调的异步版本还是同步版本),这个实例就彻底进入了完成/失效状态,再也不能调用startWriting或startSession了。你第二次录制时复用了同一个assetWriter实例,自然会触发异常。

解决方案:每次录制都创建新的AVAssetWriter实例

核心思路就是抛弃复用旧实例的想法,每次启动新录制时重新初始化一个完整的AVAssetWriter,包括对应的输入、输出配置。下面是具体的代码调整方案:

  1. 抽离AssetWriter初始化逻辑
    写一个专门创建AVAssetWriter的方法,每次录制前调用它生成全新实例:

    private func createAssetWriter(outputURL: URL) -> AVAssetWriter? {
        do {
            // 先清理旧文件:如果输出路径已存在,删除后再创建新文件
            if FileManager.default.fileExists(atPath: outputURL.path) {
                try FileManager.default.removeItem(at: outputURL)
            }
            // 创建新的AssetWriter实例
            let writer = try AVAssetWriter(outputURL: outputURL, fileType: .mov)
            
            // 添加视频输入(根据你的需求配置参数)
            let videoSettings: [String: Any] = [
                AVVideoCodecKey: AVVideoCodecType.h264,
                AVVideoWidthKey: 1920,
                AVVideoHeightKey: 1080
            ]
            let videoInput = AVAssetWriterInput(mediaType: .video, outputSettings: videoSettings)
            videoInput.expectsMediaDataInRealTime = true
            if writer.canAdd(videoInput) {
                writer.add(videoInput)
            }
            
            // 同理添加音频输入(如果需要)
            // ...
            
            return writer
        } catch {
            print("创建AssetWriter失败:\(error.localizedDescription)")
            return nil
        }
    }
    
  2. 修改start方法:每次录制生成新实例
    启动录制前,先生成新的输出文件路径,再创建新的assetWriter:

    func start() {
        // 生成唯一的输出文件URL(用时间戳命名,避免覆盖旧录制文件)
        let outputURL = getUniqueRecordingURL()
        // 创建全新的AssetWriter
        assetWriter = createAssetWriter(outputURL: outputURL)
        
        guard let writer = assetWriter else {
            print("无法启动录制:AssetWriter初始化失败")
            return
        }
        
        writer.startWriting()
        writer.startSession(atSourceTime: kCMTimeZero)
        // 这里记得开始向输入流写入媒体数据
        // ...
    }
    
    // 辅助方法:生成唯一的录制文件路径
    private func getUniqueRecordingURL() -> URL {
        let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
        let timestamp = Date().timeIntervalSince1970
        return documentsDir.appendingPathComponent("recording_\(timestamp).mov")
    }
    
  3. 完善finish方法:清理旧实例
    在完成回调中清空assetWriter的引用,确保下次录制一定会创建新实例:

    func finish() {
        guard let writer = assetWriter else { return }
        print("before finish")
        writer.finishWriting { [weak self] in
            print("finish writing")
            // 完成后清空引用,避免内存泄漏+确保下次录制用新实例
            self?.assetWriter = nil
            // 这里可以添加录制完成后的逻辑,比如通知用户、上传文件等
        }
    }
    

额外注意事项

  • 状态检查:在操作assetWriter前,可以通过status属性判断当前状态,比如只有writer.status == .unknown或.writing时才执行对应操作,避免无效调用。
  • 错误排查:如果assetWriter状态变为.failed,可以通过error属性获取具体错误信息,方便调试。
  • 文件管理:定期清理旧的录制文件,避免占用过多存储空间。

内容的提问来源于stack exchange,提问作者FuzzzzyBoy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:30:13