天天看點

H264 SPS中得到寬高的代碼(java/c),測試通過

  代碼已經過測試,能正确擷取寬高。

  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;
}