许多人使用 Android 设备分享视频。由于分享应用需要执行一些处理,因此接收的视频的质量通常不如原始视频。本文档介绍了如何优化共享视频的质量,以及要避免的一些常见视频处理陷阱。如需针对分享 HDR 视频内容进行优化,请参阅本页面中的使用转换器模块将 HDR 转码为 SDR。
主要做法是在准备分享视频时保持稳定的分辨率,并尽可能长时间地保持视频质量。
共享流水线
图 1 展示了分享视频的典型流程:
流水线包括以下步骤:
- 拍摄视频并对其进行编码,可能会在拍摄期间添加特效。 或者,用户可以跳过此步骤,从存储空间中选择通过其他应用预先录制的视频。
- 编辑、过滤、修饰或以其他方式处理视频。
- 调整视频大小或调整视频大小,为转码做好准备。
- 对视频进行转码以便分享。第 2 步中的过滤通常会在此步骤中应用。
您可以在流水线中通过两个步骤设置用于确定视频质量的参数:在初始录制期间编码,以及在分享之前进行转码。此外,您可能需要在完成最终转码步骤之前重新缩放视频,这也会影响质量。
建议
表 1 显示了视频质量的五个主要参数,并指出了哪些步骤可以使用这些参数。
参数 | 拍摄 | 共享 |
个人资料 | Y | Y |
分辨率 | Y | Y |
比特率 | Y | Y |
量化参数 (QP) | (很少) | Y |
B 帧 | 否 | Y |
个人资料
为了获得更好的结果,请使用特定编解码器提供的更高级的配置文件。对于 AVC 编码,请选择“High profile and level 4”。
分辨率、剪裁和缩放
在转码以便共享之前,您可以在缩放步骤中更改所拍摄视频的初始分辨率,但这样做可能会降低视频质量。我们建议您避免缩放,然后选择一个可以在整个流水线中使用的初始编码分辨率。另请注意,过度剪裁会导致图片质量不佳,尤其是放大剪裁后的图片时。请遵循以下准则:
- 选择分辨率,至少与最终共享分辨率一样大。
除非所有中间步骤都设计为支持较大的分辨率(例如初始拍摄期间的比特率较高),否则拍摄分辨率不应明显超过共享分辨率。
- 如果共享编码产生的分辨率为 720x1280,我们建议使用 720x1280 的拍摄分辨率。
- 如果拍摄与分享之间的中间步骤包括剪裁,请使用更高的拍摄分辨率(例如 1080x1920),并增加拍摄比特率以处理额外的像素。
过度剪裁会导致图片质量不佳,尤其是在剪裁后的图片放大时。
避免从较低分辨率提升到较高分辨率。扩展功能会尝试创建不存在的细节。从一开始就需要采用更高的分辨率。
如果必须调大,请调整编码参数。例如,如果分辨率更高的像素是原来的两倍,比特率就会翻倍。
分辨率和比特率彼此相关。例如,如果通过最终转码为低比特率的共享流水线传输高分辨率视频,那么与从低分辨率开始相比,产生的图像质量较差。随着比特率降低,会出现交叉点,分辨率越小,会产生更好的结果:
比特率 | 分辨率 |
5 Mbps 以上 | 1080x1920 |
1.5 - 5 Mbps 以上 | 720x1280 |
1.5 Mbps 或更低 | 与标清等效。宽高比为 9:16 的相同像素数约为 416x736 |
许多热门应用以 720p 或更低的分辨率分享视频。数据表明,如果比特率介于 1.5 Mbps 到 5 Mbps 之间,则 720p 分辨率是合适的选择。
比特率
录制
使用更高的编码比特率可以最大程度地提高视频质量。我们建议您选择与原生相机应用的比特率。对于 720x1280 的分辨率,我们建议使用 10 Mbps 的捕获比特率。
由于拍摄编码是在设备上完成的,因此您可以使用更高的比特率来补偿大多数共享步骤转换,并且几乎不产生负面影响。较大的生成的文件仅用于设备上的操作。
您可以在最后的转码步骤降低比特率,如表 2 所示。
分享
比特率在共享时影响最大,因为它与将上传的视频大小直接相关。您需要在视频质量、文件传输时间和云端存储费用之间进行权衡。
在此阶段,编码配置文件、B 帧和 QP 边界值的选择也比捕获期间更重要。
我们建议采用 4-5 Mbps 的比特率(适用于 720x1280 的分辨率),以确保良好的视觉效果。
量化参数 (QP)
在 Android 12 及更高版本中,QP 键已标准化,可在 MediaFormat
API 和 NDK 媒体库中使用。在较低的 Android 版本中,只能通过在 MediaFormat
配置中使用供应商专用密钥的框架函数进行 QP 操作。
录制
在视频拍摄期间,请使用比特率控制,而不是 QP 设置,它们并非始终可用。
我们不建议调整 10Mbps(针对 720x1280)捕获比特率的 QP 设置。如果捕获比特率明显较低(720x1280 低于 5 Mbps),则 QP 设置为 40 可以很好地兼顾提升质量,而且不会强制编解码器过于频繁地超过目标比特率。
分享
我们建议将 QP 上限设为 40,尤其是在比特率低于 4 Mbps 时。 虽然这样可以确保编码视频的最低质量,但会产生更高的比特率。比特率的增加取决于视频的复杂程度。虽然分享应用可以容忍所生成视频的比特率变动,但可能无法容忍超过特定阈值的比特率变动。
您可以通过限制宽松(较高)QP 边界对视频重新编码以便分享来限制比特率增加。这样一来,编解码器便可以更自由地牺牲质量并保留视频的其他部分。您可对视频重新编码以便分享,因为这属于转码操作;而且您已经拍摄了要分享的视频。
缺点是,使用这些不同参数重复执行转码步骤会增加分享视频所需的时间。缩短此延迟时间的一种方法是查看已部分转码的视频,确定该视频是否超出您的比特率限制。如果不同,您可以停止转码,然后使用更合适的 QP 参数重试。
B 帧和编码配置文件
建议仅在共享步骤中使用 B 帧,并且仅在运行 Android 10 或更高版本时使用。
应用应使用 CodecCapabilities
检查支持的编码配置文件,因为并非所有设备都支持主要配置文件或高级配置文件。使用 AVC 编码器支持的最高配置文件:高 > 主 > 基准。为了安全起见,请勿在使用基准配置文件时配置 B 帧(KEY_LATENCY
或 KEY_MAX_B_FRAMES
),因为某些编码器可能会导致配置失败。
以下代码段假定了一个 'MediaFormat format'
,该 ID 将用于配置 AVC 编码器
Android 10
API 29 或更高级别
使用支持的最高配置文件并将 B 帧参数设置为 1:
format.setInt32(KEY_PROFILE, AVCProfileHigh);
format.setInt32(KEY_MAX_B_FRAMES, 1);
在这种情况下,请勿设置 KEY_LATENCY
。
Android 8、8.1 和 9
API 26、27、28
使用支持级别最高的配置文件,但禁止生成 B 帧。这考虑了这些系统版本的 MediaMuxer
中的一些限制
format.setInt32(KEY_PROFILE, AVCProfileHigh);
format.setInt32(KEY_LATENCY, 1);
KEY_LATENCY
值可禁止编解码器生成 B 帧,但仍利用其他编解码器效率。
如果您的应用不使用 MediaMuxer
来组建最终输出文件,您可以通过将 KEY_LATENCY
值设置为 2(而不是 1)来启用 B 帧。这样一来,编解码器就可以生成 B 帧。
Android 7.1 及更低版本
API 25 及更早版本
使用基准配置文件可获得最安全的结果。
format.setInt32(KEY_PROFILE, AVCProfileBaseline);
在版本 7 之前,Android AOSP 仅支持基准配置文件。不过,OEM 可能会在某些设备上启用主要/高级配置文件(也许是通过使用供应商专用配置文件)。
如果您的应用不使用 MediaMuxer
,您可以使用主配置文件或高级配置文件(如果编解码器支持)。没有用于控制 B 帧数量的公共格式密钥。
使用“转换器”模块将 HDR 转码为 SDR
从 Android 13(API 级别 33)开始,我们建议使用 Jetpack Media3 的 Transformer 模块将 HDR 内容共享给不支持 HDR 的应用、服务和设备。Transformer 模块的工作原理是,将输入 HDR 视频流色调映射到 SDR,并将结果另存为 MP4 格式,从而实现成功播放,同时不会丢失细节或图像亮度。
注意:在以 Android 12(API 级别 32)到 Android 7.0(API 级别 24)之间的系统版本为目标平台的设备上,Transformer 模块的运作方式有所不同。如果设备支持 HDR,您的应用会在不进行色调映射的情况下播放内容。如果设备不支持 HDR,系统会抛出一个错误,指明不支持 HDR 色调映射。
以下代码设置了一个转换器,它将输入色调映射到 SDR,并以输入格式(例如 H.264/AVC)对其进行重新编码:
Kotlin
val transformer = Transformer.Builder(context) .setTransformationRequest( TransformationRequest.Builder() .setHdrMode(TransformationRequest.HDR_MODE_TONE_MAP_HDR_TO_SDR) .build()) .addListener(/* ... */) .build()
Java
Transformer transformer = new Transformer.Builder(context) .setTransformationRequest( new TransformationRequest.Builder() .setHdrMode(TransformationRequest.HDR_MODE_TONE_MAP_HDR_TO_SDR) .build()) .addListener(/* ... */) .build();
如需试用色调映射功能,请参阅 Transformer 演示版应用。
您还可以使用 MediaCodec
设置色调映射,但实现更为复杂。如需了解详情,请参阅 MediaCodec
参考文档。