代碼已經過測試,能正确擷取寬高。
SPS資料是完整的,沒有去掉頭。如果要去掉,注意NAL_HEADER即可。測試時應該是:0, 0, 0, 1, 0x67, 0x42。。。
JAVA版
package net.quantum6.mediacodec;
import net.quantum6.kit.Log;
public class H264SpsParser
{
private final static String TAG = H264SpsParser.class.getCanonicalName();
private final static int NAL_HEADER = 4;
private static int nStartBit = 0;
private static int Ue(byte[] pBuff, int nLen)
{
int nZeroNum = 0;
while (nStartBit < nLen * 8)
{
if ((pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8))) != 0)
{
break;
}
nZeroNum++;
nStartBit++;
}
nStartBit ++;
int dwRet = 0;
for (int i=0; i<nZeroNum; i++)
{
dwRet <<= 1;
if ((pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8))) != 0)
{
dwRet += 1;
}
nStartBit++;
}
return (1 << nZeroNum) - 1 + dwRet;
}
private static int Se(byte[] pBuff, int nLen)
{
int UeVal =Ue(pBuff,nLen);
double k =UeVal;
int nValue=(int)Math.ceil(k/2);
if (UeVal % 2==0)
{
nValue=-nValue;
}
return nValue;
}
private static int u(int BitCount, byte[] buf)
{
int dwRet = 0;
for (int i=0; i<BitCount; i++)
{
dwRet <<= 1;
if ((buf[nStartBit / 8] & (0x80 >> (nStartBit % 8))) != 0)
{
dwRet += 1;
}
nStartBit++;
}
return dwRet;
}
private static boolean h264_decode_seq_parameter_set(byte[] buf, int nLen, int[] size)
{
nStartBit = NAL_HEADER*8;
int forbidden_zero_bit=u(1, buf);
int nal_ref_idc =u(2, buf);
int nal_unit_type =u(5, buf);
if(nal_unit_type==7)
{
int profile_idc =u(8, buf);
int constraint_set0_flag=u(1, buf);//(buf[1] & 0x80)>>7;
int constraint_set1_flag=u(1, buf);//(buf[1] & 0x40)>>6;
int constraint_set2_flag=u(1, buf);//(buf[1] & 0x20)>>5;
int constraint_set3_flag=u(1, buf);//(buf[1] & 0x10)>>4;
int reserved_zero_4bits =u(4, buf);
int level_idc =u(8, buf);
int seq_parameter_set_id=Ue(buf, nLen);
if ( profile_idc == 100 || profile_idc == 110 ||
profile_idc == 122 || profile_idc == 144 )
{
int chroma_format_idc=Ue(buf, nLen);
if ( chroma_format_idc == 3 )
{
int residual_colour_transform_flag=u(1,buf);
}
int bit_depth_luma_minus8 =Ue(buf, nLen);
int bit_depth_chroma_minus8 =Ue(buf, nLen);
int qpprime_y_zero_transform_bypass_flag=u(1, buf);
int seq_scaling_matrix_present_flag =u(1, buf);
int[] seq_scaling_list_present_flag = new int[8];
if ( seq_scaling_matrix_present_flag != 0)
{
for( int i = 0; i < 8; i++ )
{
seq_scaling_list_present_flag[i]=u(1, buf);
}
}
}
int log2_max_frame_num_minus4=Ue(buf, nLen);
int pic_order_cnt_type =Ue(buf, nLen);
if ( pic_order_cnt_type == 0 )
{
int log2_max_pic_order_cnt_lsb_minus4=Ue(buf, nLen);
}
else if( pic_order_cnt_type == 1 )
{
int delta_pic_order_always_zero_flag =u(1, buf);
int offset_for_non_ref_pic =Se(buf, nLen);
int offset_for_top_to_bottom_field =Se(buf, nLen);
int num_ref_frames_in_pic_order_cnt_cycle=Ue(buf, nLen);
int[] offset_for_ref_frame=new int[num_ref_frames_in_pic_order_cnt_cycle];
for( int i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ )
{
offset_for_ref_frame[i]=Se(buf, nLen);
}
}
int num_ref_frames =Ue(buf, nLen);
int gaps_in_frame_num_value_allowed_flag=u(1, buf);
int pic_width_in_mbs_minus1 =Ue(buf, nLen);
int pic_height_in_map_units_minus1 =Ue(buf, nLen);
size[0]=(pic_width_in_mbs_minus1 +1)*16;
size[1]=(pic_height_in_map_units_minus1+1)*16;
/*
int frame_mbs_only_flag=u(1,buf,StartBit);
if(!frame_mbs_only_flag)
int mb_adaptive_frame_field_flag=u(1,buf,StartBit);
int direct_8x8_inference_flag=u(1,buf,StartBit);
int frame_cropping_flag=u(1,buf,StartBit);
if(frame_cropping_flag)
{
int frame_crop_left_offset=Ue(buf,nLen,StartBit);
int frame_crop_right_offset=Ue(buf,nLen,StartBit);
int frame_crop_top_offset=Ue(buf,nLen,StartBit);
int frame_crop_bottom_offset=Ue(buf,nLen,StartBit);
}
int vui_parameter_present_flag=u(1,buf,StartBit);
if(vui_parameter_present_flag)
{
int aspect_ratio_info_present_flag=u(1,buf,StartBit);
if(aspect_ratio_info_present_flag)
{
int aspect_ratio_idc=u(8,buf,StartBit);
if(aspect_ratio_idc==255)
{
int sar_width=u(16,buf,StartBit);
int sar_height=u(16,buf,StartBit);
}
}
int overscan_info_present_flag=u(1,buf,StartBit);
if(overscan_info_present_flag)
int overscan_appropriate_flagu=u(1,buf,StartBit);
int video_signal_type_present_flag=u(1,buf,StartBit);
if(video_signal_type_present_flag)
{
int video_format=u(3,buf,StartBit);
int video_full_range_flag=u(1,buf,StartBit);
int colour_description_present_flag=u(1,buf,StartBit);
if(colour_description_present_flag)
{
int colour_primaries=u(8,buf,StartBit);
int transfer_characteristics=u(8,buf,StartBit);
int matrix_coefficients=u(8,buf,StartBit);
}
}
int chroma_loc_info_present_flag=u(1,buf,StartBit);
if(chroma_loc_info_present_flag)
{
int chroma_sample_loc_type_top_field=Ue(buf,nLen,StartBit);
int chroma_sample_loc_type_bottom_field=Ue(buf,nLen,StartBit);
}
int timing_info_present_flag=u(1,buf,StartBit);
if(timing_info_present_flag)
{
int num_units_in_tick=u(32,buf,StartBit);
int time_scale=u(32,buf,StartBit);
fps=time_scale/num_units_in_tick;
int fixed_frame_rate_flag=u(1,buf,StartBit);
if(fixed_frame_rate_flag)
{
fps=fps/2;
}
}
}
*/
return true;
}
return false;
}
public static int[] getSizeFromSps(byte[] data)
{
for (int i=0; i<data.length-4; i++)
{
if (data[i]==0 && data[i+1]==0 && data[i+2]==0 && data[i+3]==1 && data[i+4]==0x67)
{
int[] size = new int[2];
h264_decode_seq_parameter_set(data, data.length, size);
Log.d(TAG, "Sps=("+size[0]+", "+size[1]+")");
return size;
}
}
}
}
return null;
}
}
C版
JAVA代碼是從C改過來的。沒有運作。也許有小錯誤,各位參考JAVA再改。
#include <cstdint>
#include <cmath>
#define NAL_HEADEER 4
uint32_t Ue(uint8_t *pBuff, uint32_t nLen, uint32_t &nStartBit)
{
//計算0bit的個數
uint32_t nZeroNum = 0;
while (nStartBit < nLen * 8)
{
if (pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8))) //&:按位與,%取餘
{
break;
}
nZeroNum++;
nStartBit++;
}
nStartBit ++;
//計算結果
uint32_t dwRet = 0;
for (uint32_t i=0; i<nZeroNum; i++)
{
dwRet <<= 1;
if (pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8)))
{
dwRet += 1;
}
nStartBit++;
}
return (1 << nZeroNum) - 1 + dwRet;
}
int Se(uint8_t *pBuff, uint32_t nLen, uint32_t &nStartBit)
{
int UeVal=Ue(pBuff,nLen,nStartBit);
double k=UeVal;
int nValue=ceil(k/2);//ceil函數:ceil函數的作用是求不小于給定實數的最小整數。ceil(2)=ceil(1.2)=cei(1.5)=2.00
if (UeVal % 2==0)
{
nValue=-nValue;
}
return nValue;
}
uint32_t u(uint32_t BitCount, uint8_t * buf, uint32_t &nStartBit)
{
uint32_t dwRet = 0;
for (uint32_t i=0; i<BitCount; i++)
{
dwRet <<= 1;
if (buf[nStartBit / 8] & (0x80 >> (nStartBit % 8)))
{
dwRet += 1;
}
nStartBit++;
}
return dwRet;
}
bool h264_decode_seq_parameter_set(uint8_t * buf, uint32_t nLen ,int &Width, int &Height)
{
uint32_t StartBit=NAL_HEADEER*8;
int forbidden_zero_bit=u(1, buf, StartBit);
int nal_ref_idc =u(2, buf, StartBit);
int nal_unit_type =u(5, buf, StartBit);
if (nal_unit_type==7)
{
int profile_idc =u(8, buf, StartBit);
int constraint_set0_flag=u(1, buf, StartBit);//(buf[1] & 0x80)>>7;
int constraint_set1_flag=u(1, buf, StartBit);//(buf[1] & 0x40)>>6;
int constraint_set2_flag=u(1, buf, StartBit);//(buf[1] & 0x20)>>5;
int constraint_set3_flag=u(1, buf, StartBit);//(buf[1] & 0x10)>>4;
int reserved_zero_4bits =u(4, buf, StartBit);
int level_idc=u(8, buf, StartBit);
int seq_parameter_set_id=Ue(buf, nLen, StartBit);
if ( profile_idc == 100 || profile_idc == 110 ||
profile_idc == 122 || profile_idc == 144 )
{
int chroma_format_idc=Ue(buf, nLen, StartBit);
if ( chroma_format_idc == 3 )
{
int residual_colour_transform_flag =u(1, buf, StartBit);
}
int bit_depth_luma_minus8 =Ue(buf, nLen, StartBit);
int bit_depth_chroma_minus8 =Ue(buf, nLen, StartBit);
int qpprime_y_zero_transform_bypass_flag=u(1, buf, StartBit);
int seq_scaling_matrix_present_flag =u(1, buf, StartBit);
int seq_scaling_list_present_flag[8];
if ( seq_scaling_matrix_present_flag )
{
for ( int i = 0; i < 8; i++ )
{
seq_scaling_list_present_flag[i]=u(1, buf, StartBit);
}
}
}
int log2_max_frame_num_minus4=Ue(buf, nLen, StartBit);
int pic_order_cnt_type =Ue(buf, nLen, StartBit);
if ( pic_order_cnt_type == 0 )
{
int log2_max_pic_order_cnt_lsb_minus4=Ue(buf, nLen, StartBit);
}
else if ( pic_order_cnt_type == 1 )
{
int delta_pic_order_always_zero_flag =u(1, buf, StartBit);
int offset_for_non_ref_pic =Se(buf, nLen, StartBit);
int offset_for_top_to_bottom_field =Se(buf, nLen, StartBit);
int num_ref_frames_in_pic_order_cnt_cycle=Ue(buf, nLen, StartBit);
int *offset_for_ref_frame=new int[num_ref_frames_in_pic_order_cnt_cycle];
for ( int i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ )
{
offset_for_ref_frame[i]=Se(buf, nLen, StartBit);
}
delete [] offset_for_ref_frame;
}
int num_ref_frames=Ue(buf,nLen,StartBit);
int gaps_in_frame_num_value_allowed_flag=u(1, buf, StartBit);
int pic_width_in_mbs_minus1 =Ue(buf, nLen, StartBit);
int pic_height_in_map_units_minus1 =Ue(buf, nLen, StartBit);
Width =(pic_width_in_mbs_minus1 +1)*16;
Height=(pic_height_in_map_units_minus1+1)*16;
return true;
}
return false;
}
int main()
{
int Width, Height;
if (h264_decode_seq_parameter_set(str, 11, Width, Height))
{
}
return 0;
}