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

iOS端WebRTC如何提取RTCVideoFrame实现远端视频实时录制

实现方案

你需要通过实现WebRTC提供的RTCVideoSink协议接收实时RTCVideoFrame,这是官方提供的标准帧提取入口,不会影响原有视频渲染链路。

步骤1:创建自定义帧接收器

实现RTCVideoSink协议,在回调方法中获取每帧视频数据:

import WebRTC

class VideoRecordSink: NSObject, RTCVideoSink {
    // 定义帧回调闭包,你可以在这里把RTCVideoFrame转成CMSampleBuffer喂给AVAssetWriter
    var onFrameCaptured: ((RTCVideoFrame) -> Void)?
    
    func onCapturedFrame(_ frame: RTCVideoFrame) {
        // 注意:这个回调默认在WebRTC内部队列执行,不要直接操作UI
        onFrameCaptured?(frame)
    }
}

步骤2:给远程视频轨绑定接收器

在你获取到remoteVideoTrack的位置(也就是RTCPeerConnectionDelegate的didAdd stream方法中),给视频轨添加你自定义的sink:
首先你需要在homeViewModel中持有sink实例,避免被释放导致回调中断:

// 先在homeViewModel中添加属性
var recordSink: VideoRecordSink?

修改代理方法:

func peerConnection(_ peerConnection: RTCPeerConnection, didAdd stream: RTCMediaStream) {
    dLog("")

    remoteVideoTrack = stream.videoTracks.first
    remoteVideoTrack?.isEnabled = true
    refreshRemoteVideoTrack = true
    
    // 初始化帧接收器,绑定帧回调
    let recordSink = VideoRecordSink()
    recordSink.onFrameCaptured = { [weak self] frame in
        // 在这里处理帧转换、写入AVAssetWriter的逻辑
        guard let self = self else { return }
        // 你已经知道的RTCVideoFrame转CMSampleBuffer、写入逻辑放在这里即可
    }
    // 给视频轨添加sink
    remoteVideoTrack?.add(recordSink)
    // 持有sink实例,避免释放
    self.recordSink = recordSink
}

注意事项

  • 停止录制的时候需要调用remoteVideoTrack?.remove(recordSink)移除接收器,避免内存泄漏
  • onCapturedFrame回调不在主线程,你可以把帧处理、写入逻辑放到专门的串行队列执行,避免阻塞WebRTC线程
  • 要确保AVAssetWriter已经调用startWriting和startSession(atSourceTime:)之后再开始写入CMSampleBuffer,避免写入失败
  • 同一个视频轨可以添加多个sink,新增的录制sink不会影响原有RTCEAGLVideoView的渲染逻辑

内容的提问来源于stack exchange,提问作者윤지훈

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 01:06:07