如何旋转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,需要给视频轨道加一个中间帧处理层:
- 先实现一个中间渲染代理,接收原始视频帧,修改旋转角度后转发给实际的渲染视图:
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) } }
- 修改你的
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,提问作者윤지훈
相关产品推荐
相关产品推荐

