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的数据不同。

但是解码出来的YUV数据差别很大,做了一个简单的数据统计,YUV-A/B/C 的统计数据如下:

输入YUV是我做的一个灰阶图,覆盖0~256范围。

解出来的YUV情况分别如下

YUV-B:16~235

YUVC:0~256

所以造成两个YUV这么大差异的原因,一定是ffmpeg解码流程的不同。
把ffmpeg解码YUV的两段log拿出来比较一下:

可以看出,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字段解释如下:

后面还给了一些计算公式,简单来说就是,
如果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会把一种格式,解码成另一种格式。
对于 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。
只不过当初没看懂罢了。

3.3 解决方案

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

看一下ffmpeg支持的mode:

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也不会报错,这里还是要自己在check看一遍。

4. 参考链接

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

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

  1. 记录一个有关QT生成PDF的过程

    直接上代码,代码中添加注释进行解释,方便自己和大家研究. 首先是头文件 genpdf.h #ifndef GENPDF_H #define GENPDF_H#include <QObject&g ...

  2. ffmpeg解码视频文件并播放

    最近学习了一下如何使用ffmpeg解码音视频,网上的教程挺多但是也挺杂的,搞了好几天,明白了ffmpeg解码音视频的大体流程,这里记录一下ffmpeg解码视频并播放音视频的例子,但并没有做音频.视频播 ...

  3. 【Qt+FFmpeg】 - FFmpeg解码详细流程

    目录 一:视频解码流程 二:FFMPEG解码流程 三:FFmpeg解码函数 四:FFmpeg解码的数据结构 五:FFmpeg数据结构简介 六:FFmpeg数据结构分析 七:像素数据转换 八:FFMPE ...

  4. FFmpeg开发笔记(七):ffmpeg解码音频保存为PCM并使用软件播放

    若该文为原创文章,转载请注明原文出处 本文章博客地址:https://blog.csdn.net/qq21497936/article/details/108799279 各位读者,知识无穷而人力有穷 ...

  5. 一个可以在线生成条形码的网站

    记录一个在网上生成条形码的网站,以备用到时免得到处找: http://www.tec-it.com/online-demos/tbarcode/barcode-generator.aspx?LANG= ...

  6. 从零实现简易播放器:4.ffmpeg 解码视频为yuv数据-使用avcodec_send_packet与avcodec_receive_frame

    ffmpeg 解码视频为yuv数据 作者:史正 邮箱:shizheng163@126.com 如有错误还请及时指正 如果有错误的描述给您带来不便还请见谅 如需交流请发送邮件,欢迎联系 csdn : h ...

  7. 用surfaceview播放FFmpeg解码视屏

    关于FFmpeg解码请看第一篇教程:FFmpeg解码 下载转码库libyuv 一般我们用surfaceview播放视频都是才用RGBA格式等播放的,但我们解码之后的视频可能是h.264等等 所以我们这 ...

  8. FFmpeg再学习 -- FFmpeg解码知识

    继续看雷霄骅的 课程资料 - 基于FFmpeg+SDL的视频播放器的制作 前面用了五个篇幅来讲 FFmpeg,其主要目的是为实现将图片转视频的功能. 总的来说,对于 FFmepg 多少有一些了解了.但 ...

  9. ffmpeg解码H.264视频数据,MFC播放视频

    ffmpeg 是一个完整的视频流解决方案,开源且有良好的跨平台性,ffmpeg具有强大的多媒体数据处理能力,能够实现视频的采集,多种视频格式间转换,给视频添加水印等多种功能,已被 VLC.Mplaye ...

最新文章

  1. 院士戴琼海:脑科学走向人工智能的重要路径
  2. php redis 管道技术,Redis管道技术这么厉害,你都用对了吗
  3. Xamarin Essentials教程发送邮件Email
  4. DL:关于深度学习常用数据集中训练好的权重文件(Deeplab v3、MobileNet、InceptionV3、VGG系列、ResNet、Mask R-CNN )下载地址集合(持续更新)
  5. 用python 中的链表 实现 截取其中一部分_Python数据结构——链表的实现
  6. String定义字符串,实际操作
  7. cassandra可视化工具_耗时1个月整理!160种Python标准库、第三方库和外部工具都有了...
  8. 编译AVX代码,升级Redhat 5.5 GCC至4.7.1
  9. 在CMakeLists.txt文件中包含Eigen
  10. c++ 工厂模式_Java面试专题之五:设计模式学习,详细分析工厂方法模式
  11. 数据--第35课 - 创建二叉树
  12. APP分发渠道的竞争分析
  13. python微信红包代码_哄女朋友必备之微信自动发红包脚本(python+adb+androidviewclient)...
  14. 离职原因要如何写才能不引发纠纷
  15. proface普洛菲斯触摸屏维修GP4601TAA PFXGP4601TAA及故障处理
  16. 骞云科技 DevOps 实践
  17. python tcl tk_安装Python WARNING: The version of Tcl/Tk (8.5.9)
  18. Flutter组件--重叠布局/相对布局(Stack,Positioned组件)
  19. 计算机快速结束进程,结束进程快捷键,详细教您电脑结束进程快捷键怎么操作...
  20. Vue--keep-alive--详解

热门文章

  1. 重装系统教程(适合小白)
  2. 蛇形走线用于什么方面,一文告诉你
  3. 香帅的北大金融学课笔记15 -- 大师投资智慧
  4. 安卓中Paint类和Canvas类的方法汇总
  5. 云图(词云图)实现方式
  6. HDOJ/HDU 2551 竹青遍野(打表~)
  7. 谁动了你的cookie
  8. 操作系统实验八:页面置换模拟程序设计
  9. 计算机电脑照片大小,电脑上怎么调整照片kb
  10. wxpython后台线程更新界面控件方法