解析HEVC(H265)与H264的SPS参数

有时候来一个RTP包数据,是FU模式打包,没有起始码,我们使用工具无法进行参数解析,

 1 Hevc/H265 SPS 解析视频宽高

#include <iostream>
#pragma once
#include<string.h>
#include<stdio.h>
typedef unsigned char* LPBYTE;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned long  uint32;
typedef unsigned __int64  uint64;
typedef signed char  int8;
typedef signed short  int16;
typedef signed long  int32;
typedef signed __int64  int64;

struct vc_params_t
{
    int width, height;
    int profile, level;
    int nal_length_size;
    void clear()
    {
        memset(this, 0, sizeof(*this));
    }
};


class NALBitstream
{
public:
    NALBitstream() : m_data(NULL), m_len(0), m_idx(0), m_bits(0), m_byte(0), m_zeros(0) {};
    NALBitstream(void* data, int len) { Init(data, len); };
    void Init(void* data, int len)
    {
        m_data = (LPBYTE)data;
        m_len = len;
        m_idx = 0;
        m_bits = 0;
        m_byte = 0;
        m_zeros = 0;
    };

    uint8 GetBYTE()
    {
        if (m_idx >= m_len)
            return 0;
        uint8 b = m_data[m_idx++];
        // to avoid start-code emulation, a byte 0x03 is inserted
        // after any 00 00 pair. Discard that here.
        if (b == 0)
        {
            m_zeros++;
            if ((m_idx < m_len) && (m_zeros == 2) && (m_data[m_idx] == 0x03))
            {

                m_idx++;
                m_zeros = 0;
            }
        }
        else {
            m_zeros = 0;
        }
        return b;
    };

    uint32 GetBit()
    {
        if (m_bits == 0)
        {
            m_byte = GetBYTE();
            m_bits = 8;
        }
        m_bits--;
        return (m_byte >> m_bits) & 0x1;
    };

    uint32 GetWord(int bits)
    {

        uint32 u = 0;
        while (bits > 0)
        {
            u <<= 1;
            u |= GetBit();
            bits--;
        }
        return u;
    };

    uint32 GetUE()
    {
        // Exp-Golomb entropy coding: leading zeros, then a one, then
        // the data bits. The number of leading zeros is the number of
        // data bits, counting up from that number of 1s as the base.
        // That is, if you see
        //      0001010
        // You have three leading zeros, so there are three data bits (010)
        // counting up from a base of 111: thus 111 + 010 = 1001 = 9
        int zeros = 0;
        while (m_idx < m_len && GetBit() == 0)
            zeros++;
        return GetWord(zeros) + ((1 << zeros) - 1);
    };


    int32 GetSE()
    {
        // same as UE but signed.
        // basically the unsigned numbers are used as codes to indicate signed numbers in pairs
        // in increasing value. Thus the encoded values
        //      0, 1, 2, 3, 4
        // mean
        //      0, 1, -1, 2, -2 etc
        uint32 UE = GetUE();
        bool positive = UE & 1;
        int32 SE = (UE + 1) >> 1;
        if (!positive)
        {
            SE = -SE;
        }
        return SE;
    };


private:
    LPBYTE m_data;
    int m_len;
    int m_idx;
    int m_bits;
    uint8 m_byte;
    int m_zeros;
};


