前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何在H264码流的SPS中获取宽和高信息?

如何在H264码流的SPS中获取宽和高信息?

作者头像
liuzhen007
发布2023-03-08 16:40:55
2.7K0
发布2023-03-08 16:40:55
举报
文章被收录于专栏:流媒体音视频流媒体音视频

前言

了解H264视频编码格式的小伙伴都知道,H264编码中存在两个非常重要的参数集。没错,它们就是序列参数集(SPS)和图像参数集(PPS),而且通常情况下,PPS会依赖SPS中的部分参数信息,同时,视频码流的宽高信息也存储在SPS中。那么如何从中获取视频的宽高信息呢,就是今天本文的主要内容。

正文

一、SPS的结构

对H264码流进行解码时,肯定会用到SPS中的相关参数,因此,我们非常有必要了解其中参数的含义。其中,H.264标准协议中(文档的7.3.2.1.1部分)规定的SPS格式如下图所示:

接下来,介绍一下上图中的部分参数。

(1) profile_idc

标识当前H.264码流的profile。我们知道,H.264中定义了三种常用的档次profile:

基准档次:baseline profile;

主要档次:main profile;

扩展档次:extended profile;

在H.264的SPS中,第一个字节表示profile_idc,根据profile_idc的值可以确定码流符合哪一种档次。判断规律如下:

profile_idc = 66 → baseline profile;

profile_idc = 77 → main profile;

profile_idc = 88 → extended profile;

在新版的标准中,还包括了High、High 10、High 4:2:2、High 4:4:4、High 10 Intra、High

4:2:2 Intra、High 4:4:4 Intra、CAVLC 4:4:4 Intra等,每一种都由不同的profile_idc表示。

另外,constraint_set0_flag ~ constraint_set5_flag是在编码的档次方面对码流增加的其他一些额外限制性条件。

(2) level_idc

标识当前码流的Level。编码的Level定义了某种条件下的最大视频分辨率、最大视频帧率等参数,码流所遵从的level由level_idc指定。

当前码流中,level_idc = 0x1e = 30,因此码流的级别为3。

(3) seq_parameter_set_id

表示当前的序列参数集的id。通过该id值,图像参数集pps可以引用其代表的sps中的参数。

(4) log2_max_frame_num_minus4

用于计算MaxFrameNum的值。计算公式如下:

MaxFrameNum = 2^(log2_max_frame_num_minus4 + 4)

MaxFrameNum是frame_num的上限值,frame_num是图像序号的一种表示方法,在帧间编码中常用作一种参考帧标记的手段。

(5) pic_order_cnt_type

表示解码picture order count(POC)的方法。POC是另一种计量图像序号的方式,与frame_num有着不同的计算方法。该语法元素的取值为0、1或2。

(6) log2_max_pic_order_cnt_lsb_minus4

用于计算MaxPicOrderCntLsb的值,该值表示POC的上限。计算公式如下:

MaxPicOrderCntLsb = 2^(log2_max_pic_order_cnt_lsb_minus4 + 4)

(7) max_num_ref_frames

用于表示参考帧的最大数目。

(8) gaps_in_frame_num_value_allowed_flag

标识位,说明frame_num中是否允许不连续的值。

(9) pic_width_in_mbs_minus1

用于计算图像的宽度,单位为宏块个数。

(10) pic_height_in_map_units_minus1

使用PicHeightInMapUnits来度量视频中一帧图像的高度。PicHeightInMapUnits并非图像明确的以像素或宏块为单位的高度,而需要考虑该宏块是帧编码或场编码。

(11) frame_mbs_only_flag

标识位,说明宏块的编码方式。当该标识位为0时,宏块可能为帧编码或场编码;该标识位为1时,所有宏块都采用帧编码。根据该标识位取值不同,PicHeightInMapUnits的含义也不同,为0时表示一场数据按宏块计算的高度,为1时表示一帧数据按宏块计算的高度。

按照宏块计算的图像实际高度FrameHeightInMbs的计算方法为:

FrameHeightInMbs = ( 2 − frame_mbs_only_flag ) * PicHeightInMapUnits

(12) mb_adaptive_frame_field_flag

标识位,说明是否采用了宏块级的帧场自适应编码。当该标识位为0时,不存在帧编码和场编码之间的切换;当标识位为1时,宏块可能在帧编码和场编码模式之间进行选择。

(13) direct_8x8_inference_flag

标识位,用于B_Skip、B_Direct模式运动矢量的推导计算。

(14) frame_cropping_flag

标识位,说明是否需要对输出的图像帧进行裁剪。

(15) vui_parameters_present_flag

标识位,说明SPS中是否存在VUI信息。

二、SPS的存储位置

在H264码流中,都是以"0x00 0x00 0x01"或者"0x00 0x00 0x00 0x01"作为起始码的,找到起始码之后,使用开始码之后的第一个字节的低5位判断是否为7,也就是SPS类型标识,伪代码如下:

data[3] & 0x1f == 7 data[4] & 0x1f == 7

SPS 对于H264而言,就是编码后的第一帧,如果是读取的H264文件,就是第一个帧界定符和第二个帧界定符之间的数据,一般长度是4。

三、如何计算宽高信息

根据SPS信息计算视频宽高的常用公式如下:

代码语言:javascript
复制
width = (pic_width_in_mbs_minus1+1)*16;
height = (pic_height_in_map_units_minus1+1)*16;
代码语言:javascript
复制

但是这是针对宽高是16的整数倍的情况,如果宽高不是16整数倍时,frame_cropping_flag值为1,frame_mbs_only_flag为1,公式如下:(也可以认为这是统一公式)

代码语言:javascript
复制
width = ((pic_width_in_mbs_minus1 +1)*16) - frame_crop_left_offset*2 - frame_crop_right_offset*2;
height= ((2 - frame_mbs_only_flag)* (pic_height_in_map_units_minus1 +1) * 16) - \
(frame_crop_top_offset * 2) - (frame_crop_bottom_offset * 2);

四、举例分析

比如一个1080P视频的SPS信息如下:

pic_width_in_mbs_minus1 : 119 pic_height_in_map_units_minus1 : 67 frame_mbs_only_flag : 1 mb_adaptive_frame_field_flag : 0 direct_8x8_inference_flag : 1 frame_cropping_flag : 1 frame_crop_left_offset : 0 frame_crop_right_offset : 0 frame_crop_top_offset : 0 frame_crop_bottom_offset : 4

根据上面的统一公式,计算结果如下:

width = (119+1) * 18 - 0*2 - 0*2 = 1920 height = (2-1) * (67+1)*16 - 0*2 - 4*2 = 1088 - 8 = 1080

代码如下:

代码语言:javascript
复制
    // 宽高计算公式
    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);
    }

作者简介:😄大家好,我是 Data-Mining(liuzhen007),是一名典型的音视频技术爱好者,前后就职于传统广电巨头和音视频互联网公司,具有丰富的音视频直播和点播相关经验,对 WebRTC、FFmpeg 和 Electron 有非常深入的了解。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-02-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 玩转音视频 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 正文
    • 一、SPS的结构
      • 二、SPS的存储位置
        • 三、如何计算宽高信息
          • 四、举例分析
          相关产品与服务
          云直播
          云直播(Cloud Streaming Services,CSS)为您提供极速、稳定、专业的云端直播处理服务,根据业务的不同直播场景需求,云直播提供了标准直播、快直播、云导播台三种服务,分别针对大规模实时观看、超低延时直播、便捷云端导播的场景,配合腾讯云视立方·直播 SDK,为您提供一站式的音视频直播解决方案。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档