解析 H.264 NAL Unit 帧类型

来源:互联网 发布:海岛大亨mac汉化补丁 编辑:程序博客网 时间:2024/05/29 08:02

解析 H.264 NAL Unit 帧类型的代码:


//////////////////////////////////////////////////////////////////////////// 功能: 从 Nal Unit 数据中获取帧类型// 读取字节结构体typedef struct bs_t_T{  unsigned char *pucStart;               // 缓冲区首地址  unsigned char *pucCurrent;             // 缓冲区当前的读写指针:当前字节的地址(这个会不断的 ++),每次 ++ 进入一个新的字节  unsigned char *pucEnd;                 // 缓冲区尾地址  int iLeft;                   // pucCurrent 所指字节当前还有多少"位" 可读写}bs_t;// nal 类型enum{  NAL_UNKNOWN     = 0,  NAL_SLICE       = 1,  NAL_SLICE_DPA   = 2,  NAL_SLICE_DPB   = 3,  NAL_SLICE_DPC   = 4,  NAL_SLICE_IDR   = 5,    /* ref_idc != 0 */  NAL_SEI         = 6,    /* ref_idc == 0 */  NAL_SPS         = 7,  NAL_PPS         = 8  /* ref_idc == 0 for 6,9,10,11,12 */};typedef enum NalFrameType_E{  NAL_FRAME_TYPE_NULL,  NAL_FRAME_TYPE_P,  NAL_FRAME_TYPE_B,  NAL_FRAME_TYPE_SP,  NAL_FRAME_TYPE_I,  NAL_FRAME_TYPE_SI,}NalFrameType;void bsInit(bs_t *s,void *pData,int iDataLen){  s->pucStart = (unsigned char *)pData;  s->pucCurrent = (unsigned char *)pData;  s->pucEnd = s->pucCurrent + iDataLen;  s->iLeft = 8;}int bsRead2(bs_t *s){  if(s->pucCurrent < s->pucEnd)   {    unsigned int uiResult;    s->iLeft--;    // 把要读的比特移到当前字节最右,然后与 0x01:00000001 进行逻辑与操作    // 因为要读的只是一个比特,这个比特不是 0 就是 1,所以与 0000 0001 按位与    uiResult = (*s->pucCurrent >> s->iLeft) & 0x01;    if(0 == s->iLeft)                // 如果当前字节剩余未读位数是0,即是说当前字节全读过了    {      s->pucCurrent++;             // 指针 s->p 移到下一字节      s->iLeft = 8;                // 新字节中,未读位数当然是 8 位    }    return uiResult;  }  return 0;}int bsRead(bs_t *s, int iCount){  static int iMaskArray[33] =  {    0x00,    0x01,      0x03,      0x07,      0x0f,    0x1f,      0x3f,      0x7f,      0xff,    0x1ff,     0x3ff,     0x7ff,     0xfff,    0x1fff,    0x3fff,    0x7fff,    0xffff,    0x1ffff,   0x3ffff,   0x7ffff,   0xfffff,    0x1fffff,  0x3fffff,  0x7fffff,  0xffffff,    0x1ffffff, 0x3ffffff, 0x7ffffff, 0xfffffff,    0x1fffffff,0x3fffffff,0x7fffffff,0xffffffff  };  /*        数组中的元素用二进制表示如下:        假设:初始为0,已写入为+,已读取为-                字节:   1   2   3   4           00000000 00000000 00000000 00000000    下标        0x00:               00000000    x[0]        0x01:               00000001    x[1]        0x03:               00000011    x[2]        0x07:               00000111    x[3]        0x0f:               00001111    x[4]        0x1f:               00011111    x[5]        0x3f:               00111111    x[6]        0x7f:               01111111    x[7]        0xff:               11111111    x[8]  1字节       0x1ff:            0001 11111111    x[9]       0x3ff:            0011 11111111    x[10] iMaskArray[s->iLeft]       0x7ff:            0111 11111111    x[11]       0xfff:            1111 11111111    x[12] 1.5字节      0x1fff:          00011111 11111111    x[13]      0x3fff:          00111111 11111111    x[14]      0x7fff:          01111111 11111111    x[15]      0xffff:          11111111 11111111    x[16] 2字节       0x1ffff:       0001 11111111 11111111    x[17]       0x3ffff:       0011 11111111 11111111    x[18]       0x7ffff:       0111 11111111 11111111    x[19]       0xfffff:       1111 11111111 11111111    x[20] 2.5字节      0x1fffff:     00011111 11111111 11111111    x[21]      0x3fffff:     00111111 11111111 11111111    x[22]      0x7fffff:     01111111 11111111 11111111    x[23]      0xffffff:     11111111 11111111 11111111    x[24] 3字节     0x1ffffff:    0001 11111111 11111111 11111111    x[25]     0x3ffffff:    0011 11111111 11111111 11111111    x[26]     0x7ffffff:    0111 11111111 11111111 11111111    x[27]     0xfffffff:    1111 11111111 11111111 11111111    x[28] 3.5字节    0x1fffffff:00011111 11111111 11111111 11111111    x[29]    0x3fffffff:00111111 11111111 11111111 11111111    x[30]    0x7fffffff:01111111 11111111 11111111 11111111    x[31]    0xffffffff:11111111 11111111 11111111 11111111    x[32] 4字节   */    int iShr;    int iResult = 0;        // 用来存放读取到的的结果    while(iCount > 0)       // 要读取的比特数    {        if(s->pucCurrent >= s->pucEnd)        {            break;        }        if((iShr = s->iLeft - iCount) >= 0)    // 当前字节剩余的未读位数,比要读取的位数多,或者相等        {            iResult |= (*s->pucCurrent >> iShr) & iMaskArray[iCount];      /* 读取后,更新结构体里的字段值 */            s->iLeft -= iCount;    // 当前字节剩余的未读位数            if(0 == s->iLeft)      // 当前字节读完了,就要开始下一个字节            {                s->pucCurrent++;   // 移动指针,所以 pucCurrent 好象是以字节为步长移动指针的                s->iLeft = 8;      // 当前字节剩余的未读位数,就是 8 比特            }            return iResult;        // 可能的返回值之一为: 00000000 00000000 00000000 00000001 (4字节长)        }        else  /* iShr < 0,跨字节的情况 */        {      iResult |= (*s->pucCurrent & iMaskArray[s->iLeft]) << -iShr;  // "-iShr" 相当于取了绝对值                                    // |= 和 << 都是位操作符,优先级相同,所以从左往右顺序执行                                    // iLeft 最大是 8,最小是 0,取值范围是 [0,8]      iCount -= s->iLeft;     // 待读取的比特数      s->pucCurrent++;        // 定位到下一个新的字节      s->iLeft = 8;           // 对一个新字节来说,未读过的位数当然是 8,即本字节所有位都没读取过        }    }    return iResult;                 // 可能的返回值之一为: 00000000 00000000 00000000 00000001 (4字节长)}int bsReadUE(bs_t *s){  int i = 0;  // 条件为: 读到的当前比特 =0,指针未越界,最多只能读 32 比特  while(0 == bsRead2(s) && s->pucCurrent < s->pucEnd && i < 32)  {    i++;  }  return ((1 << i) - 1 + bsRead(s, i));}/* * 功能: 从 Nal Unit 中获取帧类型 * 返回值: 帧类型*/int GetFrameType(NALUnit *nal){  bs_t s;  int iFrameType = 0;  NalFrameType FrameType = NAL_FRAME_TYPE_NULL;  ZeroMemory(&s,sizeof(bs_t));  bsInit(&s,nal->pcNaluBuf + 1, nal->uiLength - 1);  if(NAL_SLICE == nal->iNalUnitType || NAL_SLICE_IDR == nal->iNalUnitType)  {    /* i_first_mb */    bsReadUE(&s);    /* picture type */    iFrameType = bsReadUE(&s);    switch(iFrameType)    {    case 0:     case 5: /* P */      FrameType = NAL_FRAME_TYPE_P;      printf("当前帧是 P 帧!\n");      break;    case 1:     case 6: /* B */      FrameType = NAL_FRAME_TYPE_B;      printf("当前帧是 B 帧!\n");      break;    case 3:     case 8: /* SP */      FrameType = NAL_FRAME_TYPE_SP;      printf("当前帧是 SP 帧!\n");      break;    case 2:     case 7: /* I */      FrameType = NAL_FRAME_TYPE_I;      printf("当前帧是 I 帧!\n");      break;    case 4:     case 9: /* SI */      FrameType = NAL_FRAME_TYPE_SI;      printf("当前帧是 SI 帧!\n");      break;    default:      break;    }  }  return FrameType;}


原创粉丝点击