【编解码】记录一个ffmpeg解码生成YUV的 color range 问题,以及video_full_range_flag用法。

这篇具有很好参考价值的文章主要介绍了【编解码】记录一个ffmpeg解码生成YUV的 color range 问题,以及video_full_range_flag用法。。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 问题起因

注: 本文软件版本:ffmpeg 4.4 。安霸cv2x SDK 3.0.9

最近有客户在使用我们芯片的avc/hevc 编码器的提了一个问题,很有意思,我花了2天来找原因和做实验。现将过程和结论记录如此,希望能帮助到后来者。

1.1 问题的现象

客户使用我们的芯片去编码一段固定的YUV 序列(golden data,记为YUV-A),
得到HEVC码流(记作StreamB)后,再使用ffmpeg解码,得到YUV(记作YUV-B)。

ffmpeg -i case1.h265 -vcodec rawvideo -pix_fmt nv12 -an YUV-B.yuv

然后使用PSNR 和 VMAF,参考YUV-A去计算YUV-B,计算视频质量,以此想评估编码器性能。
意外的发现,直接使用默认参数编解码后,得分不高。
但是如果强行码流中的SPS中的VUI的 video_full_range_flag 字段从1改为0,得到StreamC,再去解码,得到新的YUV(记为YUV-C),再评估,参考YUV-A去计算YUV-C,得分大大提高。
因此,客户想跟我们确认这个参数是否可以改动,有没有什么影响。

1.2 问题的分析

首先得分高低肯定是因为每个像素的差值变化。
我简单比较了一下两个文件的像素值,发现YUV-B和YUV-A差值较大,而YUV-C 和 YUV-A的差值就比较小。
而在码流文件中,用vega比较了streamB 和 streamC,发现YUV数据完全一致,二者的参数中仅有SPS中的video_full_range_flag不同。
如图,一共60帧2个GOP,是只有2个SPS的数据不同。
【编解码】记录一个ffmpeg解码生成YUV的 color range 问题,以及video_full_range_flag用法。
但是解码出来的YUV数据差别很大,做了一个简单的数据统计,YUV-A/B/C 的统计数据如下:

输入YUV是我做的一个灰阶图,覆盖0~256范围。
【编解码】记录一个ffmpeg解码生成YUV的 color range 问题,以及video_full_range_flag用法。

解出来的YUV情况分别如下

YUV-B:16~235
【编解码】记录一个ffmpeg解码生成YUV的 color range 问题,以及video_full_range_flag用法。
YUVC:0~256
【编解码】记录一个ffmpeg解码生成YUV的 color range 问题,以及video_full_range_flag用法。

所以造成两个YUV这么大差异的原因,一定是ffmpeg解码流程的不同。
把ffmpeg解码YUV的两段log拿出来比较一下:
【编解码】记录一个ffmpeg解码生成YUV的 color range 问题,以及video_full_range_flag用法。
可以看出,ffmpeg把streamB 和 streamC识别成了不同的格式,一个是jpeg,一个mpeg。
这就是问题的关键的,这些是什么?会导致什么?
OK,下面开始正式分析ffmpeg的解码。

2. video_full_range_flag

2.1 color range : full (jpeg)/ limited(mpeg)

在正式看 video_full_range_flag 的问题之前,我们需要先了解一下mpeg 和 jpeg这么两个东西。
YUV的色彩范围分为两种:

  1. full range Y / U / V 的范围是[0, 255]
  2. limited range Y [16,235]
    UV[16,240]
    为什么会有这两种区别,主要是应用场景不同
    电视机一般只支持240个色阶,从16~255,这就是limited
    电脑显示器支持255个色阶,从0~255,这就是full。

在下面的内容中,你可以默认这些东西是等效的,因为不同软件,不同模块,使用了不同的表达方式,但是他们的含义都是一样的。

“full range” = “jpeg” = “pc” = “cg” = “high rgb”

“limited range” = “mpeg” = “tv” = “broadcast” = “low rgb”

2.2 video_full_range_flag

接下来,我们先来看一下video_full_range_flag的含义,看看这个字段能不能随意修改。
我以H264的白皮书来分析,翻到附录E。
video_full_range_flag字段解释如下:
【编解码】记录一个ffmpeg解码生成YUV的 color range 问题,以及video_full_range_flag用法。
后面还给了一些计算公式,简单来说就是,
如果video_full_range_flag=0,代表这段码流是limited range的。
如果video_full_range_flag=1,代表这段码流是full range的。
同时,默认值为0.
我不是很理解的就是为什么默认是0。
是个历史遗留问题?为了以前都是电视机播放? 可能是为了过去的兼容性问题吧。一直也不改。
感觉放到现在还是默认为1比较好,做一个全范围的。
我们芯片里的参数就是默认为1的。我认为1更全面更合理。

