Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1844393
  • 博文数量: 274
  • 博客积分: 2366
  • 博客等级: 大尉
  • 技术积分: 1880
  • 用 户 组: 普通用户
  • 注册时间: 2007-04-22 09:37
文章分类

全部博文(274)

文章存档

2022年(1)

2020年(10)

2019年(7)

2018年(18)

2017年(26)

2016年(32)

2015年(43)

2014年(30)

2013年(44)

2012年(36)

2011年(17)

2010年(10)

分类: 其他平台

2014-04-25 14:46:50

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


作者:Usher 发布于:2012-12-14 15:02 Friday 分类:技术杂记
    在使用ffmpeg解码播放TS流的时候(例如之前写过的UDP组播流),在连接时往往需要耗费大量时间。经过debug发现是av_find_stream_info(已抛弃,现在使用的是avformat_find_stream_info)这个方法十分耗时,而且是阻塞的。av_find_stream_info方法主要是获得相应的流信息,其中对我的应用最有用的就是视频的分辨率。在av_find_stream_info中是要不断的读取数据包,解码获得相应的信息,而其中除了分辨率信息以外的东西对我的应用中是无用的。所以,考虑自己手动从H.264码流中解析出视频的分辨率信息。
    以下内容主要参考了这篇文章:
       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。
 
      欢迎转载,转载请注明出处:
    以下是解析宽高的代码:



