You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

为何FFmpeg读取的YUV数据与原始输入不一致?HDR视频制作存疑

问题分析与解决方案

你遇到的YUV数据不一致和HDR视频验证问题,我可以从编码流程、位深处理和验证方法这几个方面来帮你拆解解决:

一、YUV提取数据不一致的原因与解决方法

1. 核心原因:位深转换+有损编码

你的编码流程里有两个关键因素导致数据偏差:

  • 位深转换:输入是8位yuv420p,但编码时通过format=yuv420p10le转成了10位格式,而提取时又用-pix_fmt yuv420p强制转回8位,这个过程会丢失部分精度。
  • 有损压缩:即使crf=12是高质量设置,libx265的默认模式仍是有损压缩,会对像素值做微小调整来优化码率,所以原始全白帧的Y值(235)会出现234/235的波动。

2. 解决方法

方法1:提取时保持10位格式

修改提取命令,直接提取10位YUV,避免位深转换带来的损失:

ffmpeg -i test.mp4 -vframes 1 -c:v rawvideo -pix_fmt yuv420p10le read_yuv_10bit.yuv

读取时用uint16类型解析10位数据:

read_yuv_10bit = np.fromfile("read_yuv_10bit.yuv", dtype='uint16')
print("read_yuv_10bit", read_yuv_10bit[:10])

原始8位Y值235转成10位后是235 << 2 = 940(8位到10位是扩展量化范围,像素值左移2位),你会看到提取的10位Y值接近940(有损编码下有微小波动是正常的)。

方法2:使用无损编码

如果需要完全一致的YUV数据,在x265参数中添加lossless=1开启无损压缩:

ffmpeg -y -s 100*100 -pix_fmt yuv420p -threads 4 -r 1 -stream_loop -1 -f rawvideo -i write_yuv.yuv -vf \
scale=out_h_chr_pos=0:out_v_chr_pos=0,format=yuv420p10le \
-c:v libx265 -tag:v hvc1 -t 10 -pix_fmt yuv420p10le -preset medium -x265-params \
crf=12:colorprim=bt2020:transfer=smpte2084:colormatrix=bt2020nc:master-display=\"G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,1)\":max-cll=\"1000,400\":lossless=1 \
-an test_lossless.mp4

此时提取10位YUV数据,会和原始转10位后的结果完全一致。

关于imageio读取的结果

imageio读取HDR视频时会自动做色调映射(Tone Mapping),把HDR的SMPTE2084转换函数映射到SDR的RGB空间,所以得到的[253,253,253]是正常的映射结果,并非原始HDR像素值。

二、HDR视频的验证方法

1. 检查HDR元数据

用FFmpeg查看视频的色彩参数,确认HDR元数据是否正确写入:

ffmpeg -i test.mp4 -hide_banner

你应该在输出中看到类似以下的信息,重点确认color_primariescolor_trccolor_space以及master display、max-cll和你设置的一致:

Stream #0:0(und): Video: hevc (Main 10) (hvc1 / 0x31637668), yuv420p10le(tv, bt2020nc/bt2020/smpte2084), 100x100, 1 fps, 1 tbr, 16384 tbn, 1 tbc (default)
Metadata:
  encoder         : Lavc60.31.100 libx265
  color_range     : tv
  color_space     : bt2020nc
  color_primaries : bt2020
  color_trc       : smpte2084
  chroma_location : left
Mastering display metadata:
  Red:     (0.708,0.292), Green: (0.170,0.797), Blue: (0.131,0.046), White point: (0.3127,0.329)
  Luminance: min=0.0001 cd/m2, max=10000 cd/m2
Max content light level: 1000 cd/m2, Max frame average light level: 400 cd/m2

2. 检查编码位深

用ffprobe确认视频是10位编码:

ffprobe -v error -select_streams v:0 -show_entries stream=pix_fmt -of default=noprint_wrappers=1:nokey=1 test.mp4

输出应为yuv420p10le,说明是符合HDR标准的10位视频。

3. 播放验证

用支持HDR的播放器测试:

  • MPV:命令行添加--hdr-compute-peak参数,播放时会显示HDR相关状态;
  • Windows Movies & TV:若显示器支持HDR,播放时会自动切换到HDR模式,视频亮度会明显高于普通SDR内容;
  • VLC:需要在设置中开启“HDR support”,播放时查看是否识别为HDR视频。

4. 提取SEI信息验证

用FFmpeg导出HDR相关的SEI补充增强信息,确认元数据是否正确嵌入:

ffmpeg -i test.mp4 -dump_sections hdr -f null -

输出中会包含master display和max CLL的详细数据,和你设置的参数对比即可。

内容的提问来源于stack exchange,提问作者sianyi Huang

火山引擎 最新活动