• 解析 H.264 NAL Unit 帧类型


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

      1 //////////////////////////////////////////////////////////////////////////  
      2 // 功能: 从 Nal Unit 数据中获取帧类型  
      3 // 读取字节结构体  
      4 typedef struct bs_t_T  
      5 {  
      6   unsigned char *pucStart;               // 缓冲区首地址  
      7   unsigned char *pucCurrent;             // 缓冲区当前的读写指针:当前字节的地址(这个会不断的 ++),每次 ++ 进入一个新的字节  
      8   unsigned char *pucEnd;                 // 缓冲区尾地址  
      9   int iLeft;                   // pucCurrent 所指字节当前还有多少"位" 可读写  
     10 }bs_t;  
     11 // nal 类型  
     12 enum  
     13 {  
     14   NAL_UNKNOWN     = 0,  
     15   NAL_SLICE       = 1,  
     16   NAL_SLICE_DPA   = 2,  
     17   NAL_SLICE_DPB   = 3,  
     18   NAL_SLICE_DPC   = 4,  
     19   NAL_SLICE_IDR   = 5,    /* ref_idc != 0 */  
     20   NAL_SEI         = 6,    /* ref_idc == 0 */  
     21   NAL_SPS         = 7,  
     22   NAL_PPS         = 8  
     23   /* ref_idc == 0 for 6,9,10,11,12 */  
     24 };  
     25 typedef enum NalFrameType_E  
     26 {  
     27   NAL_FRAME_TYPE_NULL,  
     28   NAL_FRAME_TYPE_P,  
     29   NAL_FRAME_TYPE_B,  
     30   NAL_FRAME_TYPE_SP,  
     31   NAL_FRAME_TYPE_I,  
     32   NAL_FRAME_TYPE_SI,  
     33 }NalFrameType;  
     34 void bsInit(bs_t *s,void *pData,int iDataLen)  
     35 {  
     36   s->pucStart = (unsigned char *)pData;  
     37   s->pucCurrent = (unsigned char *)pData;  
     38   s->pucEnd = s->pucCurrent + iDataLen;  
     39   s->iLeft = 8;  
     40 }  
     41 int bsRead2(bs_t *s)  
     42 {  
     43   if(s->pucCurrent < s->pucEnd)   
     44   {  
     45     unsigned int uiResult;  
     46     s->iLeft--;  
     47     // 把要读的比特移到当前字节最右,然后与 0x01:00000001 进行逻辑与操作  
     48     // 因为要读的只是一个比特,这个比特不是 0 就是 1,所以与 0000 0001 按位与  
     49     uiResult = (*s->pucCurrent >> s->iLeft) & 0x01;  
     50     if(0 == s->iLeft)                // 如果当前字节剩余未读位数是0,即是说当前字节全读过了  
     51     {  
     52       s->pucCurrent++;             // 指针 s->p 移到下一字节  
     53       s->iLeft = 8;                // 新字节中,未读位数当然是 8 位  
     54     }  
     55     return uiResult;  
     56   }  
     57   return 0;  
     58 }  
     59 int bsRead(bs_t *s, int iCount)  
     60 {  
     61   static int iMaskArray[33] =  
     62   {  
     63     0x00,  
     64     0x01,      0x03,      0x07,      0x0f,  
     65     0x1f,      0x3f,      0x7f,      0xff,  
     66     0x1ff,     0x3ff,     0x7ff,     0xfff,  
     67     0x1fff,    0x3fff,    0x7fff,    0xffff,  
     68     0x1ffff,   0x3ffff,   0x7ffff,   0xfffff,  
     69     0x1fffff,  0x3fffff,  0x7fffff,  0xffffff,  
     70     0x1ffffff, 0x3ffffff, 0x7ffffff, 0xfffffff,  
     71     0x1fffffff,0x3fffffff,0x7fffffff,0xffffffff  
     72   };  
     73   /*  
     74         数组中的元素用二进制表示如下:  
     75         假设:初始为0,已写入为+,已读取为-  
     76           
     77         字节:   1   2   3   4  
     78            00000000 00000000 00000000 00000000    下标  
     79         0x00:               00000000    x[0]  
     80         0x01:               00000001    x[1]  
     81         0x03:               00000011    x[2]  
     82         0x07:               00000111    x[3]  
     83         0x0f:               00001111    x[4]  
     84         0x1f:               00011111    x[5]  
     85         0x3f:               00111111    x[6]  
     86         0x7f:               01111111    x[7]  
     87         0xff:               11111111    x[8]  1字节  
     88        0x1ff:            0001 11111111    x[9]  
     89        0x3ff:            0011 11111111    x[10] iMaskArray[s->iLeft]  
     90        0x7ff:            0111 11111111    x[11]  
     91        0xfff:            1111 11111111    x[12] 1.5字节  
     92       0x1fff:          00011111 11111111    x[13]  
     93       0x3fff:          00111111 11111111    x[14]  
     94       0x7fff:          01111111 11111111    x[15]  
     95       0xffff:          11111111 11111111    x[16] 2字节  
     96        0x1ffff:       0001 11111111 11111111    x[17]  
     97        0x3ffff:       0011 11111111 11111111    x[18]  
     98        0x7ffff:       0111 11111111 11111111    x[19]  
     99        0xfffff:       1111 11111111 11111111    x[20] 2.5字节  
    100       0x1fffff:     00011111 11111111 11111111    x[21]  
    101       0x3fffff:     00111111 11111111 11111111    x[22]  
    102       0x7fffff:     01111111 11111111 11111111    x[23]  
    103       0xffffff:     11111111 11111111 11111111    x[24] 3字节  
    104      0x1ffffff:    0001 11111111 11111111 11111111    x[25]  
    105      0x3ffffff:    0011 11111111 11111111 11111111    x[26]  
    106      0x7ffffff:    0111 11111111 11111111 11111111    x[27]  
    107      0xfffffff:    1111 11111111 11111111 11111111    x[28] 3.5字节  
    108     0x1fffffff:00011111 11111111 11111111 11111111    x[29]  
    109     0x3fffffff:00111111 11111111 11111111 11111111    x[30]  
    110     0x7fffffff:01111111 11111111 11111111 11111111    x[31]  
    111     0xffffffff:11111111 11111111 11111111 11111111    x[32] 4字节  
    112    */  
    113     int iShr;  
    114     int iResult = 0;        // 用来存放读取到的的结果  
    115     while(iCount > 0)       // 要读取的比特数  
    116     {  
    117         if(s->pucCurrent >= s->pucEnd)  
    118         {  
    119             break;  
    120         }  
    121         if((iShr = s->iLeft - iCount) >= 0)    // 当前字节剩余的未读位数,比要读取的位数多,或者相等  
    122         {  
    123             iResult |= (*s->pucCurrent >> iShr) & iMaskArray[iCount];  
    124       /* 读取后,更新结构体里的字段值 */  
    125             s->iLeft -= iCount;    // 当前字节剩余的未读位数  
    126             if(0 == s->iLeft)      // 当前字节读完了,就要开始下一个字节  
    127             {  
    128                 s->pucCurrent++;   // 移动指针,所以 pucCurrent 好象是以字节为步长移动指针的  
    129                 s->iLeft = 8;      // 当前字节剩余的未读位数,就是 8 比特  
    130             }  
    131             return iResult;        // 可能的返回值之一为: 00000000 00000000 00000000 00000001 (4字节长)  
    132         }  
    133         else  /* iShr < 0,跨字节的情况 */  
    134         {  
    135       iResult |= (*s->pucCurrent & iMaskArray[s->iLeft]) << -iShr;  // "-iShr" 相当于取了绝对值  
    136                                     // |= 和 << 都是位操作符,优先级相同,所以从左往右顺序执行  
    137                                     // iLeft 最大是 8,最小是 0,取值范围是 [0,8]  
    138       iCount -= s->iLeft;     // 待读取的比特数  
    139       s->pucCurrent++;        // 定位到下一个新的字节  
    140       s->iLeft = 8;           // 对一个新字节来说,未读过的位数当然是 8,即本字节所有位都没读取过  
    141         }  
    142     }  
    143     return iResult;                 // 可能的返回值之一为: 00000000 00000000 00000000 00000001 (4字节长)  
    144 }  
    145 int bsReadUE(bs_t *s)  
    146 {  
    147   int i = 0;  
    148   // 条件为: 读到的当前比特 =0,指针未越界,最多只能读 32 比特  
    149   while(0 == bsRead2(s) && s->pucCurrent < s->pucEnd && i < 32)  
    150   {  
    151     i++;  
    152   }  
    153   return ((1 << i) - 1 + bsRead(s, i));  
    154 }  
    155 /*  
    156  * 功能: 从 Nal Unit 中获取帧类型  
    157  * 返回值: 帧类型  
    158 */  
    159 int GetFrameType(NALUnit *nal)  
    160 {  
    161   bs_t s;  
    162   int iFrameType = 0;  
    163   NalFrameType FrameType = NAL_FRAME_TYPE_NULL;  
    164   ZeroMemory(&s,sizeof(bs_t));  
    165   bsInit(&s,nal->pcNaluBuf + 1, nal->uiLength - 1);  
    166   if(NAL_SLICE == nal->iNalUnitType || NAL_SLICE_IDR == nal->iNalUnitType)  
    167   {  
    168     /* i_first_mb */  
    169     bsReadUE(&s);  
    170     /* picture type */  
    171     iFrameType = bsReadUE(&s);  
    172     switch(iFrameType)  
    173     {  
    174     case 0:   
    175     case 5: /* P */  
    176       FrameType = NAL_FRAME_TYPE_P;  
    177       printf("当前帧是 P 帧!
    ");  
    178       break;  
    179     case 1:   
    180     case 6: /* B */  
    181       FrameType = NAL_FRAME_TYPE_B;  
    182       printf("当前帧是 B 帧!
    ");  
    183       break;  
    184     case 3:   
    185     case 8: /* SP */  
    186       FrameType = NAL_FRAME_TYPE_SP;  
    187       printf("当前帧是 SP 帧!
    ");  
    188       break;  
    189     case 2:   
    190     case 7: /* I */  
    191       FrameType = NAL_FRAME_TYPE_I;  
    192       printf("当前帧是 I 帧!
    ");  
    193       break;  
    194     case 4:   
    195     case 9: /* SI */  
    196       FrameType = NAL_FRAME_TYPE_SI;  
    197       printf("当前帧是 SI 帧!
    ");  
    198       break;  
    199     default:  
    200       break;  
    201     }  
    202   }  
    203   return FrameType;  
    204 }  
  • 相关阅读:
    oracle中的游标
    Oracle中的表空间
    Oracle中建表及表操作
    oracle中的权限管理
    oracle中的数据类型
    Oracle中常用的系统函数
    oracle中的dual表简介
    Oracle中常用的系统表
    Git常用命令总结
    Git配置文件与git config命令
  • 原文地址:https://www.cnblogs.com/91program/p/5206036.html
Copyright © 2020-2023  润新知