点击(此处)折叠或打开

  1. bool UDPReceiver::getResolution(int channel, int &Width, int& Height)
  2. {
  3.     BYTE *buf = new BYTE[1024];
  4.     int nLen;
  5.     AVPacket packet;
  6.     BOOL bSpsComplete = FALSE;
  7.     // Find SPS
  8.     while(!bSpsComplete)
  9.     {
  10.         int ret = av_read_frame(m_pFormatContext[channel], &packet);
  11.         if(packet.flags & AV_PKT_FLAG_KEY)
  12.         {
  13.             BYTE* p = packet.data;
  14.             BYTE last_nal_type = 0;
  15.             int last_nal_pos = 0;
  16.             for(int i=0; i<packet.size-5; i++)
  17.             {
  18.                 p = packet.data + i;
  19.                 if(p[0]==0x00&&p[1]==0x00&&p[2]==0x00&&p[3]==0x01)
  20.                 {
  21.                     if(last_nal_type == 0x67)
  22.                     {
  23.                         nLen = i-last_nal_pos;
  24.                         memcpy(buf, packet.data+last_nal_pos, nLen);
  25.                         bSpsComplete = TRUE;
  26.                     }
  27.                     last_nal_type = p[4];
  28.                     last_nal_pos = i;
  29.                     if(bSpsComplete)
  30.                     {
  31.                         break;
  32.                     }
  33.                 }
  34.             }
  35.             if (last_nal_type == 0x67 && bSpsComplete == FALSE)
  36.             {
  37.                 nLen = packet.size - last_nal_pos;
  38.                 memcpy(buf, packet.data+last_nal_pos, nLen);
  39.                 bSpsComplete = TRUE;
  40.             }
  41.         }
  42.     }
  43.     // Analyze SPS to find width and height
  44.     UINT StartBit=0;
  45.         buf = buf + 4;
  46.     int forbidden_zero_bit=u(1,buf,StartBit);
  47.     int nal_ref_idc=u(2,buf,StartBit);
  48.     int nal_unit_type=u(5,buf,StartBit);
  49.     if(nal_unit_type==7)
  50.     {
  51.         int profile_idc=u(8,buf,StartBit);
  52.         int constraint_set0_flag=u(1,buf,StartBit);//(buf[1] & 0x80)>>7;
  53.         int constraint_set1_flag=u(1,buf,StartBit);//(buf[1] & 0x40)>>6;
  54.         int constraint_set2_flag=u(1,buf,StartBit);//(buf[1] & 0x20)>>5;
  55.         int constraint_set3_flag=u(1,buf,StartBit);//(buf[1] & 0x10)>>4;
  56.         int reserved_zero_4bits=u(4,buf,StartBit);
  57.         int level_idc=u(8,buf,StartBit);

  58.         int seq_parameter_set_id=Ue(buf,nLen,StartBit);

  59.         if( profile_idc == 100 || profile_idc == 110 ||
  60.             profile_idc == 122 || profile_idc == 144 )
  61.         {
  62.             int chroma_format_idc=Ue(buf,nLen,StartBit);
  63.             if( chroma_format_idc == 3 )
  64.                 int residual_colour_transform_flag=u(1,buf,StartBit);
  65.             int bit_depth_luma_minus8=Ue(buf,nLen,StartBit);
  66.             int bit_depth_chroma_minus8=Ue(buf,nLen,StartBit);
  67.             int qpprime_y_zero_transform_bypass_flag=u(1,buf,StartBit);
  68.             int seq_scaling_matrix_present_flag=u(1,buf,StartBit);

  69.             int seq_scaling_list_present_flag[8];
  70.             if( seq_scaling_matrix_present_flag )
  71.             {
  72.                 for( int i = 0; i < 8; i++ ) {
  73.                     seq_scaling_list_present_flag[i]=u(1,buf,StartBit);
  74.                 }
  75.             }
  76.         }
  77.         int log2_max_frame_num_minus4=Ue(buf,nLen,StartBit);
  78.         int pic_order_cnt_type=Ue(buf,nLen,StartBit);
  79.         if( pic_order_cnt_type == 0 )
  80.             int log2_max_pic_order_cnt_lsb_minus4=Ue(buf,nLen,StartBit);
  81.         else if( pic_order_cnt_type == 1 )
  82.         {
  83.             int delta_pic_order_always_zero_flag=u(1,buf,StartBit);
  84.             int offset_for_non_ref_pic=Se(buf,nLen,StartBit);
  85.             int offset_for_top_to_bottom_field=Se(buf,nLen,StartBit);
  86.             int num_ref_frames_in_pic_order_cnt_cycle=Ue(buf,nLen,StartBit);

  87.             int *offset_for_ref_frame=new int[num_ref_frames_in_pic_order_cnt_cycle];
  88.             for( int i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ )
  89.                 offset_for_ref_frame[i]=Se(buf,nLen,StartBit);
  90.             delete [] offset_for_ref_frame;
  91.         }
  92.         int num_ref_frames=Ue(buf,nLen,StartBit);
  93.         int gaps_in_frame_num_value_allowed_flag=u(1,buf,StartBit);
  94.         int pic_width_in_mbs_minus1=Ue(buf,nLen,StartBit);
  95.         int pic_height_in_map_units_minus1=Ue(buf,nLen,StartBit);

  96.         Width=(pic_width_in_mbs_minus1+1)*16;
  97.         Height=(pic_height_in_map_units_minus1+1)*16;

  98.         return true;
  99.     }
  100.     else
  101.     {
  102.         return false;
  103.     }
  104. }

  105. // Ue find the num of zeros and get (num+1) bits from the first 1, and
  106. // change it to decimal
  107. // e.g. 00110 -> return 6(110)
  108. UINT UDPReceiver::Ue(BYTE *pBuff, UINT nLen, UINT &nStartBit)
  109. {
  110.     //计算0bit的个数
  111.     UINT nZeroNum = 0;
  112.     while (nStartBit < nLen * 8)
  113.     {
  114.         if (pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8))) //&:按位与,%取余
  115.         {
  116.             break;
  117.         }
  118.         nZeroNum++;
  119.         nStartBit++;
  120.     }
  121.     nStartBit ++;


  122.     //计算结果
  123.     DWORD dwRet = 0;
  124.     for (UINT i=0; i<nZeroNum; i++)
  125.     {
  126.         dwRet <<= 1;
  127.         if (pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8)))
  128.         {
  129.             dwRet += 1;
  130.         }
  131.         nStartBit++;
  132.     }
  133.     return (1 << nZeroNum) - 1 + dwRet;
  134. }

  135. int UDPReceiver::Se(BYTE *pBuff, UINT nLen, UINT &nStartBit)
  136. {
  137.     int UeVal=Ue(pBuff,nLen,nStartBit);
  138.     double k=UeVal;
  139.     int nValue=std::ceil(k/2);//ceil函数:ceil函数的作用是求不小于给定实数的最小整数。ceil(2)=ceil(1.2)=cei(1.5)=2.00
  140.     if (UeVal % 2==0)
  141.         nValue=-nValue;
  142.     return nValue;
  143. }

  144. // u Just returns the BitCount bits of buf and change it to decimal.
  145. // e.g. BitCount = 4, buf = 01011100, then return 5(0101)
  146. DWORD UDPReceiver::u(UINT BitCount,BYTE * buf,UINT &nStartBit)
  147. {
  148.     DWORD dwRet = 0;
  149.     for (UINT i=0; i<BitCount; i++)
  150.     {
  151.         dwRet <<= 1;
  152.         if (buf[nStartBit / 8] & (0x80 >> (nStartBit % 8)))
  153.         {
  154.             dwRet += 1;
  155.         }
  156.         nStartBit++;
  157.     }
  158.     return dwRet;
  159. }



阅读(3430) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~