限时福利领取


在Android视频开发中,ExoPlayer作为Google推荐的媒体播放库,其默认的视频显示设置常导致画面拉伸或黑边问题。本文将分享如何通过精确控制视频显示大小来提升用户体验。

视频尺寸适配示意图

1. 问题分析:为什么视频显示会变形?

  • 宽高比不匹配:视频源分辨率(如16:9)与View容器(如4:3)比例不一致
  • 默认缩放模式问题:FIT模式会产生黑边,FILL模式会导致裁剪
  • SurfaceView特性:与TextureView不同,SurfaceView的渲染会受WindowManager限制

2. 核心解决方案

2.1 布局选择

  • AspectRatioFrameLayout(推荐):
  • 内置宽高比计算逻辑
  • 自动处理measure/layout过程
  • 支持所有ResizeMode

  • 自定义ViewGroup

  • 更灵活的布局控制
  • 需要手动实现onMeasure()
  • 适合特殊裁剪需求

2.2 ResizeMode详解

  1. FIT:保持比例,可能产生黑边
  2. FILL:填满容器,可能裁剪内容
  3. FIXED_WIDTH/FIXED_HEIGHT:固定单边尺寸
  4. ZOOM:折中方案,轻微裁剪+轻微变形

2.3 动态计算公式

// 计算最佳显示区域(考虑SurfaceView裁剪)
fun calculateDisplaySize(
    videoWidth: Int, 
    videoHeight: Int,
    viewWidth: Int, 
    viewHeight: Int
): Pair<Int, Int> {
    val videoRatio = videoWidth.toFloat() / videoHeight
    val viewRatio = viewWidth.toFloat() / viewHeight

    return if (videoRatio > viewRatio) {
        // 以宽度为基准
        viewWidth to (viewWidth / videoRatio).toInt()
    } else {
        // 以高度为基准
        (viewHeight * videoRatio).toInt() to viewHeight
    }
}

3. 完整实现方案

代码结构图

// 1. 初始化播放器时设置
player.videoScalingMode = C.VIDEO_SCALING_MODE_SCALE_TO_FIT

// 2. 监听视频尺寸变化
player.addListener(object : Player.Listener {
    override fun onVideoSizeChanged(videoSize: VideoSize) {
        updateVideoLayout(videoSize.width, videoSize.height)
    }
})

// 3. 动态更新视图
private fun updateVideoLayout(width: Int, height: Int) {
    val (displayWidth, displayHeight) = calculateDisplaySize(
        width, height, 
        container.width, container.height
    )

    val matrix = Matrix().apply {
        // 计算缩放比例
        val scaleX = displayWidth.toFloat() / width
        val scaleY = displayHeight.toFloat() / height

        // 居中显示
        postTranslate(
            (container.width - displayWidth) / 2f,
            (container.height - displayHeight) / 2f
        )

        setScale(scaleX, scaleY)
    }

    videoView.setTransform(matrix)
}

4. 性能优化要点

  1. 视图类型选择
  2. SurfaceView:内存占用低,不支持动画(适合4K视频)
  3. TextureView:支持变换,多消耗10-20%内存

  4. 硬件加速配置

    <application android:hardwareAccelerated="true" />
  5. 内存管理

  6. 及时释放MediaCodec资源
  7. 使用SimpleExoPlayer.release()

5. 常见问题解决

  • 黑屏问题:检查SurfaceHolder回调是否正常
  • DRM内容异常:禁用VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
  • 横竖屏切换
    override fun onConfigurationChanged(newConfig: Configuration) {
        super.onConfigurationChanged(newConfig)
        player?.videoSize?.let { updateVideoLayout(it.width, it.height) }
    }

实践建议

通过合理选择ResizeMode配合动态计算,可以完美适配90%的视频显示需求。对于特殊场景,建议:

  1. 直播场景优先使用SurfaceView+FIT模式
  2. 短视频编辑推荐TextureView+自定义Matrix
  3. 4K以上分辨率务必测试内存占用

希望这些实战经验能帮助你解决ExoPlayer的显示适配问题!

Logo

音视频技术社区,一个全球开发者共同探讨、分享、学习音视频技术的平台,加入我们,与全球开发者一起创造更加优秀的音视频产品!

更多推荐