从 H.264 的 SPS 中提取图像宽高,就像拆快递盒里的说明书找尺寸——关键看两个参数,再处理可能的裁剪!
以下是具体步骤:
一、核心参数:宏块数与乘法
-
获取宏块数量:
- 宽度宏块数:
pic_width_in_mbs_minus1 + 1
(如pic_width_in_mbs_minus1=119→ 120个宏块) - 高度宏块数:
pic_height_in_map_units_minus1 + 1
(如pic_height_in_map_units_minus1=67→ 68个宏块)
- 宽度宏块数:
-
转换为像素:
- 宽度:
(pic_width_in_mbs_minus1 + 1) * 16
(120 * 16 = 1920像素) - 高度:
(pic_height_in_map_units_minus1 + 1) * 16
(68 * 16 = 1088像素 → 但实际可能需裁剪)
- 宽度:
二、处理裁剪(Frame Cropping)
-
检查标志位:
SPS 中的frame_cropping_flag表示是否启用裁剪。- 若为1:需根据裁剪参数调整最终显示尺寸。
- 若为0:直接使用计算的宽高。
-
裁剪参数解析(若启用裁剪):
frame_crop_left_offset:左侧裁剪像素数frame_crop_right_offset:右侧裁剪像素数frame_crop_top_offset:顶部裁剪像素数frame_crop_bottom_offset:底部裁剪像素数
-
计算实际显示尺寸:
- 显示宽度 = 原宽度 - (左裁剪 + 右裁剪)
- 显示高度 = 原高度 - (上裁剪 + 下裁剪)
示例:
原宽高 1920x1088,裁剪参数:
- 左裁剪=0,右裁剪=0,上裁剪=4,下裁剪=4
- 最终显示尺寸:1920x1080(1088 - 8 = 1080)
三、代码逻辑(伪代码)
def get_resolution(sps):
# 提取宏块数
width_mb = sps.pic_width_in_mbs_minus1 + 1
height_mb = sps.pic_height_in_map_units_minus1 + 1
# 计算原始宽高(16像素/宏块)
raw_width = width_mb * 16
raw_height = height_mb * 16
# 处理裁剪
if sps.frame_cropping_flag:
crop_left = sps.frame_crop_left_offset * 2 # 单位是亮度像素间隔(需乘2)
crop_right = sps.frame_crop_right_offset * 2
crop_top = sps.frame_crop_top_offset * 2
crop_bottom = sps.frame_crop_bottom_offset * 2
display_width = raw_width - (crop_left + crop_right)
display_height = raw_height - (crop_top + crop_bottom)
else:
display_width = raw_width
display_height = raw_height
return (display_width, display_height)
四、常见问题
-
为什么高度可能是1088而非1080?
- 编码器要求宏块对齐(16的倍数),1080无法被16整除 → 补到1088再裁剪。
-
如何解析SPS中的参数?
- SPS参数使用 指数哥伦布编码(Exp-Golomb) ,建议用现成库(如FFmpeg的
h264_parser)。
- SPS参数使用 指数哥伦布编码(Exp-Golomb) ,建议用现成库(如FFmpeg的
-
裁剪参数单位是什么?
- 以亮度像素的间隔为单位,实际像素数需乘2(如
frame_crop_top_offset=2→ 裁剪4像素)。
- 以亮度像素的间隔为单位,实际像素数需乘2(如
五、总结口诀
“SPS里找宽高,宏块数量先记牢。
乘十六后得原值,裁剪参数再减掉。
解析注意哥伦布,现成库函数更高效!”