Android用ExoPlayer获取视频正确的尺寸

devtools/2025/3/1 13:22:59/

最近在实现视频预加载功能,遇到了较多的疑问未解决,但机缘巧合解决了困扰我很久的某些视频

展示异常的问题(被压扁),如下图

我的实现方法:

@Overridepublic void onVideoSizeChanged(VideoSize videoSize) { currentVideoWidth = videoSize.width;currentVideoHeight = videoSize.height;//根据视频的宽高比决定改视频是竖屏还是横屏,然后再根据手机的分辨率对视频进行放大/缩小//大部分视频只有处理没有问题,近期采购了其他供应商的视频,发现对某些视频会存在压缩}

百度/Google啥都问了一遍,没发现什么可借鉴的方法,直到现在deepseek/豆包啥的AI上线,问他们比问百度精准很多,最后是deepseek给我解惑了,如下:

问:pixelWidthHeightRatio等于1.0 等于0.31640625 有什么区别
嗯,用户问到了pixelWidthHeightRatio等于1.0和0.31640625有什么区别。我需要先回顾一下之前讨论的内容,确保自己对这个参数的理解正确。之前讨论过ExoPlayer中视频尺寸的问题,特别是旋转和像素宽高比的影响。用户现在可能在处理视频显示尺寸的问题,特别是在获取到的视频宽高和实际下载的尺寸不符时,遇到的困惑。
首先,pixelWidthHeightRatio(PAR,像素宽高比)是视频元数据中的一个参数,它表示像素的宽高比。通常,如果PAR是1.0,意味着每个像素是正方形的,宽高比为1:1。而如果PAR不是1.0,比如0.31640625,说明像素不是正方形的,可能是长方形,这会影响视频的显示尺寸。
接下来,我需要解释这两种情况的具体区别。当PAR是1.0时,视频的显示宽度就是存储宽度,不需要调整。而当PAR是其他数值时,比如0.31640625,显示宽度需要根据PAR进行调整。例如,视频的存储宽度是607,PAR是0.31640625,那么实际显示宽度会是607 * 0.31640625 ≈ 192,这可能与用户之前提到的1920x1080有关联吗?或者可能是用户遇到了这样的情况,导致显示尺寸与存储尺寸不一致。
这里需要进一步分析用户可能遇到的具体情况。用户之前提到ExoPlayer报告的尺寸是1920x1080,但下载下来的视频是607x1080,需要确认PAR是否是0.31640625,这样计算出来的显示宽度为607 * 0.31640625 ≈ 192,但这似乎与1920相差较大,所以可能存在其他因素,比如旋转或不同的PAR值。
或者,用户提到的0.31640625可能是一个具体的例子,需要解释这个数值的来源和计算方式。例如,如果视频的显示宽高比(DAR)是16:9,存储尺寸是607x1080,那么DAR = (SAR宽 / SAR高) * (存储宽 / 存储高)。这里可能需要用PAR来计算实际的显示尺寸。
另外,用户可能需要了解如何正确处理PAR值,以确保在ExoPlayer中正确显示视频尺寸。例如,在onVideoSizeChanged回调中,pixelWidthHeightRatio参数用于调整实际显示的宽度,这样显示宽度 = width * pixelWidthHeightRatio,而显示高度保持为height,或者需要考虑旋转的情况。
需要确保用户理解PAR的作用,以及如何应用它来正确计算视频的显示尺寸。如果用户仍然遇到尺寸不符的问题,可能需要进一步检查视频的元数据,是否存在旋转或其他因素,或者是否在代码中没有正确应用PAR值。
可能用户在实际操作中发现pixelWidthHeightRatio的值有时是1.0,有时是0.31640625,导致显示尺寸不同,需要解释这两者的区别以及对应的处理方式。例如,当PAR为0.31640625时,如何调整显示宽高,以避免尺寸错误。
总结来说,用户的问题核心在于理解不同PAR值对视频显示尺寸的影响,以及如何在代码中正确处理这些情况,确保显示的尺寸与预期一致。需要分步骤解释这两种PAR值的区别,并提供代码示例或计算公式,帮助用户进行正确的调整。

在 ExoPlayer 的 onVideoSizeChanged 方法中,pixelWidthHeightRatio(PAR,像素宽高比)直接影响视频的最终显示尺寸。以下是 pixelWidthHeightRatio = 1.0 和 pixelWidthHeightRatio = 0.31640625 的详细区别及实际影响:

1. pixelWidthHeightRatio = 1.0

1.含义:像素是正方形的(宽高比为 1:1)。
2.显示尺寸计算:
显示宽度 = 存储宽度(width) × PAR = width × 1.0
显示高度 = 存储高度(height)
即显示尺寸与存储尺寸一致。
3.示例:
视频存储尺寸为 607×1080,且 PAR=1.0,则显示尺寸为 607×1080。


2. pixelWidthHeightRatio = 0.31640625

1.含义:像素是长方形的(宽高比非 1:1),具体为宽:高 = 0.31640625:1(即宽度更窄,像素被“压扁”)。
2.显示尺寸计算:
显示宽度 = 存储宽度(width) × PAR = width × 0.31640625
显示高度 = 存储高度(height)
显示宽度会被压缩到原始宽度的约 31.6%。
3.示例:
视频存储尺寸为 607×1080,且 PAR=0.31640625,则显示宽度为:
607 × 0.31640625 ≈ 192,显示尺寸为 192×1080。


3. 为什么需要 PAR?
视频的存储尺寸(stored resolution)和显示尺寸(display resolution)可能不一致,原因包括:

1.历史兼容性:早期视频编码为节省带宽,使用非正方形像素(如 PAL 标清视频的 PAR=59:54)。
2.动态适配:某些编码器会调整 PAR 以匹配目标显示比例(如 16:9)。
4. 结合旋转(Rotation)的场景
如果视频包含旋转元数据(如 90°),onVideoSizeChanged 的 width 和 height 会互换,此时需先处理旋转,再应用 PAR:

override fun onVideoSizeChanged(width: Int, height: Int, unappliedRotationDegrees: Int, pixelWidthHeightRatio: Float) {// 处理旋转(交换宽高)val rotatedWidth = if (unappliedRotationDegrees % 180 == 90) height else widthval rotatedHeight = if (unappliedRotationDegrees % 180 == 90) width else height// 应用 PAR 计算显示尺寸val displayWidth = rotatedWidth * pixelWidthHeightRatioval displayHeight = rotatedHeightLog.d("Video", "显示尺寸: ${displayWidth.toInt()}x$displayHeight")
}


5. 实际场景示例
假设视频元数据为:

.存储尺寸:607×1080
.旋转角度:90°
.PAR:0.31640625


1.处理旋转:
旋转后尺寸变为 1080×607(宽高交换)。
2.应用 PAR:
显示宽度 = 1080 × 0.31640625 ≈ 342,显示高度 = 607
最终显示尺寸为 342×607。


6. 对比总结

参数pixelWidthHeightRatio = 1.0pixelWidthHeightRatio = 0.31640625
像素形状正方形长方形(宽度被压缩)
显示宽度存储宽度 × 1.0(无缩放)存储宽度 × 0.31640625
典型场景现代标准视频(如 1080p)老式编码视频或特殊比例适配
对显示尺寸的影响显著缩小宽度

7. 如何验证 PAR?
使用 ffprobe 检查视频的宽高比信息:
ffprobe -v error -show_entries stream=sample_aspect_ratio,display_aspect_ratio -of default=noprint_wrappers=1 input.mp4


.sample_aspect_ratio(SAR):即 pixelWidthHeightRatio(如 3164:10000 ≈ 0.3164)。
.display_aspect_ratio(DAR):最终显示宽高比,计算方式为:
DAR = (SAR宽 × 存储宽) / (SAR高 × 存储高)。
8. 代码中正确处理
在 ExoPlayer 中,始终需要结合 unappliedRotationDegrees 和 pixelWidthHeightRatio 计算最终尺寸:

val displayWidth = rotatedWidth * pixelWidthHeightRatio
val displayAspectRatio = displayWidth / displayHeight// 用于设置 SurfaceView 的宽高比例
surfaceView.setAspectRatio(displayAspectRatio)


通过理解 pixelWidthHeightRatio 的作用,可以避免因像素宽高比和旋转导致的显示尺寸错误。

总结:

1.从onVideoSizeChanged中获取视频相关信息:宽&高&像素宽高比(PAR)&角度;

2.如果视频包含旋转元数据(如 90°),onVideoSizeChangedwidthheight 会互换,此时需先处理旋转,再应用 PAR:

3.应用PAR

视频的像素有正方形有长方形,如果像素为正方形直接去宽高没有问题,如果不是正方形,宽度要重新计算:真实的宽度=videoSize.width*videoSize.pixelWidthHeightRatio,正方形时videoSize.pixelWidthHeightRatio=1.0,所以无论像素是正方形还是长方形:真实的宽度=videoSize.width*videoSize.pixelWidthHeightRatio

 @Overridepublic void onVideoSizeChanged(VideoSize videoSize) {//视频尺寸回调,像素宽高比:pixelWidthHeightRatio = 1.0====像素是正方形的(宽高比为 1:1),否则像素是长方形的(宽高比非 1:1),像素被“压扁”LogUtil.d(TAG, "onVideoSizeChanged width " + videoSize.width + " height:" + videoSize.height + ",PAR,像素宽高比:" + videoSize.pixelWidthHeightRatio + ",角度:" + videoSize.unappliedRotationDegrees);int width = videoSize.width;int height = videoSize.height;// 处理旋转(交换宽高)int rotatedWidth = videoSize.unappliedRotationDegrees % 180 == 90 ? height : width;int rotatedHeight = videoSize.unappliedRotationDegrees % 180 == 90 ? width : height;// 应用 PAR 计算显示尺寸currentVideoWidth = (int) (rotatedWidth * videoSize.pixelWidthHeightRatio);currentVideoHeight = rotatedHeight; }

ps:ExoPlayer不同版本onVideoSizeChanged回调的参数格式不一样,我的是2.16.1版本,

有些是:onVideoSizeChanged(width: Int, height: Int, unappliedRotationDegrees: Int, pixelWidthHeightRatio: Float),根据自己的环境获取视频信息即可


http://www.ppmy.cn/devtools/163626.html

相关文章

nuxt常用组件库html-validator应用解析

html-validator 主要用于自动验证nuxt服务器呈现的HTML(SSR和SSG),以检测可能导致水合错误的HTML常见问题,有助于减少水合错误,检测常见的可访问性错误。 安装 npx nuxilatest module add html-validator配置 若自动更新nuxt.config.ts配置文…

鸿蒙开发-画布综合示例

以下是一个更复杂的ArkTS示例,它展示了如何在画布上绘制多个形状(包括圆形、矩形和文本),并处理触摸事件来改变画布上的某些属性(如颜色)。 示例代码 import { Color, Point } from ohos.build.attr; imp…

【蓝桥杯集训·每日一题2025】 AcWing 5439. 农夫约翰真的种地 python

AcWing 5439. 农夫约翰真的种地 题目描述 Week 2 2月27日 农夫约翰在他的农场种植了 N N N 个芦笋,编号 1 ∼ N 1 \sim N 1∼N。 其中,第 i i i 个芦笋的初始高度为 h i h_i hi​,每经过一天高度会增长 a i a_i ai​。 给定一个 0…

Python在实际工作中的运用-指定目录内所有Excel文件转CSV

闲来无事浏览到《【办公自动化】使用Python批量处理Excel文件并转为csv文件》这篇博文,关于多层目录Excel转Csv在处理过程中略显繁复,而且灵活度不高,代码如下: import pandas as pd import os from datetime import datetime # …

dify镜像拉取不下来如何解决

# 启动docker(一定要先启动再添加dns) systemctl start docker #添加国境镜像和dns sudo vim /etc/docker/daemon.json { "registry-mirrors":[ "https://dockerpull.pw", "https://dockerhub.icu", "https://hu…

Redis 分布式锁

概念 在⼀个分布式的系统中,也会涉及到多个节点访问同⼀个公共资源的情况,此时就需要通过锁来做互斥控制,避免出现类似于 "线程安全" 的问题。但 C 的 std::mutex 只能在当前进程中⽣效, 在分布式的这种多个进程多个主机的场景下就…

C++核心指导原则: 源文件

C Core Guidelines 整理目录 哲学部分接口(Interface)部分函数部分类和类层次结构部分枚举部分资源管理部分表达式和语句部分性能部分并发和并行错误处理常量和不可变性泛型编程源文件 源文件规则 SF.1: Use a .cpp suffix for code files and .h for interface files if you…

微信小程序自定义导航栏,胶囊菜单按钮高度适配问题

抽离公共方法用条件编译对微信小程序&#xff0c;抖音小程序适配 公共组件模块建立一个导航模块 <template><view class"layout"><view class"navbar" ><view class"statusBar" :style"{height:getStatusBarHeight()p…