bool  ParseSequenceParameterSet(uint8* data, int size, vc_params_t& params)
{
    if (size < 20)
    {
        return false;
    }
    NALBitstream bs(data, size);

    // seq_parameter_set_rbsp()
    bs.GetWord(4);// sps_video_parameter_set_id
    int sps_max_sub_layers_minus1 = bs.GetWord(3); // "The value of sps_max_sub_layers_minus1 shall be in the range of 0 to 6, inclusive."
    if (sps_max_sub_layers_minus1 > 6)
    {
        return false;
    }
    bs.GetWord(1);// sps_temporal_id_nesting_flag
    // profile_tier_level( sps_max_sub_layers_minus1 )
    {
        bs.GetWord(2);// general_profile_space
        bs.GetWord(1);// general_tier_flag
        params.profile = bs.GetWord(5);// general_profile_idc
        bs.GetWord(32);// general_profile_compatibility_flag[32]
        bs.GetWord(1);// general_progressive_source_flag
        bs.GetWord(1);// general_interlaced_source_flag
        bs.GetWord(1);// general_non_packed_constraint_flag
        bs.GetWord(1);// general_frame_only_constraint_flag
        bs.GetWord(44);// general_reserved_zero_44bits
        params.level = bs.GetWord(8);// general_level_idc
        uint8 sub_layer_profile_present_flag[6] = { 0 };
        uint8 sub_layer_level_present_flag[6] = { 0 };
        for (int i = 0; i < sps_max_sub_layers_minus1; i++) {
            sub_layer_profile_present_flag[i] = bs.GetWord(1);
            sub_layer_level_present_flag[i] = bs.GetWord(1);
        }

        if (sps_max_sub_layers_minus1 > 0) {
            for (int i = sps_max_sub_layers_minus1; i < 8; i++) {
                uint8 reserved_zero_2bits = bs.GetWord(2);
            }
        }

        for (int i = 0; i < sps_max_sub_layers_minus1; i++) {
            if (sub_layer_profile_present_flag[i]) {
                bs.GetWord(2);// sub_layer_profile_space[i]
                bs.GetWord(1);// sub_layer_tier_flag[i]
                bs.GetWord(5);// sub_layer_profile_idc[i]
                bs.GetWord(32);// sub_layer_profile_compatibility_flag[i][32]
                bs.GetWord(1);// sub_layer_progressive_source_flag[i]
                bs.GetWord(1);// sub_layer_interlaced_source_flag[i]
                bs.GetWord(1);// sub_layer_non_packed_constraint_flag[i]
                bs.GetWord(1);// sub_layer_frame_only_constraint_flag[i]
                bs.GetWord(44);// sub_layer_reserved_zero_44bits[i]
            }

            if (sub_layer_level_present_flag[i]) {
                bs.GetWord(8);// sub_layer_level_idc[i]
            }
        }
    }

    uint32 sps_seq_parameter_set_id = bs.GetUE(); // "The  value  of sps_seq_parameter_set_id shall be in the range of 0 to 15, inclusive."
    if (sps_seq_parameter_set_id > 15) {
        return false;
    }

    uint32 chroma_format_idc = bs.GetUE(); // "The value of chroma_format_idc shall be in the range of 0 to 3, inclusive."
    if (sps_seq_parameter_set_id > 3) {
        return false;
    }

    if (chroma_format_idc == 3) {
        bs.GetWord(1);// separate_colour_plane_flag
    }

    params.width = bs.GetUE(); // pic_width_in_luma_samples
    params.height = bs.GetUE(); // pic_height_in_luma_samples

    if (bs.GetWord(1)) {// conformance_window_flag
        bs.GetUE();  // conf_win_left_offset
        bs.GetUE();  // conf_win_right_offset
        bs.GetUE();  // conf_win_top_offset
        bs.GetUE();  // conf_win_bottom_offset
    }

    uint32 bit_depth_luma_minus8 = bs.GetUE();
    uint32 bit_depth_chroma_minus8 = bs.GetUE();

    if (bit_depth_luma_minus8 != bit_depth_chroma_minus8) {
        return false;
    }

    return true;
}
int main()
{
    vc_params_t params = { 0 };
//将PPS数据以16进制送进程序 uint8 Sps[]
= { 0x42, 0x01, 0x01 ,0x01 ,0x40 ,0x00 ,0x00 ,0x03 ,0x00, 0x00 ,0x03 ,0x00 ,0x00 ,0x03 ,0x00 ,0x00 ,0x03 ,0x00 ,0x5D ,0xA0 ,0x02 ,0x80 ,0x80 ,0x2E ,0x1F ,0x13 ,0x96 ,0xBB ,0x90 ,0x84 ,0x64 ,0xB8 ,0x9A ,0x80 ,0x00 ,0x02 ,0x82 ,0x00 ,0x00 ,0x03 ,0x00 ,0x02,0x00 ,0x00 ,0x03 ,0x00 ,0x28 ,0x10 ,0x24 ,0x00 ,0x00 ,0x13 ,0x80 ,0x60 ,0x00 ,0x02 ,0x8A ,0x0B ,0x96 ,0x2E ,0x00 ,0x00 ,0x00 ,0x02 }; ParseSequenceParameterSet(Sps, 64, params); printf("%d-%d-%d\n", params.width, params.height, params.level);
//我上边的数据得到的宽高是720P system(
"pause"); return 0; }

 --------------------------------

2 解析H264的SPS视频参数