3. ffmpeg的解码问题

3.1 解码流程

回到ffmpeg的解码问题,从日志log可以看出来。
【编解码】记录一个ffmpeg解码生成YUV的 color range 问题,以及video_full_range_flag用法。

ffmpeg会把一种格式,解码成另一种格式。
对于 streamB -> YUV-B,是从 yuv420p(tv, bt709) 转到nv12(tv, bt709, progressive)。
对于 streamC-> YUV-C,是从 yuvj420p(pc, bt709)转到nv12(tv, bt709, progressive)。
对于输入的格式:
tv 和 pc我们前面已经解释过了,是color range,这个值就是根据 码流中的 “video_full_range_flag” 字段来确定的。
但是输出的格式:
我就不能理解了,居然默认是tv,也就是limited?
为什么呢?就是因为这个,导致了二者解码流程的不同,进而YUV数据出现巨大的差异, PSNR的得分变化很大。
下面来分析一下流程,
为什么streamB的分低,streamC的分高。

  1. StreamB
    我们的reference YUV 是 full range的。
    使用编码器编出来的H265也是full range的,没有做色彩的映射,同时标注了video_full_range_flag=1。
    ffmpeg检测到码流是full range的(因为video_full_range_flag=1),但是它默认输出limited range的 YUV,因此做了色彩映射,把[0,255]的范围映射到了[16, 235]之间,相当于每个像素值都做了偏移。
    在最后计算得分的时候,这些偏移都被当做了噪声。refer YUV是[0, 255]的,结果YUV是[16, 235]的,可想而知,MSE均方差很大,得分就低。

  2. SteamC
    我们的reference YUV 是 full range的。
    使用编码器编出来的H265也是full range的,没有做色彩的映射,但是video_full_range_flag被强制改成了0。
    ffmpeg检测到码流是limited range的(因为video_full_range_flag=0),而且它默认输出limited range的 YUV,因此没有色彩映射,保持了码流中的color range,码流中的色彩范围实际是full range,相当于每个像素值都没有添加偏移。
    在最后计算得分的时候,因为没有偏移,每个像素间的差值就小,所以MES小,得分高。

这就是根本原因。

3.2 警告: [swscaler @ 0000022f98f360c0] deprecated pixel format used, make sure you did set range correctly

log中有一句warning,之前忽略了。
看了一下代码,这句话的触发条件就是,使用yuvj420p(或者yuvj444p/yuvj422p) 这个格式。
我们的码流中的video_full_range_flag=1导致在解码过程中,设置src format是yuvj420p,触发了这个打印。
已经提醒了 检查设置range。
只不过当初没看懂罢了。
【编解码】记录一个ffmpeg解码生成YUV的 color range 问题,以及video_full_range_flag用法。

3.3 解决方案

针对full range的reference YUV, full range编码的encoder,在用ffmpeg解码的时候,需要指定输出的范围是full,而不能使用默认的limited!

看一下ffmpeg支持的mode:

【编解码】记录一个ffmpeg解码生成YUV的 color range 问题,以及video_full_range_flag用法。

ffmpeg.exe -i case.h265 -vcodec rawvideo -pix_fmt nv12 -an case.yuv -lavfi "scale=out_range=full"

注意最后的
-lavfi “scale=out_range=full”

最后再check一下ffmpeg中的log是不是变化了
【编解码】记录一个ffmpeg解码生成YUV的 color range 问题,以及video_full_range_flag用法。
因为有时候我发现有些参数并没有生效,但是ffmpeg也不会报错,这里还是要自己在check看一遍。文章来源地址https://www.toymoban.com/news/detail-409774.html

4. 参考链接

  • 【错帖归档】B站视频压制参数需要调整——色彩范围在转码中的重要性 – 这篇分析的挺中肯的,列在这里不是因为配图
  • color range问题总结 (附:色彩空间简介) – 总结的挺好,也不是因为配图
  • full range 和 limit range的区别
  • ffmpeg的色彩4个属性

