使用SceneKit与AVPlayer实现视频播放时,视频方向异常如何修正?
解决SceneKit中AVPlayer视频方向不正确的问题
我用SceneKit结合AVPlayer和SCNNode开发视频播放器,逻辑是通过视频URL创建AVPlayer,将播放器设为SCNPlane的漫反射内容,以此平面为几何体创建SCNNode后添加到SCNView的rootNode中,代码如下:
private func setupVideoNode() { videoPlayer = AVPlayer(url: videoURL) let videoTrack = videoPlayer!.currentItem!.asset.tracks(withMediaType: .video).first! let naturalSize = videoTrack.naturalSize let aspectRatio: CGFloat = CGFloat(naturalSize.width / naturalSize.height) * 10 let videoPlane = SCNPlane(width: aspectRatio, height: 10) videoPlane.firstMaterial?.isDoubleSided = true videoPlane.firstMaterial?.diffuse.contents = videoPlayer videoNode = SCNNode(geometry: videoPlane) sceneView.scene?.rootNode.addChildNode(videoNode!) }
但竖屏视频显示方向不正确(视频被旋转为横屏,画面横向拉伸)。尝试用preferredTransform计算视频宽高后,效果仍不符合预期(比例调整了但方向还是错误)。
正确的调整方案
问题出在只调整了平面的宽高比,没处理preferredTransform中包含的视频旋转信息。需要同时调整SCNNode的旋转角度和平面的正确宽高:
- 从
preferredTransform中提取视频的旋转角度和实际显示尺寸 - 根据旋转角度设置SCNNode的rotation属性
- 基于实际显示尺寸计算SCNPlane的宽高比
修改后的完整代码:
private func setupVideoNode() { videoPlayer = AVPlayer(url: videoURL) guard let videoTrack = videoPlayer?.currentItem?.asset.tracks(withMediaType: .video).first else { return } let naturalSize = videoTrack.naturalSize let transform = videoTrack.preferredTransform // 提取旋转角度(处理90/270度旋转的情况) let rotationInRadians = atan2(transform.b, transform.a) // 计算实际显示的尺寸(应用变换后的尺寸) let adjustedSize = naturalSize.applying(transform) let fixedWidth = abs(adjustedSize.width) let fixedHeight = abs(adjustedSize.height) // 计算平面的宽高比,保持高度为10的话,宽度按比例调整 let aspectRatio = fixedWidth / fixedHeight * 10 let videoPlane = SCNPlane(width: aspectRatio, height: 10) videoPlane.firstMaterial?.isDoubleSided = true videoPlane.firstMaterial?.diffuse.contents = videoPlayer videoNode = SCNNode(geometry: videoPlane) // 设置节点的旋转(绕y轴旋转,适配AVPlayer的旋转方向) videoNode?.rotation = SCNVector4(0, 1, 0, -rotationInRadians) sceneView.scene?.rootNode.addChildNode(videoNode!) // 可选:启动播放 videoPlayer?.play() }
关键说明
- 旋转角度提取:
atan2(transform.b, transform.a)可以从preferredTransform矩阵中算出视频的旋转角度,这个矩阵包含了拍摄时的方向信息(比如竖屏拍摄的90度旋转)。 - 尺寸修正:
naturalSize.applying(transform)得到的是视频实际应该显示的宽高,取绝对值避免负数。 - 节点旋转:SceneKit中SCNNode的rotation是绕指定轴的弧度值,这里绕y轴旋转并取负,是为了适配AVPlayer的旋转方向,确保画面正确 upright。
内容的提问来源于stack exchange,提问作者cleanrun
相关产品推荐
相关产品推荐