#include <stdio.h>

	typedef struct
	{
		unsigned int profile_idc;
		unsigned int level_idc;

		unsigned int width;
		unsigned int height;
		unsigned int fps;       //SPS中可能不包含FPS信息。也可能包含错误的FPS
	} sps_info_struct;


	/**
	 解析SPS数据信息,主要是为了得到宽高信息

	 @param data SPS数据内容,需要Nal类型为0x7开始,不带起始码
	 @param dataSize SPS数据的长度
	 @param info SPS解析之后的信息数据结构体
	 @return success:1,fail:0
	 *------https://www.jianshu.com/p/304ba7e9db29----
	 */
	int h264_parse_sps(const unsigned char *data, unsigned int dataSize, sps_info_struct *info);

  

#include "头文件.h"
#include <string.h>
#include <stdlib.h>
#include <math.h>

typedef unsigned char BYTE;
typedef int INT;
typedef unsigned int UINT;

typedef struct
{
	const BYTE *data;   //sps数据
	UINT size;          //sps数据大小
	UINT index;         //当前计算位所在的位置标记
} sps_bit_stream;

/**
 移除H264的NAL防竞争码(0x03)
 @param data sps数据
 @param dataSize sps数据大小
 */
static void del_emulation_prevention(BYTE *data, UINT *dataSize)
{
	UINT dataSizeTemp = *dataSize;
	for (UINT i = 0, j = 0; i < (dataSizeTemp - 2); i++) {
		int val = (data[i] ^ 0x0) + (data[i + 1] ^ 0x0) + (data[i + 2] ^ 0x3);    //检测是否是竞争码
		if (val == 0) {
			for (j = i + 2; j < dataSizeTemp - 1; j++) {    //移除竞争码
				data[j] = data[j + 1];
			}

			(*dataSize)--;      //data size 减1
		}
	}
}

static void sps_bs_init(sps_bit_stream *bs, const BYTE *data, UINT size)
{
	if (bs) {
		bs->data = data;
		bs->size = size;
		bs->index = 0;
	}
}

/**
 是否已经到数据流最后

 @param bs sps_bit_stream数据
 @return 1:yes,0:no
 */
static INT eof(sps_bit_stream *bs)
{
	return (bs->index >= bs->size * 8);    //位偏移已经超出数据
}

/**
 读取从起始位开始的BitCount个位所表示的值

 @param bs sps_bit_stream数据
 @param bitCount bit位个数(从低到高)
 @return value
 */
static UINT u(sps_bit_stream *bs, BYTE bitCount)
{
	UINT val = 0;
	for (BYTE i = 0; i < bitCount; i++) {
		val <<= 1;
		if (eof(bs)) {
			val = 0;
			break;
		}
		else if (bs->data[bs->index /8 ] & (0x80 >> (bs->index % 8))) {     //计算index所在的位是否为1
			val |= 1;
		}
		bs->index++;  //递增当前起始位(表示该位已经被计算,在后面的计算过程中不需要再次去计算所在的起始位索引,缺点:后面每个bit位都需要去位移)
	}

	return val;
}

/**
 读取无符号哥伦布编码值(UE)
 #2^LeadingZeroBits - 1 + (xxx)
 @param bs sps_bit_stream数据
 @return value
 */
static UINT ue(sps_bit_stream *bs)
{
	UINT zeroNum = 0;
	while (u(bs, 1) == 0 && !eof(bs) && zeroNum < 32) {
		zeroNum++;
	}

	return (UINT)((1 << zeroNum) - 1 + u(bs, zeroNum));
}

/**
 读取有符号哥伦布编码值(SE)
 #(-1)^(k+1) * Ceil(k/2)

 @param bs sps_bit_stream数据
 @return value
 */
INT se(sps_bit_stream *bs)
{
	INT ueVal = (INT)ue(bs);
	double k = ueVal;

	INT seVal = (INT)ceil(k / 2);     //ceil:返回大于或者等于指定表达式的最小整数
	if (ueVal % 2 == 0) {       //偶数取反,即(-1)^(k+1)
		seVal = -seVal;
	}

	return seVal;
}

/**
 视频可用性信息(Video usability information)解析
 @param bs sps_bit_stream数据
 @param info sps解析之后的信息数据及结构体
 @see E.1.1 VUI parameters syntax
 */
