分享

ffmpeg笔记——快速获得H.264视频分辨率的方法

 SamBookshelf 2013-12-27

    在使用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为开始码的(在我的应用中为后者),之后通过检测开始码后第一个字节的后五位是否为700111)来判断其是否为SPS。得到SPS之后,就可以解析出视频的分辨率。SPS中有两个成员,pic_width_in_mbs_minus1pic_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

    以下是解析宽高的代码:

001bool UDPReceiver::getResolution(int channel, int &Width, int& Height)
002{
003    BYTE *buf = new BYTE[1024];
004    int nLen;
005    AVPacket packet;
006    BOOL bSpsComplete = FALSE;
007    // Find SPS
008    while(!bSpsComplete)
009    {
010        int ret = av_read_frame(m_pFormatContext[channel], &packet);
011        if(packet.flags & AV_PKT_FLAG_KEY)
012        {
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++)
017            {
018                p = packet.data + i;
019                if(p[0]==0x00&&p[1]==0x00&&p[2]==0x00&&p[3]==0x01)
020                {
021                    if(last_nal_type == 0x67)
022                    {
023                        nLen = i-last_nal_pos;
024                        memcpy(buf, packet.data+last_nal_pos, nLen);
025                        bSpsComplete = TRUE;
026                    }
027                    last_nal_type = p[4];
028                    last_nal_pos = i;
029                    if(bSpsComplete)
030                    {
031                        break;
032                    }
033                }
034            }
035            if (last_nal_type == 0x67 && bSpsComplete == FALSE)
036            {
037                nLen = packet.size - last_nal_pos;
038                memcpy(buf, packet.data+last_nal_pos, nLen);
039                bSpsComplete = TRUE;
040            }
041        }
042    }
043    // Analyze SPS to find width and height
044    UINT StartBit=0;
045        buf = buf + 4;
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);
049    if(nal_unit_type==7)
050    {
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);
058 
059        int seq_parameter_set_id=Ue(buf,nLen,StartBit);
060 
061        if( profile_idc == 100 || profile_idc == 110 ||
062            profile_idc == 122 || profile_idc == 144 )
063        {
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);
071 
072            int seq_scaling_list_present_flag[8];
073            if( seq_scaling_matrix_present_flag )
074            {
075                for( int i = 0; i < 8; i++ ) {
076                    seq_scaling_list_present_flag[i]=u(1,buf,StartBit);
077                }
078            }
079        }
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 )
085        {
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);
090 
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;
095        }
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);
100 
101        Width=(pic_width_in_mbs_minus1+1)*16;
102        Height=(pic_height_in_map_units_minus1+1)*16;
103 
104        return true;
105    }
106    else
107    {
108        return false;
109    }
110}
111 
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)
115UINT UDPReceiver::Ue(BYTE *pBuff, UINT nLen, UINT &nStartBit)
116{
117    //计算0bit的个数
118    UINT nZeroNum = 0;
119    while (nStartBit < nLen * 8)
120    {
121        if (pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8))) //&:按位与,%取余
122        {
123            break;
124        }
125        nZeroNum++;
126        nStartBit++;
127    }
128    nStartBit ++;
129 
130 
131    //计算结果
132    DWORD dwRet = 0;
133    for (UINT i=0; i<nZeroNum; i++)
134    {
135        dwRet <<= 1;
136        if (pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8)))
137        {
138            dwRet += 1;
139        }
140        nStartBit++;
141    }
142    return (1 << nZeroNum) - 1 + dwRet;
143}
144 
145int UDPReceiver::Se(BYTE *pBuff, UINT nLen, UINT &nStartBit)
146{
147    int UeVal=Ue(pBuff,nLen,nStartBit);
148    double k=UeVal;
149    int nValue=std::ceil(k/2);//ceil函数:ceil函数的作用是求不小于给定实数的最小整数。ceil(2)=ceil(1.2)=cei(1.5)=2.00
150    if (UeVal % 2==0)
151        nValue=-nValue;
152    return nValue;
153}
154 
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)
157DWORD UDPReceiver::u(UINT BitCount,BYTE * buf,UINT &nStartBit)
158{
159    DWORD dwRet = 0;
160    for (UINT i=0; i<BitCount; i++)
161    {
162        dwRet <<= 1;
163        if (buf[nStartBit / 8] & (0x80 >> (nStartBit % 8)))
164        {
165            dwRet += 1;
166        }
167        nStartBit++;
168    }
169    return dwRet;
170}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多