在使用ffmpeg解码播放TS流的时候(例如之前写过的UDP组播流),在连接时往往需要耗费大量时间。经过debug发现是av_find_stream_info(已抛弃,现在使用的是avformat_find_stream_info)这个方法十分耗时,而且是阻塞的。av_find_stream_info方法主要是获得相应的流信息,其中对我的应用最有用的就是视频的分辨率。在av_find_stream_info中是要不断的读取数据包,解码获得相应的信息,而其中除了分辨率信息以外的东西对我的应用中是无用的。所以,考虑自己手动从H.264码流中解析出视频的分辨率信息。
以下内容主要参考了这篇文章:http://www./internet/586390.html
H.264码流的流信息都存储在了特殊的结构中,叫做SPS(Sequence
Parameter Set)。要解析SPS就需要知道一些H.264码流的格式信息。
在H.264码流中,都是以0x00 0x00 0x01 或者 0x00 0x00 0x00 0x01为开始码的(在我的应用中为后者),之后通过检测开始码后第一个字节的后五位是否为7(00111)来判断其是否为SPS。得到SPS之后,就可以解析出视频的分辨率。SPS中有两个成员,pic_width_in_mbs_minus1和pic_height_in_map_units_minus_1,分别表示图像的宽和高,但是要注意的是它们都是以16为单位(在面积上就是以16*16的块为单位)再减1,所以实际的宽是(pic_width_in_mbs_minus1 + 1)*16,高为(pic_height_in_map_units_minus_1+1)*16。
欢迎转载,转载请注明出处:http:///Tech/34.html
以下是解析宽高的代码:
001 | bool UDPReceiver::getResolution( int channel, int &Width, int & Height) |
003 | BYTE *buf = new BYTE [1024]; |
006 | BOOL bSpsComplete = FALSE; |
010 | int ret = av_read_frame(m_pFormatContext[channel], &packet); |
011 | if (packet.flags & AV_PKT_FLAG_KEY) |
013 | BYTE * p = packet.data; |
014 | BYTE last_nal_type = 0; |
015 | int last_nal_pos = 0; |
016 | for ( int i=0; i<packet.size-5; i++) |
019 | if (p[0]==0x00&&p[1]==0x00&&p[2]==0x00&&p[3]==0x01) |
021 | if (last_nal_type == 0x67) |
023 | nLen = i-last_nal_pos; |
024 | memcpy (buf, packet.data+last_nal_pos, nLen); |
027 | last_nal_type = p[4]; |
035 | if (last_nal_type == 0x67 && bSpsComplete == FALSE) |
037 | nLen = packet.size - last_nal_pos; |
038 | memcpy (buf, packet.data+last_nal_pos, nLen); |
043 | // Analyze SPS to find width and height |
046 | int forbidden_zero_bit=u(1,buf,StartBit); |
047 | int nal_ref_idc=u(2,buf,StartBit); |
048 | int nal_unit_type=u(5,buf,StartBit); |
051 | int profile_idc=u(8,buf,StartBit); |
052 | int constraint_set0_flag=u(1,buf,StartBit); //(buf[1] & 0x80)>>7; |
053 | int constraint_set1_flag=u(1,buf,StartBit); //(buf[1] & 0x40)>>6; |
054 | int constraint_set2_flag=u(1,buf,StartBit); //(buf[1] & 0x20)>>5; |
055 | int constraint_set3_flag=u(1,buf,StartBit); //(buf[1] & 0x10)>>4; |
056 | int reserved_zero_4bits=u(4,buf,StartBit); |
057 | int level_idc=u(8,buf,StartBit); |
059 | int seq_parameter_set_id=Ue(buf,nLen,StartBit); |
061 | if ( profile_idc == 100 || profile_idc == 110 || |
062 | profile_idc == 122 || profile_idc == 144 ) |
064 | int chroma_format_idc=Ue(buf,nLen,StartBit); |
065 | if ( chroma_format_idc == 3 ) |
066 | int residual_colour_transform_flag=u(1,buf,StartBit); |
067 | int bit_depth_luma_minus8=Ue(buf,nLen,StartBit); |
068 | int bit_depth_chroma_minus8=Ue(buf,nLen,StartBit); |
069 | int qpprime_y_zero_transform_bypass_flag=u(1,buf,StartBit); |
070 | int seq_scaling_matrix_present_flag=u(1,buf,StartBit); |
072 | int seq_scaling_list_present_flag[8]; |
073 | if ( seq_scaling_matrix_present_flag ) |
075 | for ( int i = 0; i < 8; i++ ) { |
076 | seq_scaling_list_present_flag[i]=u(1,buf,StartBit); |
080 | int log2_max_frame_num_minus4=Ue(buf,nLen,StartBit); |
081 | int pic_order_cnt_type=Ue(buf,nLen,StartBit); |
082 | if ( pic_order_cnt_type == 0 ) |
083 | int log2_max_pic_order_cnt_lsb_minus4=Ue(buf,nLen,StartBit); |
084 | else if ( pic_order_cnt_type == 1 ) |
086 | int delta_pic_order_always_zero_flag=u(1,buf,StartBit); |
087 | int offset_for_non_ref_pic=Se(buf,nLen,StartBit); |
088 | int offset_for_top_to_bottom_field=Se(buf,nLen,StartBit); |
089 | int num_ref_frames_in_pic_order_cnt_cycle=Ue(buf,nLen,StartBit); |
091 | int *offset_for_ref_frame= new int [num_ref_frames_in_pic_order_cnt_cycle]; |
092 | for ( int i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ ) |
093 | offset_for_ref_frame[i]=Se(buf,nLen,StartBit); |
094 | delete [] offset_for_ref_frame; |
096 | int num_ref_frames=Ue(buf,nLen,StartBit); |
097 | int gaps_in_frame_num_value_allowed_flag=u(1,buf,StartBit); |
098 | int pic_width_in_mbs_minus1=Ue(buf,nLen,StartBit); |
099 | int pic_height_in_map_units_minus1=Ue(buf,nLen,StartBit); |
101 | Width=(pic_width_in_mbs_minus1+1)*16; |
102 | Height=(pic_height_in_map_units_minus1+1)*16; |
112 | // Ue find the num of zeros and get (num+1) bits from the first 1, and |
113 | // change it to decimal |
114 | // e.g. 00110 -> return 6(110) |
115 | UINT UDPReceiver::Ue( BYTE *pBuff, UINT nLen, UINT &nStartBit) |
119 | while (nStartBit < nLen * 8) |
121 | if (pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8))) //&:按位与,%取余 |
133 | for ( UINT i=0; i<nZeroNum; i++) |
136 | if (pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8))) |
142 | return (1 << nZeroNum) - 1 + dwRet; |
145 | int UDPReceiver::Se( BYTE *pBuff, UINT nLen, UINT &nStartBit) |
147 | int UeVal=Ue(pBuff,nLen,nStartBit); |
149 | int nValue=std:: ceil (k/2); //ceil函数:ceil函数的作用是求不小于给定实数的最小整数。ceil(2)=ceil(1.2)=cei(1.5)=2.00 |
155 | // u Just returns the BitCount bits of buf and change it to decimal. |
156 | // e.g. BitCount = 4, buf = 01011100, then return 5(0101) |
157 | DWORD UDPReceiver::u( UINT BitCount, BYTE * buf, UINT &nStartBit) |
160 | for ( UINT i=0; i<BitCount; i++) |
163 | if (buf[nStartBit / 8] & (0x80 >> (nStartBit % 8))) |
|