void vui_para_parse(sps_bit_stream *bs, sps_info_struct *info)
{
	UINT aspect_ratio_info_present_flag = u(bs, 1);
	if (aspect_ratio_info_present_flag) {
		UINT aspect_ratio_idc = u(bs, 8);
		if (aspect_ratio_idc == 255) {      //Extended_SAR
			u(bs, 16);      //sar_width
			u(bs, 16);      //sar_height
		}
	}

	UINT overscan_info_present_flag = u(bs, 1);
	if (overscan_info_present_flag) {
		u(bs, 1);       //overscan_appropriate_flag
	}

	UINT video_signal_type_present_flag = u(bs, 1);
	if (video_signal_type_present_flag) {
		u(bs, 3);       //video_format
		u(bs, 1);       //video_full_range_flag
		UINT colour_description_present_flag = u(bs, 1);
		if (colour_description_present_flag) {
			u(bs, 8);       //colour_primaries
			u(bs, 8);       //transfer_characteristics
			u(bs, 8);       //matrix_coefficients
		}
	}

	UINT chroma_loc_info_present_flag = u(bs, 1);
	if (chroma_loc_info_present_flag) {
		ue(bs);     //chroma_sample_loc_type_top_field
		ue(bs);     //chroma_sample_loc_type_bottom_field
	}

	UINT timing_info_present_flag = u(bs, 1);
	if (timing_info_present_flag) {
		UINT num_units_in_tick = u(bs, 32);
		UINT time_scale = u(bs, 32);
		UINT fixed_frame_rate_flag = u(bs, 1);

		info->fps = (UINT)((float)time_scale / (float)num_units_in_tick);
		if (fixed_frame_rate_flag) {
			info->fps = info->fps / 2;
		}
	}

	UINT nal_hrd_parameters_present_flag = u(bs, 1);
	if (nal_hrd_parameters_present_flag) {
		//hrd_parameters()  //see E.1.2 HRD parameters syntax
	}

	//后面代码需要hrd_parameters()函数接口实现才有用
	UINT vcl_hrd_parameters_present_flag = u(bs, 1);
	if (vcl_hrd_parameters_present_flag) {
		//hrd_parameters()
	}
	if (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag) {
		u(bs, 1);   //low_delay_hrd_flag
	}

	u(bs, 1);       //pic_struct_present_flag
	UINT bitstream_restriction_flag = u(bs, 1);
	if (bitstream_restriction_flag) {
		u(bs, 1);   //motion_vectors_over_pic_boundaries_flag
		ue(bs);     //max_bytes_per_pic_denom
		ue(bs);     //max_bits_per_mb_denom
		ue(bs);     //log2_max_mv_length_horizontal
		ue(bs);     //log2_max_mv_length_vertical
		ue(bs);     //max_num_reorder_frames
		ue(bs);     //max_dec_frame_buffering
	}
}

