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

如何获取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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 00:20:39