最近在实现视频预加载功能,遇到了较多的疑问未解决,但机缘巧合解决了困扰我很久的某些视频
展示异常的问题(被压扁),如下图
我的实现方法:
@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.0 | pixelWidthHeightRatio = 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°),onVideoSizeChanged
的 width
和 height
会互换,此时需先处理旋转,再应用 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),根据自己的环境获取视频信息即可