如何获取AVPlayer中视频实际播放区域的尺寸与坐标?
关于AVPlayer播放视频时获取播放区域及黑边区域尺寸/坐标的问题
我使用AVPlayer播放分辨率为720x1280的视频,由于不同手机的分辨率存在差异,请问如何获取视频在手机上的实际播放区域坐标或尺寸?同时,如何获取下图中橙色线条标注区域(黑边)的尺寸或坐标?
现有代码
let url = URL(fileURLWithPath: path) let playerItem: AVPlayerItem = AVPlayerItem(url: url) player = AVPlayer(playerItem: playerItem) playerLayer = AVPlayerLayer(player: player) playerLayer!.frame = viewPlayer.bounds viewPlayer.layer.addSublayer(playerLayer!) player!.play() print("playerLayer videoRect: \(String(describing: playerLayer?.videoRect.width))") print("playerLayer bounds: \(String(describing: playerLayer?.bounds))") print("playerLayer frame: \(String(describing: playerLayer?.frame))") let size = videoTrack.naturalSize // 视频原始尺寸720x1280
播放效果示意图
竖屏播放(橙色标注为上下黑边):
横屏播放(橙色标注为左右黑边):
解决方案
1. 获取视频实际播放区域
AVPlayerLayer的videoRect属性直接对应视频内容在layer内的实际显示区域。必须等视频加载完成后再获取,否则会得到无效值。
实现步骤
- 监听AVPlayerItem的
status状态,确认视频已准备好播放 - 拿到
videoRect后,可根据需求转换为屏幕坐标系或父视图坐标系的区域
代码示例
// 监听AVPlayerItem的加载状态 playerItem.addObserver(self, forKeyPath: "status", options: [.new], context: nil) // 处理监听回调 override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { guard keyPath == "status", let item = object as? AVPlayerItem else { return } if item.status == .readyToPlay { // 此时videoRect已可用 guard let videoRect = playerLayer?.videoRect else { return } print("视频播放区域(相对于playerLayer):\(videoRect)") // 转换为屏幕坐标系的区域 if let window = view.window { let screenRect = playerLayer!.convert(videoRect, to: window) print("视频播放区域(屏幕坐标系):\(screenRect)") } } } // 记得在deinit中移除监听 deinit { playerItem.removeObserver(self, forKeyPath: "status") }
也可以直接监听playerLayer的videoRect属性变化,实时获取最新区域:
playerLayer?.addObserver(self, forKeyPath: "videoRect", options: [.new], context: nil)
2. 获取橙色标注的黑边区域
橙色标注的是playerLayer中未被视频填充的黑边区域,可通过playerLayer.bounds减去videoRect计算得出:
代码示例
guard let playerLayer = playerLayer, let videoRect = playerLayer.videoRect else { return } let layerBounds = playerLayer.bounds // 竖屏时的上下黑边 let topBarHeight = (layerBounds.height - videoRect.height) / 2 let topBarRect = CGRect(x: 0, y: 0, width: layerBounds.width, height: topBarHeight) let bottomBarRect = CGRect(x: 0, y: videoRect.maxY, width: layerBounds.width, height: topBarHeight) print("上黑边区域:\(topBarRect),下黑边区域:\(bottomBarRect)") // 横屏时的左右黑边 let leftBarWidth = (layerBounds.width - videoRect.width) / 2 let leftBarRect = CGRect(x: 0, y: 0, width: leftBarWidth, height: layerBounds.height) let rightBarRect = CGRect(x: videoRect.maxX, y: 0, width: leftBarWidth, height: layerBounds.height) print("左黑边区域:\(leftBarRect),右黑边区域:\(rightBarRect)")
注意事项
- 屏幕旋转或viewPlayer的frame变化时,需重新计算区域,可在
viewDidLayoutSubviews方法中执行计算逻辑 - 若使用自动布局,确保playerLayer的frame随viewPlayer同步更新
内容的提问来源于stack exchange,提问作者patient
相关产品推荐
相关产品推荐

