如何在ExoPlayer的PlayerView中获取9:16视频帧的四角坐标
获取Android PlayerView中9:16视频帧的四角坐标
要定位文本覆盖层,核心是计算视频帧在PlayerView容器内的实际显示区域——因为PlayerView会自动按比例缩放视频并居中显示,所以需要结合视频原始比例和PlayerView的尺寸来推导坐标。

步骤1:获取视频原始宽高
首先要在视频加载完成后拿到视频的真实宽高,以ExoPlayer为例,通过Player.Listener监听视频尺寸变化:
player.addListener(object : Player.Listener { override fun onVideoSizeChanged(videoSize: VideoSize) { super.onVideoSizeChanged(videoSize) val videoWidth = videoSize.width val videoHeight = videoSize.height // 校验是否为9:16竖屏视频(允许微小误差) val is916Portrait = Math.abs((videoHeight.toFloat() / videoWidth) - 16f/9f) < 0.01f if (is916Portrait) { calculateVideoFrame(playerView, videoWidth, videoHeight) } } })
步骤2:计算视频帧的显示区域与四角坐标
PlayerView的尺寸需要在布局完成后才能准确获取,所以用ViewTreeObserver监听布局完成事件,再推导坐标:
private fun calculateVideoFrame(playerView: PlayerView, videoWidth: Int, videoHeight: Int) { playerView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { override fun onGlobalLayout() { // 移除监听避免重复触发 playerView.viewTreeObserver.removeOnGlobalLayoutListener(this) val containerWidth = playerView.width val containerHeight = playerView.height // 计算缩放比例:取容器与视频宽高比的较小值,保证视频完整显示 val scaleX = containerWidth.toFloat() / videoWidth val scaleY = containerHeight.toFloat() / videoHeight val scale = min(scaleX, scaleY) // 视频实际显示的宽高 val displayedWidth = videoWidth * scale val displayedHeight = videoHeight * scale // 居中显示时的偏移量(左右/上下边距) val offsetX = (containerWidth - displayedWidth) / 2f val offsetY = (containerHeight - displayedHeight) / 2f // 计算四个角的局部坐标(以PlayerView左上角为原点) val topLeft = Pair(offsetX, offsetY) val topRight = Pair(offsetX + displayedWidth, offsetY) val bottomLeft = Pair(offsetX, offsetY + displayedHeight) val bottomRight = Pair(offsetX + displayedWidth, offsetY + displayedHeight) // 这里可以将坐标用于文本覆盖层的定位 // 如需屏幕绝对坐标,可通过playerView.getLocationOnScreen()转换 } }) }
额外注意事项
- 若PlayerView布局变化(如屏幕旋转、窗口调整),需要重新计算坐标,可以在
onConfigurationChanged或View.OnLayoutChangeListener中重复执行计算逻辑。 - 如果使用了非默认缩放模式(如
resize_mode="fill"),缩放比例要取max(scaleX, scaleY),此时视频会被裁剪,需根据需求调整坐标计算。 - 如需将局部坐标转为屏幕绝对坐标,可使用以下代码:
val containerLocation = IntArray(2) playerView.getLocationOnScreen(containerLocation) val screenTopLeftX = containerLocation[0] + topLeft.first val screenTopLeftY = containerLocation[1] + topLeft.second
内容的提问来源于stack exchange,提问作者nervian tone
相关产品推荐
相关产品推荐