到了这里,关于【编解码】记录一个ffmpeg解码生成YUV的 color range 问题,以及video_full_range_flag用法。的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 使用NVIDIA GPU FFmpeg转码 YUV to H264(成功)

    NVIDIA官方教程:链接,本篇内容主要参考2.2 Software Setup。 确保nvidia-smi能够正常使用: 注意要与显卡驱动版本对应,验证toolkit是否正确安装: 下载地址 编译方法:解压进入文件夹后 验证安装          显示版本号证明安装成功: 下载地址 配置方法: 进入ffmpeg-x.x文件夹

    2024年02月06日
    浏览(36)
  • FFmpeg安装问题记录

    在CentOS操作系统上安装FFmpeg的方法如下: 更新系统软件包: 安装必要的依赖软件: 下载源代码: 进入FFmpeg目录: 配置并生成构建脚本: 构建并安装FFmpeg: 完成安装后,可以通过在终端输入 ffmpeg 来验证FFmpeg是否已正确安装。 按照以上步骤基本可以将ffmpeg程序以缺省授权是

    2024年02月10日
    浏览(40)
  • 在Ubuntu虚拟机使用ffmpeg采集摄像头的yuv视频数据

    提取命令: ./cl.mp4为当前目录下的cl.mp4视频文件 -an其中a代表是audio,n代表是none,意思就是过滤掉音频 -c:v代表的是视频的编解码器 rawvideo代表我们使用rawvideo这个工具对视频进行处理 -pix_fmt yuv420p表示我们指定输出yuv视频的格式,这里我们指定为yuv420p 最后一个就是我们输出

    2023年04月11日
    浏览(72)
  • ffmpeg写YUV420文件碰到阶梯型横线或者条纹状画面的原因和解决办法

    版权声明:本文为CSDN博主「文三~」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/asdasfdgdhh/article/details/112831581 看到了,转载,留着备份一下 阶梯型横线: 条纹状画面:   出现阶梯型横线的原因是:对FFmpeg中AVFrame中

    2024年02月02日
    浏览(31)
  • 最简单的基于 FFmpeg 的视频编码器(YUV 编码为 HEVC(H.265))

    参考雷霄骅博士的文章,链接:最简单的基于FFmpeg的视频编码器-更新版(YUV编码为HEVC(H.265)) 前一阵子做过一个基于 FFmpeg 的视频编码器的例子:最简单的基于 FFmpeg 的视频编码器(YUV 编码为 H.264)。 在该例子中,可以将 YUV 像素数据(YUV420P)编码为 H.264 码流。因为 FFmpeg

    2024年04月27日
    浏览(37)
  • ffmpeg将图片压缩成视频过程中的问题记录

    问题描述:服务器集群上在使用如下命令对img_path文件夹下的图片(图片名1.jpg……300.jpg)进行批量合成视频过程中,ffmpeg创建完视频文件后,写入过程中,自动kill,捕获异常为空。 问题原因:集群pods的内存不够,导致ffmpeg在创建完视频文件后,写入过程中内存不够,ffmpeg自动

    2024年02月12日
    浏览(39)
  • 玩转rk3588(六):rk3588使用ffmpeg实现硬件解码,解决opencv中VideoCapture获取网络摄像头视频时,一直在open时返回false的问题(一)

    目录 0、前言 1、开发环境 2、安装rkmpp 3、安装x264 4、安装libdrm 5、安装ffmpeg 6、相关报错 1)libdrm编译过程中报错

    2024年02月03日
    浏览(38)
  • FFmpeg编解码流程解读--视频解码1

    首先我们知道ffmpeg是一个开源的音视频编解码,封装和解封装的工具。具体的下载方式这里不多赘述(感兴趣百度自行下载源码)。这里主要将编解码。ffmpeg音视频编解码依赖libavcodec。其为我们提供一套架构,其中包含了编解码器。这里主要介绍我们常用的一些API接口去处理

    2023年04月08日
    浏览(30)
  • FFMPEG解码实时流,支持cpu、gpu解码

    官网下载的ffmpeg目前只能下载到X64版本的库,具体编译请参考windows编译ffmpeg源码(32位库)_windows 32位ffmpeg动态库-CSDN博客 直接上代码 解码显示效果图 英伟达显卡播放效果因本人没有显卡不在这里展示,可以看出通过硬解降低将近一半的cpu。 代码参考 https://download.csdn.net/

    2024年01月18日
    浏览(33)
  • FFmpeg之视频解码

    第一次写CSDN,先熟悉熟悉FFmpeg 常用结构体 常用方法函数 视频解码的一些基础知识: 视频流是按一定的顺序排列 I 帧, P 帧 和 B 帧的。   因此,重要性:I 帧 P 帧 B 帧。由于不同类型的帧的重要性不同,这意味着我们要按播放连贯的视频,就必须按照一定规定来显示这些帧

    2023年04月08日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包