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

如何旋转RTCEAGLVideoView,实现远端视频画面90度旋转?

方案1:渲染视图直接做变换(实现最简单,性能最优)

这种方案不需要修改视频帧本身,仅在显示层面做旋转,适合仅需要调整显示效果的场景,修改你的VideoView代码即可:

struct VideoView: UIViewRepresentable {
    let videoTrack: RTCVideoTrack?
    @Binding var refreshVideoTrack: Bool
    // 可以外部传入需要的旋转角度,.pi/2对应90度、.pi对应180度、-.pi/2对应270度
    let rotationAngle: CGFloat = .pi / 2

    func makeUIView(context: Context) -> RTCEAGLVideoView {
        let view = RTCEAGLVideoView(frame: .zero)
        view.contentMode = .scaleAspectFit // 旋转后建议用fit避免画面裁剪超出视图范围
        // 在这里应用旋转变换
        view.transform = CGAffineTransform(rotationAngle: rotationAngle)
        return view
    }

    func updateUIView(_ view: RTCEAGLVideoView, context: Context) {
        if refreshVideoTrack {
            videoTrack?.add(view)
            refreshVideoTrack = false
        }
        // 如果需要动态修改旋转角度,也可以在这里更新transform
        view.transform = CGAffineTransform(rotationAngle: rotationAngle)
    }
}
方案2:通过RTCVideoRotation修改视频帧属性

如果你需要修改原始视频帧的旋转属性(比如旋转后的帧还要用于本地录制、推流等其他逻辑),就需要用到RTCVideoRotation,需要给视频轨道加一个中间帧处理层:

  1. 先实现一个中间渲染代理,接收原始视频帧,修改旋转角度后转发给实际的渲染视图:
class RotationVideoRenderer: NSObject, RTCVideoRenderer {
    private let targetRenderer: RTCVideoRenderer
    private let targetRotation: RTCVideoRotation

    init(targetRenderer: RTCVideoRenderer, rotation: RTCVideoRotation) {
        self.targetRenderer = targetRenderer
        self.targetRotation = rotation
        super.init()
    }

    func setSize(_ size: CGSize) {
        targetRenderer.setSize(size)
    }

    func renderFrame(_ frame: RTCVideoFrame?) {
        guard let originalFrame = frame else {
            targetRenderer.renderFrame(nil)
            return
        }
        // 构造新的帧,替换rotation属性为你需要的角度
        let rotatedFrame = RTCVideoFrame(buffer: originalFrame.buffer,
                                         rotation: targetRotation,
                                         timeStampNs: originalFrame.timeStampNs)
        targetRenderer.renderFrame(rotatedFrame)
    }
}
  1. 修改你的VideoView代码,把中间代理绑定到视频轨道上:
struct VideoView: UIViewRepresentable {
    let videoTrack: RTCVideoTrack?
    @Binding var refreshVideoTrack: Bool
    // 指定需要的旋转角度,可选.rotation_0 / .rotation_90 / .rotation_180 / .rotation_270
    let rotation: RTCVideoRotation = .rotation_90
    // 持有中间渲染代理避免被释放
    private var rotationRenderer: RotationVideoRenderer?

    func makeUIView(context: Context) -> RTCEAGLVideoView {
        let view = RTCEAGLVideoView(frame: .zero)
        view.contentMode = .scaleAspectFill
        // 初始化中间渲染代理
        rotationRenderer = RotationVideoRenderer(targetRenderer: view, rotation: rotation)
        return view
    }

    func updateUIView(_ view: RTCEAGLVideoView, context: Context) {
        if refreshVideoTrack, let renderer = rotationRenderer {
            // 把中间代理添加到视频轨道,而不是直接添加渲染视图
            videoTrack?.add(renderer)
            refreshVideoTrack = false
        }
    }
}

两种方案按需选择即可:仅调整显示效果选方案1,需要修改原始帧属性选方案2。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 14:15:08