//See 7.3.1 NAL unit syntax
//See 7.3.2.1.1 Sequence parameter set data syntax
int h264_parse_sps(const unsigned char * data, unsigned int dataSize, sps_info_struct * info)
{
	if (!data || dataSize <= 0 || !info) return 0;
	INT ret = 0;

	BYTE *dataBuf = malloc(dataSize);
	memcpy(dataBuf, data, dataSize);        //重新拷贝一份数据,防止移除竞争码时对原数据造成影响
	del_emulation_prevention(dataBuf, &dataSize);

	sps_bit_stream bs = { 0 };
	sps_bs_init(&bs, dataBuf, dataSize);   //初始化SPS数据流结构体

	u(&bs, 1);      //forbidden_zero_bit
	u(&bs, 2);      //nal_ref_idc
	UINT nal_unit_type = u(&bs, 5);

	if (nal_unit_type == 0x7) {     //Nal SPS Flag
		info->profile_idc = u(&bs, 8);
		u(&bs, 1);      //constraint_set0_flag
		u(&bs, 1);      //constraint_set1_flag
		u(&bs, 1);      //constraint_set2_flag
		u(&bs, 1);      //constraint_set3_flag
		u(&bs, 1);      //constraint_set4_flag
		u(&bs, 1);      //constraint_set4_flag
		u(&bs, 2);      //reserved_zero_2bits
		info->level_idc = u(&bs, 8);

		ue(&bs);    //seq_parameter_set_id

		UINT chroma_format_idc = 1;     //摄像机出图大部分格式是4:2:0
		if (info->profile_idc == 100 || info->profile_idc == 110 || info->profile_idc == 122 ||
			info->profile_idc == 244 || info->profile_idc == 44 || info->profile_idc == 83 ||
			info->profile_idc == 86 || info->profile_idc == 118 || info->profile_idc == 128 ||
			info->profile_idc == 138 || info->profile_idc == 139 || info->profile_idc == 134 || info->profile_idc == 135) {
			chroma_format_idc = ue(&bs);
			if (chroma_format_idc == 3) {
				u(&bs, 1);      //separate_colour_plane_flag
			}

			ue(&bs);        //bit_depth_luma_minus8
			ue(&bs);        //bit_depth_chroma_minus8
			u(&bs, 1);      //qpprime_y_zero_transform_bypass_flag
			UINT seq_scaling_matrix_present_flag = u(&bs, 1);
			if (seq_scaling_matrix_present_flag) {
				UINT seq_scaling_list_present_flag[8] = { 0 };
				for (INT i = 0; i < ((chroma_format_idc != 3) ? 8 : 12); i++) {
					seq_scaling_list_present_flag[i] = u(&bs, 1);
					if (seq_scaling_list_present_flag[i]) {
						if (i < 6) {    //scaling_list(ScalingList4x4[i], 16, UseDefaultScalingMatrix4x4Flag[i])
						}
						else {    //scaling_list(ScalingList8x8[i − 6], 64, UseDefaultScalingMatrix8x8Flag[i − 6] )
						}
					}
				}
			}
		}

		ue(&bs);        //log2_max_frame_num_minus4
		UINT pic_order_cnt_type = ue(&bs);
		if (pic_order_cnt_type == 0) {
			ue(&bs);        //log2_max_pic_order_cnt_lsb_minus4
		}
		else if (pic_order_cnt_type == 1) {
			u(&bs, 1);      //delta_pic_order_always_zero_flag
			se(&bs);        //offset_for_non_ref_pic
			se(&bs);        //offset_for_top_to_bottom_field

			UINT num_ref_frames_in_pic_order_cnt_cycle = ue(&bs);
			INT *offset_for_ref_frame = (INT *)malloc((UINT)num_ref_frames_in_pic_order_cnt_cycle * sizeof(INT));
			for (INT i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++) {
				offset_for_ref_frame[i] = se(&bs);
			}
			free(offset_for_ref_frame);
		}

		ue(&bs);      //max_num_ref_frames
		u(&bs, 1);      //gaps_in_frame_num_value_allowed_flag

		UINT pic_width_in_mbs_minus1 = ue(&bs);     //第36位开始
		UINT pic_height_in_map_units_minus1 = ue(&bs);      //47
		UINT frame_mbs_only_flag = u(&bs, 1);

		info->width = (INT)(pic_width_in_mbs_minus1 + 1) * 16;
		info->height = (INT)(2 - frame_mbs_only_flag) * (pic_height_in_map_units_minus1 + 1) * 16;

		if (!frame_mbs_only_flag) {
			u(&bs, 1);      //mb_adaptive_frame_field_flag
		}

		u(&bs, 1);     //direct_8x8_inference_flag
		UINT frame_cropping_flag = u(&bs, 1);
		if (frame_cropping_flag) {
			UINT frame_crop_left_offset = ue(&bs);
			UINT frame_crop_right_offset = ue(&bs);
			UINT frame_crop_top_offset = ue(&bs);
			UINT frame_crop_bottom_offset = ue(&bs);

			//See 6.2 Source, decoded, and output picture formats
			INT crop_unit_x = 1;
			INT crop_unit_y = 2 - frame_mbs_only_flag;      //monochrome or 4:4:4
			if (chroma_format_idc == 1) {   //4:2:0
				crop_unit_x = 2;
				crop_unit_y = 2 * (2 - frame_mbs_only_flag);
			}
			else if (chroma_format_idc == 2) {    //4:2:2
				crop_unit_x = 2;
				crop_unit_y = 2 - frame_mbs_only_flag;
			}

			info->width -= crop_unit_x * (frame_crop_left_offset + frame_crop_right_offset);
			info->height -= crop_unit_y * (frame_crop_top_offset + frame_crop_bottom_offset);
		}

		UINT vui_parameters_present_flag = u(&bs, 1);
		if (vui_parameters_present_flag) {
			vui_para_parse(&bs, info);
		}

		ret = 1;
	}
	free(dataBuf);

	return ret;
}

  

 

posted on 2023-04-07 11:02  邗影  阅读(358)  评论(0编辑  收藏  举报

导航