H.264分辨率需从SPS中解析pic_width_in_mbs_minus1和pic_height_in_map_units_minus1,结合frame_mbs_only_flag等计算,实际宽高为宏块数×16(场模式高度×2);帧率仅当VUI中fixed_frame_rate_flag=1时可用time_scale/(2×num_units_in_tick)估算,否则应依赖PTS差值或容器信息。

从SPS中解析H.264分辨率(width/height)
H.264码流本身不带“宽高”明文字段,分辨率藏在SPS(Sequence Parameter Set)的pic_width_in_mbs_minus1和pic_height_in_map_units_minus1里,还需结合frame_mbs_only_flag和mb_adaptive_frame_field_flag计算。直接读裸码流时,得先定位SPS——它通常以0x00 0x00 0x00 0x01或0x00 0x00 0x01开头,后跟NALU type = 7。
实操建议:
立即学习“C++免费学习笔记(深入)”;
本地 Ollama 文生图工具。使用 x/z-image-turbo 模型生成图片,分辨率 1024x1024,每张图约耗时 90 秒。当用户说"生成图片"、"文生图"、"画一张图"、或提交中文提示词生成图像时使用。
- 用
avcC盒子(如MP4中)或裸流扫描方式找到SPS NALU起始位置,跳过NALU header(1字节)再解码RBSP - SPS是变长编码(Exp-Golomb),别用固定偏移硬读;推荐用FFmpeg的
ff_h264_decode_seq_parameter_set或手写简单Exp-Golomb解析器 - 注意
pic_width_in_mbs_minus1单位是宏块(16×16),所以实际宽度 = (pic_width_in_mbs_minus1+ 1) × 16;高度需先算出pic_height_in_map_units_minus1,再乘16,再根据frame_mbs_only_flag决定是否×2(场模式) - 常见错误:把SPS里的
bit_depth_luma_minus8当成分辨率、忽略crop_left/crop_right等裁剪参数(它们影响显示宽高,但原始解码宽高仍由宏块数决定)
从SPS+PPS推导帧率(framerate)
H.264标准不强制携带帧率,但SPS里有time_scale和num_units_in_tick两个关键字段,满足:framerate = time_scale / (2 × num_units_in_tick)(仅当fixed_frame_rate_flag == 1时成立)。这个值只是“标称帧率”,实际码流可能VFR(可变帧率),且很多编码器(如x264默认)根本不清零vui_parameters_present_flag,导致这两个字段不可用。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 先检查SPS中
vui_parameters_present_flag是否为1,再读timing_info_present_flag,否则time_scale无效 - 即使字段存在,也要验证
fixed_frame_rate_flag—— 它在nal_hrd_parameters_present_flag或vcl_hrd_parameters_present_flag为0时才有效,逻辑嵌套深,容易漏判 - 更可靠的做法:用PTS差值统计前N帧(比如50帧)的ΔPTS,除以
time_base(若已知);裸流无PTS时,只能依赖容器层(如MP4的sttsbox)或靠人眼估算 - 常见错误:直接用
time_scale / num_units_in_tick而没除2,或对非固定帧率流强行套公式,结果翻倍或归零
用FFmpeg快速提取(免解析裸流)
如果你只是想获取分辨率和帧率,而非实现解析器,FFmpeg是最稳的选择。它内部已处理SPS/PPS/VUI所有边界情况,且兼容各种封装格式。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 命令行:用
ffprobe -v quiet -show_entries stream=width,height,r_frame_rate -of default=nw=1 input.h264(注意.h264是裸流,需加-f h264参数:ffprobe -v quiet -f h264 -show_entries stream=width,height,r_frame_rate -of default=nw=1 input.h264) - C++调用:打开AVFormatContext后,遍历
ic->streams找视频流,用codecpar->width/codecpar->height读分辨率;帧率优先取stream->r_frame_rate(AVRational),fallback到codecpar->framerate - 注意裸流没有时间基,
stream->time_base常为{0, 0},此时r_frame_rate更可信;但若码流本身未写VUI,FFmpeg也会回退到“猜测模式”,可能返回1/0或0/0 - 性能影响:FFmpeg会自动解析前几个关键帧,无需解码,开销极小;但首次调用
avformat_find_stream_info可能因探测不足返回不完整信息,建议设probesize和analyzeduration参数
裸流解析时最易忽略的3个细节
手动解析SPS时,90%的问题不出在算法,而在边界条件和容器误导。
- SPS可能被RBSP emulation prevention bytes(
0x00 0x00 0x03)污染,解码前必须移除,否则Exp-Golomb解析错位 - 一个码流文件可能含多个SPS(如不同profile切换),应取第一个有效SPS,而非最后一个;FFmpeg用的是
first_sps逻辑 - 分辨率≠显示宽高:SPS给的是解码图像尺寸(coded frame size),而
vui_parameters里的overscan_appropriate_flag和video_signal_type可能要求按比例缩放,但绝大多数监控/点播场景忽略此字段
真正难的不是算公式,而是确认你拿到的那个SPS,确实是当前解码路径实际使用的那一份。

















