为什么渲染结果是全绿屏
1.绿屏
由于渲染支持的是RGB,而不是YUV,解码一般输出YUV,如果解码报错,一般YUV都是0;
YUV转RGB的时候
Y = 0.299 R + 0.587 G + 0.114 B
U = -0.1687 R - 0.3313 G + 0.5 B + 128
V = 0.5 R - 0.4187 G - 0.0813 B + 128
R = Y + 1.402 (V-128)
G= Y - 0.34414 (U-128) - 0.71414 (V-128)
B= Y + 1.772 (U-128)
将Y,U,V=0 带入
差不多就是R = -126, G = 135, B = -126
其中RGB有取值范围, 都是[0, 255]
所以最后就是R=0, G=135, B=0
查看颜色表:rgb(0,135,0) 差不多就是绿
----来自知乎 Fenngtun
2、绿边
(119+1)*16 =1920
(67+1)*16 =1088
2.1 、SPS计算待解码图像宽高有两个公式:
当宽高是16的整数倍时:为什么选择16倍数,因为一般H264的宏块大小会使用16*16
H.264 中有这样两个语法元素,pic_width_in_mbs_minus1 表示的值是横向宏块的个数减 1,pic_height_in_map_units_minus1 表示的值是纵向宏块的个数减 1。
也就是说,把他们两个加上 1,就可以获得横向的宏块个数和纵向的宏块个数。那么我们已经知道一个宏块长 16 个像素,高 16 个像素,那么就可以得出视频宽高的计算公式了:
Width = (pic_width_in_mbs_minus1+1)*16;
Height = (pic_height_in_map_units_minus1+1)*16;
2.2、当宽高不是16的整数倍时:如宽高是1920*1080;当图像的宽高不是 16 的倍数的时候,H.264 会在图像的边沿添加一些像素,来补齐成 16 的倍数,
然后通过 frame_crop_left_offset, frame_crop_right_offset, frame_crop_top_offset, frame_crop_bottom_offset 这 4 个量来记录上下左右补齐了多少数据。我们把这个过程称之为 Crop;裁剪;
由于高度1080不是16的整数倍,需要裁剪,frame_corpping_flag =1 ,frame_mbs_only_flag =1;走的解析公式如下(如下代码公式2):https://blog.csdn.net/GerZhouGengCheng/article/details/107239415
width = (119+1) * 16 - 0*2 - 0*2 = 1920
height = (2-1) * (67+1)*16 - 0*2 - 4*2 = 1088 - 8 = 1080
但是如果数据是软编码或者某些硬件设备中的编码程序打错了标记,1080高度没有打裁剪标记位,解码时候就还是走2.1的宽高计算,计算出来的高度是1088;然后进行解码,可是解码不出来多余的8行像素的高度数据,此时底下8行YUV就是0.转换RGB就只剩下G是【0,255】之间的值,所以渲染的时候就会在底下有一个绿边;
# 公式二 width = (sps->pic_width_in_mbs_minus1+1) * 16; height = (2 - sps->frame_mbs_only_flag)* (sps->pic_height_in_map_units_minus1 +1) * 16); if(sps->frame_cropping_flag) { unsigned int crop_unit_x; unsigned int crop_unit_y; if (0 == sps->chroma_format_idc) // monochrome { crop_unit_x = 1; crop_unit_y = 2 - sps->frame_mbs_only_flag; } else if (1 == sps->chroma_format_idc) // 4:2:0 { crop_unit_x = 2; crop_unit_y = 2 * (2 - sps->frame_mbs_only_flag); } else if (2 == sps->chroma_format_idc) // 4:2:2 { crop_unit_x = 2; crop_unit_y = 2 - sps->frame_mbs_only_flag; } else // 3 == sps.chroma_format_idc // 4:4:4 { crop_unit_x = 1; crop_unit_y = 2 - sps->frame_mbs_only_flag; } width -= crop_unit_x * (sps->frame_crop_left_offset + sps->frame_crop_right_offset); height -= crop_unit_y * (sps->frame_crop_top_offset + sps->frame_crop_bottom_offset); }
3 绿边原因
视频文件或视频流可能采用了ATSC(美国的数字电视国家标准),Wiki上该标准对于MPEG-2有如下说明:
The 1080-line formats are encoded with 1920 × 1088 pixel luma matrices and 960 × 540 chroma matrices, but the last 8 lines are discarded by the MPEG-2 decoding and display process.
直译意思是:1080行格式使用1920×1088像素luma矩阵和960×540色度矩阵(UV)进行编码,但最后8行被MPEG-2解码和显示过程丢弃;但是解码后最后8行没有UV信息;带入RGB转换R和B的值会偏低,G的值偏高;就是鲜艳的绿色