目录
视频转码后有色差要如何处理
KEY_COLOR_STANDARD
KEY_COLOR_RANGE
视频转码后有色差要如何处理
以下是回答,欢迎大家留言讨论补充:
1、色差是如何产生的?
1)有损压缩产生的质量损失。
- 解决方法为尽可能的提高码率。
- 可以使用 FFmpeg 指令查看原码率与输出码率对比,如果使用硬件编码码率要高于原码率一些,因为原文件可能使用了更高级的编码方式(软件编码)或编码参数(HEVC)。
2)颜色空间转换产生的损失。
- 解决方法为尽量避免颜色空间的转换,如果必须转换需要找到正确的颜色转换矩阵。
- 可以使用 FFmpeg 指令对比色差文件与原文件
color_range
、color_space
。
$ ffprobe -show_streams -I test.mp4
2、如何做颜色空间转换?
颜色空间转换每个模块都会有所涉及,播放器、转码、获取缩略图等,但按照底层模块划分如下:
1)解码模块:需要获取出正确的 ColorSpace
、ColorRange
,然后传递给后面的模块。
- iOS 模块直接存在于
CVPixelBuffer
,ColorSpace 为 CVImageBufferYCbCrMatrix
,ColorRange 在 iOS15 后包含了 FullRange
参数,之前需要根据 CVPixelBufferGetPixelFormatType(buffer) == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
判断。
- Android 模块需要根据解码后
MediaFormat
获取,ColorSpace 为 KEY_COLOR_STANDARD
,ColorRange 为 KEY_COLOR_RANGE
。
- FFmpeg 模块需要根据解码后数据 AVFrame 获取,ColorSpace 为
colorspace
,ColorRange 为 color_range
。
2)编码模块:根据外层输入的 ColorSpace
、ColorRange
,设置给编码器即可。
- iOS VideoToolBox 编码设置与解码相对应
kVTCompressionPropertyKey_YCbCrMatrix
。
- Android 编码设置与解码相对应
KEY_COLOR_STANDARD
、KEY_COLOR_RANGE
。
- FFmpeg X264 编码设置 x264_param_t 内
vui.b_fullrange
、vui.i_colmatrix
。
3)YUV 数据转换 RGBA 纹理模块。
- 数据转纹理主要涉及 GL 矩阵操作,根据解码后的 ColorSpace 与 ColorRange 生成合适的矩阵。
- GPUImage 矩阵生成,参考:GPUImage[1]。
- libyuv 矩阵生成(搜索 『bt.』),参考:libyuv[2]。
4)RGBA 纹理转换 YUV 数据模块。
- 纹理转数据与数据转纹理相反的流程,但具体转换为哪种 ColorSpace 与 ColorRange 都可以的。
- 参考 RGBA 转 YUV 即可:RGB2YUV[3]。
5)RGB 数据与 YUV 数据转换模块。
- 通常数据间转换使用
libyuv
,例如 I420 转换 RGBA,方法为 I420ToARGBMatrix
,参数支持设置矩阵 YuvConstants
。
3、其他建议
1)尽量减少自定义处理颜色空间转换。
Android 平台尽量使用 Surface 解码与编码,好处就是不需要手动处理。
2)ByteBuffer 编码必须设置 ColorSpace
、ColorRange
。
如果不设置底层不清楚输入进来的数据颜色格式,只能根据默认值随意发挥了。
3)ColorSpace
、ColorRange
默认值。
- 本地文件
ColorSpace
为空,则直接默认为 601
即可。
- 本地文件
ColorRange
为空,则直接默认为非 FullRange
。
如果你也对音视频技术感兴趣,比如,符合下面的情况:
- 在校大学生 → 学习音视频开发
- iOS/Android 客户端开发 → 转入音视频领域
- 直播/短视频业务开发 → 深入音视频底层 SDK 开发
- 音视频 SDK 开发 → 提升技能,解决优化瓶颈
不妨看看《是的,我建了一个进阶百万年薪的社群》了解一下这个社群,根据自己的需要,按需加入。
KEY_COLOR_STANDARD
在Android中,KEY_COLOR_STANDARD
是用于设置视频编码颜色标准的关键字。这个参数是在设置 MediaFormat
对象时使用的,该对象用于配置媒体编解码器(MediaCodec
)。以下是一个例子:
MediaFormat format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, width, height);
format.setInteger(MediaFormat.KEY_COLOR_STANDARD, MediaFormat.COLOR_STANDARD_BT709);
...
MediaCodec encoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
KEY_COLOR_RANGE
KEY_COLOR_RANGE
是在Android中用于设置视频编码颜色范围的关键字。这个参数也是在设置 MediaFormat
对象时使用的,该对象用于配置媒体编解码器(MediaCodec
)。以下是一个例子:
MediaFormat format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, width, height);
format.setInteger(MediaFormat.KEY_COLOR_RANGE, MediaFormat.COLOR_RANGE_FULL);
...
MediaCodec encoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
在这个例子中,我们创建了一个新的 MediaFormat
对象,用于配置一个 MediaCodec
对象。我们使用 KEY_COLOR_RANGE
来设置颜色范围为 COLOR_RANGE_FULL
。
就像 KEY_COLOR_STANDARD
一样,不是所有的设备或编码器都支持所有的颜色范围。在设置颜色范围之前,你应该检查设备或编码器是否支持你想要设置的颜色范围。
参考2:
https://stackoverflow.com/questions/68629271/opencv-read-write-video-color-difference