void get_profile(int profile_idc, char* profile_str)
{
switch (profile_idc) {
case 66:
strcpy(profile_str, "Baseline");
break;
case 77:
strcpy(profile_str, "Main");
break;
case 88:
strcpy(profile_str, "Extended");
break;
case 100:
strcpy(profile_str, "High(FRExt)");
break;
case 110:
strcpy(profile_str, "High10(FRExt)");
break;
case 122:
strcpy(profile_str, "High4:2:2(FRExt)");
break;
case 144:
strcpy(profile_str, "High4:4:4(FRExt)");
break;
default:
strcpy(profile_str, "Unknown");
}
}
unsigned int Ue(unsigned char* pBuff, unsigned int nLen, unsigned int* nStartBit)
{
unsigned int nZeroNum = 0;
while (*nStartBit < nLen * 8)
{
if (pBuff[*nStartBit / 8] & (0x80 >> (*nStartBit % 8)))
{
break;
}
nZeroNum++;
*nStartBit += 1;
}
*nStartBit += 1;
unsigned long dwRet = 0;
for (unsigned int i = 0; i < nZeroNum; i++)
{
dwRet <<= 1;
if (pBuff[*nStartBit / 8] & (0x80 >> (*nStartBit % 8)))
{
dwRet += 1;
}
*nStartBit += 1;
}
return (1 << nZeroNum) - 1 + dwRet;
}
int Se(unsigned char* pBuff, unsigned int nLen, unsigned int* nStartBit)
{
int UeVal = Ue(pBuff, nLen, nStartBit);
double k = UeVal;
int nValue = ceil(k / 2);
if (UeVal % 2 == 0)
nValue = -nValue;
return nValue;
}
unsigned long u(unsigned int BitCount, unsigned char* buf, unsigned int* nStartBit)
{
unsigned long dwRet = 0;
for (unsigned int i = 0; i < BitCount; i++)
{
dwRet <<= 1;
if (buf[*nStartBit / 8] & (0x80 >> (*nStartBit % 8)))
{
dwRet += 1;
}
*nStartBit += 1;
}
return dwRet;
}
void de_emulation_prevention(unsigned char* buf, unsigned int* buf_size)
{
unsigned char* ptr = NULL;
unsigned int tmp_buf_size = 0;
unsigned int i = 0, j = 0, val = 0;
ptr = buf;
tmp_buf_size = *buf_size;
for (i = 0; i < (tmp_buf_size - 2); i++)
{
//check for 0x000003
val = (ptr[i] ^ 0x00) + (ptr[i + 1] ^ 0x00) + (ptr[i + 2] ^ 0x03);
if (val == 0)
{
//kick out 0x03
for (j = i + 2; j < tmp_buf_size - 1; j++)
ptr[j] = ptr[j + 1];
//and so we should devrease bufsize
(*buf_size)--;
}
}
}
struct h265_sub_layer_t {
uint8_t sub_layer_profile_present_flag; // u(1)
uint8_t sub_layer_level_present_flag; // u(1)
uint8_t sub_layer_profile_space; // u(2)
uint8_t sub_layer_tier_flag; // u(1)
uint8_t sub_layer_profile_idc; // u(5)
uint32_t sub_layer_profile_compatibility_flag; // u(32)
uint64_t sub_layer_constraint_flags; // u(48)
uint8_t sub_layer_level_idc;// u(8)
};
struct h265_profile_tier_level_t {
uint8_t general_profile_space; // u(2)
uint8_t general_tier_flag; // u(1)
uint8_t general_profile_idc; // u(5)
uint32_t general_profile_compatibility_flag; // u(32)
uint64_t general_constraint_flags; // u(48)
uint8_t general_level_idc; // u(8)
struct h265_sub_layer_t sub_layer[64]; // maxNumSubLayersMinus1
};
int h265_profile_tier_level(struct h265_profile_tier_level_t* profile, int profilePresentFlag, int maxNumSubLayersMinus1, unsigned char* buf, unsigned int& StartBit)
{
int i;
if (profilePresentFlag){
profile->general_profile_idc = (uint8_t)u(2, buf, &StartBit);
profile->general_tier_flag = (uint8_t)u(1, buf, &StartBit);
profile->general_profile_idc = (uint8_t)u(5, buf, &StartBit);
profile->general_profile_compatibility_flag = u(32, buf, &StartBit);
profile->general_constraint_flags = (((uint64_t)u(32, buf, &StartBit)) << 16) | u(16, buf, &StartBit);
}
profile->general_level_idc = (uint8_t)u(8, buf, &StartBit);
for (i = 0; i < maxNumSubLayersMinus1; i++){
profile->sub_layer[i].sub_layer_profile_present_flag = (uint8_t)u(1, buf, &StartBit);
profile->sub_layer[i].sub_layer_level_present_flag = (uint8_t)u(1, buf, &StartBit);
}
// align to byte
if (maxNumSubLayersMinus1 > 0){
for (i = maxNumSubLayersMinus1; i < 8; i++)
u(2, buf, &StartBit); // reserved_zero_2bits
}
for (i = 0; i < maxNumSubLayersMinus1; i++){
if (profile->sub_layer[i].sub_layer_profile_present_flag){
profile->sub_layer[i].sub_layer_profile_space = (uint8_t)u(2, buf, &StartBit);
profile->sub_layer[i].sub_layer_tier_flag = (uint8_t)u(1, buf, &StartBit);
profile->sub_layer[i].sub_layer_profile_idc = (uint8_t)u(5, buf, &StartBit);
profile->sub_layer[i].sub_layer_profile_compatibility_flag = u(32, buf, &StartBit);
profile->sub_layer[i].sub_layer_constraint_flags = (((uint64_t)u(32, buf, &StartBit)) << 16) | u(16, buf, &StartBit);
}
if (profile->sub_layer[i].sub_layer_level_present_flag)
profile->sub_layer[i].sub_layer_level_idc = (uint8_t)u(8, buf, &StartBit);
}
return 0;
}
//return: 0/false 1/success
int h265_decode_sps(unsigned char* buf, unsigned int nLen, int* width, int* height, int* fps,int* general_level_idc)
{
unsigned int StartBit = 0;
de_emulation_prevention(buf, &nLen);
struct h265_profile_tier_level_t profile = { 0 };
//--- nal_uint_header ---
int forbidden_zero_bit = u(1, buf, &StartBit);
int nal_unit_type = u(6, buf, &StartBit);
if (nal_unit_type != 33)
return 0;
int nuh_layer_id = u(6, buf, &StartBit);
int nuh_temporal_id_plus = u(3, buf, &StartBit);
int sps_video_parameter_set_id = (uint8_t)u(4, buf, &StartBit);
int sps_max_sub_layers_minus1 = (uint8_t)u(3, buf, &StartBit);
int sps_temporal_id_nesting_flag = (uint8_t)u(1, buf, &StartBit);
h265_profile_tier_level(&profile, 1, sps_max_sub_layers_minus1, buf, StartBit);
int sps_seq_parameter_set_id = Ue(buf, nLen, &StartBit);
int chroma_format_id = (uint8_t)Ue(buf, nLen, &StartBit);
int separate_colour_plane_flag = 0;
if (3 == chroma_format_id)
separate_colour_plane_flag = (uint8_t)u(1, buf, &StartBit);
int pic_width_in_luma_samples = Ue(buf, nLen, &StartBit);
int pic_height_in_luma_samples = Ue(buf, nLen, &StartBit);
int conformance_window_flag = u(1, buf, &StartBit);
int conf_win_left_offset = 0;
int conf_win_right_offset = 0;
int conf_win_top_offset = 0;
int conf_win_bottom_offset = 0;
if (conformance_window_flag)
{
int conf_win_left_offset = Ue(buf, nLen, &StartBit);
int conf_win_right_offset = Ue(buf, nLen, &StartBit);
int conf_win_top_offset = Ue(buf, nLen, &StartBit);
int conf_win_bottom_offset = Ue(buf, nLen, &StartBit);
int sub_width_c = ((1 == chroma_format_id) || (2 == chroma_format_id)) && (0 == separate_colour_plane_flag) ? 2 : 1;
int sub_height_c = (1 == chroma_format_id) && (0 == separate_colour_plane_flag) ? 2 : 1;
*width = pic_width_in_luma_samples - (sub_width_c * conf_win_right_offset + sub_width_c * conf_win_left_offset);
*height = pic_height_in_luma_samples - (sub_height_c * conf_win_bottom_offset + sub_height_c * conf_win_top_offset);
}
else {
*width = pic_width_in_luma_samples;
*height = pic_height_in_luma_samples;
}
*fps = 0;
return 1;
}