• 嵌入式 H264视频通过RTMP直播


    前面的文章中提到了通过RTSP(Real Time Streaming Protocol)的方式来实现视频的直播,但RTSP方式的一个弊端是如果需要支持客户端通过网页来访问,就需要在在页面中嵌入一个ActiveX控件,而ActiveX一般都需要签名才能正常使用,否则用户在使用时还需要更改浏览器设置,并且ActiveX还只支持IE内核的浏览器,Chrome、FireFox需要IE插件才能运行,因此会特别影响用户体验。而RTMP(Real Time Messaging Protocol)很好的解决了这一个问题。由于RTMP是针对FLASH的流媒体协议,视频通过RTMP直播后,只需要在WEB上嵌入一个Web Player(如Jwplayer)即可观看,而且对平台也没什么限制,还可以方便的通过手机观看。

           视频通过RTMP方式发布需要一个RTMP Server(常见的有FMS、Wowza Media Server, 开源的有CRtmpServer、Red5等),原始视频只要按照RTMP协议发送给RTMP Server就可以RTMP视频流的发布了。为了便于视频的打包发布,封装了一个RTMPStream,目前只支持发送H264的视频文件。可以直接发送H264数据帧或H264文件,RTMPStream提供的接口如下。

    [cpp] view plaincopy
     
     
    1. class CRTMPStream    
    2. {    
    3. public:    
    4.     CRTMPStream(void);    
    5.     ~CRTMPStream(void);    
    6. public:    
    7.     // 连接到RTMP Server    
    8.     bool Connect(const char* url);    
    9.     // 断开连接    
    10.     void Close();    
    11.     // 发送MetaData    
    12.     bool SendMetadata(LPRTMPMetadata lpMetaData);    
    13.     // 发送H264数据帧    
    14.     bool SendH264Packet(unsigned char *data,unsigned int size,bool bIsKeyFrame,unsigned int nTimeStamp);    
    15.     // 发送H264文件    
    16.     bool SendH264File(const char *pFileName);    
    17. //...    
    18. }    
    调用示例:
    [cpp] view plaincopy
     
     
    1. #include <stdio.h>    
    2. #include "RTMPStreamRTMPStream.h"    
    3.     
    4. int main(int argc,char* argv[])    
    5. {    
    6.     CRTMPStream rtmpSender;    
    7.     
    8.     bool bRet = rtmpSender.Connect("rtmp://192.168.1.104/live/test");    
    9.     
    10.     rtmpSender.SendH264File("E:\video\test.264");    
    11.     
    12.     rtmpSender.Close();    
    13. }    

    通过JwPlayer播放效果如下:

    最后附上RTMPStream完整的代码:

    [cpp] view plaincopy
     
     
    1. /********************************************************************  
    2. filename:   RTMPStream.h 
    3. created:    2013-04-3 
    4. author:     firehood  
    5. purpose:    发送H264视频到RTMP Server,使用libRtmp库 
    6. *********************************************************************/   
    7. #pragma once  
    8. #include "rtmp.h"  
    9. #include "rtmp_sys.h"  
    10. #include "amf.h"  
    11. #include <stdio.h>  
    12.   
    13. #define FILEBUFSIZE (1024 * 1024 * 10)       //  10M  
    14.   
    15. // NALU单元  
    16. typedef struct _NaluUnit  
    17. {  
    18.     int type;  
    19.     int size;  
    20.     unsigned char *data;  
    21. }NaluUnit;  
    22.   
    23. typedef struct _RTMPMetadata  
    24. {  
    25.     // video, must be h264 type  
    26.     unsigned int    nWidth;  
    27.     unsigned int    nHeight;  
    28.     unsigned int    nFrameRate;     // fps  
    29.     unsigned int    nVideoDataRate; // bps  
    30.     unsigned int    nSpsLen;  
    31.     unsigned char   Sps[1024];  
    32.     unsigned int    nPpsLen;  
    33.     unsigned char   Pps[1024];  
    34.   
    35.     // audio, must be aac type  
    36.     bool            bHasAudio;  
    37.     unsigned int    nAudioSampleRate;  
    38.     unsigned int    nAudioSampleSize;  
    39.     unsigned int    nAudioChannels;  
    40.     char            pAudioSpecCfg;  
    41.     unsigned int    nAudioSpecCfgLen;  
    42.   
    43. } RTMPMetadata,*LPRTMPMetadata;  
    44.   
    45.   
    46. class CRTMPStream  
    47. {  
    48. public:  
    49.     CRTMPStream(void);  
    50.     ~CRTMPStream(void);  
    51. public:  
    52.     // 连接到RTMP Server  
    53.     bool Connect(const char* url);  
    54.     // 断开连接  
    55.     void Close();  
    56.     // 发送MetaData  
    57.     bool SendMetadata(LPRTMPMetadata lpMetaData);  
    58.     // 发送H264数据帧  
    59.     bool SendH264Packet(unsigned char *data,unsigned int size,bool bIsKeyFrame,unsigned int nTimeStamp);  
    60.     // 发送H264文件  
    61.     bool SendH264File(const char *pFileName);  
    62. private:  
    63.     // 送缓存中读取一个NALU包  
    64.     bool ReadOneNaluFromBuf(NaluUnit &nalu);  
    65.     // 发送数据  
    66.     int SendPacket(unsigned int nPacketType,unsigned char *data,unsigned int size,unsigned int nTimestamp);  
    67. private:  
    68.     RTMP* m_pRtmp;  
    69.     unsigned char* m_pFileBuf;  
    70.     unsigned int  m_nFileBufSize;  
    71.     unsigned int  m_nCurPos;  
    72. };  

    [cpp] view plaincopy
     
     
    1. /********************************************************************  
    2. filename:   RTMPStream.cpp 
    3. created:    2013-04-3 
    4. author:     firehood  
    5. purpose:    发送H264视频到RTMP Server,使用libRtmp库 
    6. *********************************************************************/   
    7. #include "RTMPStream.h"  
    8. #include "SpsDecode.h"  
    9. #ifdef WIN32    
    10. #include <windows.h>  
    11. #endif  
    12.   
    13. #ifdef WIN32  
    14. #pragma comment(lib,"WS2_32.lib")  
    15. #pragma comment(lib,"winmm.lib")  
    16. #endif  
    17.   
    18. enum  
    19. {  
    20.     FLV_CODECID_H264 = 7,  
    21. };  
    22.   
    23. int InitSockets()    
    24. {    
    25. #ifdef WIN32    
    26.     WORD version;    
    27.     WSADATA wsaData;    
    28.     version = MAKEWORD(1, 1);    
    29.     return (WSAStartup(version, &wsaData) == 0);    
    30. #else    
    31.     return TRUE;    
    32. #endif    
    33. }    
    34.   
    35. inline void CleanupSockets()    
    36. {    
    37. #ifdef WIN32    
    38.     WSACleanup();    
    39. #endif    
    40. }    
    41.   
    42. char * put_byte( char *output, uint8_t nVal )    
    43. {    
    44.     output[0] = nVal;    
    45.     return output+1;    
    46. }    
    47. char * put_be16(char *output, uint16_t nVal )    
    48. {    
    49.     output[1] = nVal & 0xff;    
    50.     output[0] = nVal >> 8;    
    51.     return output+2;    
    52. }    
    53. char * put_be24(char *output,uint32_t nVal )    
    54. {    
    55.     output[2] = nVal & 0xff;    
    56.     output[1] = nVal >> 8;    
    57.     output[0] = nVal >> 16;    
    58.     return output+3;    
    59. }    
    60. char * put_be32(char *output, uint32_t nVal )    
    61. {    
    62.     output[3] = nVal & 0xff;    
    63.     output[2] = nVal >> 8;    
    64.     output[1] = nVal >> 16;    
    65.     output[0] = nVal >> 24;    
    66.     return output+4;    
    67. }    
    68. char *  put_be64( char *output, uint64_t nVal )    
    69. {    
    70.     output=put_be32( output, nVal >> 32 );    
    71.     output=put_be32( output, nVal );    
    72.     return output;    
    73. }    
    74. char * put_amf_string( char *c, const char *str )    
    75. {    
    76.     uint16_t len = strlen( str );    
    77.     c=put_be16( c, len );    
    78.     memcpy(c,str,len);    
    79.     return c+len;    
    80. }    
    81. char * put_amf_double( char *c, double d )    
    82. {    
    83.     *c++ = AMF_NUMBER;  /* type: Number */    
    84.     {    
    85.         unsigned char *ci, *co;    
    86.         ci = (unsigned char *)&d;    
    87.         co = (unsigned char *)c;    
    88.         co[0] = ci[7];    
    89.         co[1] = ci[6];    
    90.         co[2] = ci[5];    
    91.         co[3] = ci[4];    
    92.         co[4] = ci[3];    
    93.         co[5] = ci[2];    
    94.         co[6] = ci[1];    
    95.         co[7] = ci[0];    
    96.     }    
    97.     return c+8;    
    98. }  
    99.   
    100. CRTMPStream::CRTMPStream(void):  
    101. m_pRtmp(NULL),  
    102. m_nFileBufSize(0),  
    103. m_nCurPos(0)  
    104. {  
    105.     m_pFileBuf = new unsigned char[FILEBUFSIZE];  
    106.     memset(m_pFileBuf,0,FILEBUFSIZE);  
    107.     InitSockets();  
    108.     m_pRtmp = RTMP_Alloc();    
    109.     RTMP_Init(m_pRtmp);    
    110. }  
    111.   
    112. CRTMPStream::~CRTMPStream(void)  
    113. {  
    114.     Close();  
    115.     WSACleanup();    
    116.     delete[] m_pFileBuf;  
    117. }  
    118.   
    119. bool CRTMPStream::Connect(const char* url)  
    120. {  
    121.     if(RTMP_SetupURL(m_pRtmp, (char*)url)<0)  
    122.     {  
    123.         return FALSE;  
    124.     }  
    125.     RTMP_EnableWrite(m_pRtmp);  
    126.     if(RTMP_Connect(m_pRtmp, NULL)<0)  
    127.     {  
    128.         return FALSE;  
    129.     }  
    130.     if(RTMP_ConnectStream(m_pRtmp,0)<0)  
    131.     {  
    132.         return FALSE;  
    133.     }  
    134.     return TRUE;  
    135. }  
    136.   
    137. void CRTMPStream::Close()  
    138. {  
    139.     if(m_pRtmp)  
    140.     {  
    141.         RTMP_Close(m_pRtmp);  
    142.         RTMP_Free(m_pRtmp);  
    143.         m_pRtmp = NULL;  
    144.     }  
    145. }  
    146.   
    147. int CRTMPStream::SendPacket(unsigned int nPacketType,unsigned char *data,unsigned int size,unsigned int nTimestamp)  
    148. {  
    149.     if(m_pRtmp == NULL)  
    150.     {  
    151.         return FALSE;  
    152.     }  
    153.   
    154.     RTMPPacket packet;  
    155.     RTMPPacket_Reset(&packet);  
    156.     RTMPPacket_Alloc(&packet,size);  
    157.   
    158.     packet.m_packetType = nPacketType;  
    159.     packet.m_nChannel = 0x04;    
    160.     packet.m_headerType = RTMP_PACKET_SIZE_LARGE;    
    161.     packet.m_nTimeStamp = nTimestamp;    
    162.     packet.m_nInfoField2 = m_pRtmp->m_stream_id;  
    163.     packet.m_nBodySize = size;  
    164.     memcpy(packet.m_body,data,size);  
    165.   
    166.     int nRet = RTMP_SendPacket(m_pRtmp,&packet,0);  
    167.   
    168.     RTMPPacket_Free(&packet);  
    169.   
    170.     return nRet;  
    171. }  
    172.   
    173. bool CRTMPStream::SendMetadata(LPRTMPMetadata lpMetaData)  
    174. {  
    175.     if(lpMetaData == NULL)  
    176.     {  
    177.         return false;  
    178.     }  
    179.     char body[1024] = {0};;  
    180.       
    181.     char * p = (char *)body;    
    182.     p = put_byte(p, AMF_STRING );  
    183.     p = put_amf_string(p , "@setDataFrame" );  
    184.   
    185.     p = put_byte( p, AMF_STRING );  
    186.     p = put_amf_string( p, "onMetaData" );  
    187.   
    188.     p = put_byte(p, AMF_OBJECT );    
    189.     p = put_amf_string( p, "copyright" );    
    190.     p = put_byte(p, AMF_STRING );    
    191.     p = put_amf_string( p, "firehood" );    
    192.   
    193.     p =put_amf_string( p, "width");  
    194.     p =put_amf_double( p, lpMetaData->nWidth);  
    195.   
    196.     p =put_amf_string( p, "height");  
    197.     p =put_amf_double( p, lpMetaData->nHeight);  
    198.   
    199.     p =put_amf_string( p, "framerate" );  
    200.     p =put_amf_double( p, lpMetaData->nFrameRate);   
    201.   
    202.     p =put_amf_string( p, "videocodecid" );  
    203.     p =put_amf_double( p, FLV_CODECID_H264 );  
    204.   
    205.     p =put_amf_string( p, "" );  
    206.     p =put_byte( p, AMF_OBJECT_END  );  
    207.   
    208.     int index = p-body;  
    209.   
    210.     SendPacket(RTMP_PACKET_TYPE_INFO,(unsigned char*)body,p-body,0);  
    211.   
    212.     int i = 0;  
    213.     body[i++] = 0x17; // 1:keyframe  7:AVC  
    214.     body[i++] = 0x00; // AVC sequence header  
    215.   
    216.     body[i++] = 0x00;  
    217.     body[i++] = 0x00;  
    218.     body[i++] = 0x00; // fill in 0;  
    219.   
    220.     // AVCDecoderConfigurationRecord.  
    221.     body[i++] = 0x01; // configurationVersion  
    222.     body[i++] = lpMetaData->Sps[1]; // AVCProfileIndication  
    223.     body[i++] = lpMetaData->Sps[2]; // profile_compatibility  
    224.     body[i++] = lpMetaData->Sps[3]; // AVCLevelIndication   
    225.     body[i++] = 0xff; // lengthSizeMinusOne    
    226.   
    227.     // sps nums  
    228.     body[i++] = 0xE1; //&0x1f  
    229.     // sps data length  
    230.     body[i++] = lpMetaData->nSpsLen>>8;  
    231.     body[i++] = lpMetaData->nSpsLen&0xff;  
    232.     // sps data  
    233.     memcpy(&body[i],lpMetaData->Sps,lpMetaData->nSpsLen);  
    234.     i= i+lpMetaData->nSpsLen;  
    235.   
    236.     // pps nums  
    237.     body[i++] = 0x01; //&0x1f  
    238.     // pps data length   
    239.     body[i++] = lpMetaData->nPpsLen>>8;  
    240.     body[i++] = lpMetaData->nPpsLen&0xff;  
    241.     // sps data  
    242.     memcpy(&body[i],lpMetaData->Pps,lpMetaData->nPpsLen);  
    243.     i= i+lpMetaData->nPpsLen;  
    244.   
    245.     return SendPacket(RTMP_PACKET_TYPE_VIDEO,(unsigned char*)body,i,0);  
    246.   
    247. }  
    248.   
    249. bool CRTMPStream::SendH264Packet(unsigned char *data,unsigned int size,bool bIsKeyFrame,unsigned int nTimeStamp)  
    250. {  
    251.     if(data == NULL && size<11)  
    252.     {  
    253.         return false;  
    254.     }  
    255.   
    256.     unsigned char *body = new unsigned char[size+9];  
    257.   
    258.     int i = 0;  
    259.     if(bIsKeyFrame)  
    260.     {  
    261.         body[i++] = 0x17;// 1:Iframe  7:AVC  
    262.     }  
    263.     else  
    264.     {  
    265.         body[i++] = 0x27;// 2:Pframe  7:AVC  
    266.     }  
    267.     body[i++] = 0x01;// AVC NALU  
    268.     body[i++] = 0x00;  
    269.     body[i++] = 0x00;  
    270.     body[i++] = 0x00;  
    271.   
    272.     // NALU size  
    273.     body[i++] = size>>24;  
    274.     body[i++] = size>>16;  
    275.     body[i++] = size>>8;  
    276.     body[i++] = size&0xff;;  
    277.   
    278.     // NALU data  
    279.     memcpy(&body[i],data,size);  
    280.   
    281.     bool bRet = SendPacket(RTMP_PACKET_TYPE_VIDEO,body,i+size,nTimeStamp);  
    282.   
    283.     delete[] body;  
    284.   
    285.     return bRet;  
    286. }  
    287.   
    288. bool CRTMPStream::SendH264File(const char *pFileName)  
    289. {  
    290.     if(pFileName == NULL)  
    291.     {  
    292.         return FALSE;  
    293.     }  
    294.     FILE *fp = fopen(pFileName, "rb");    
    295.     if(!fp)    
    296.     {    
    297.         printf("ERROR:open file %s failed!",pFileName);  
    298.     }    
    299.     fseek(fp, 0, SEEK_SET);  
    300.     m_nFileBufSize = fread(m_pFileBuf, sizeof(unsigned char), FILEBUFSIZE, fp);  
    301.     if(m_nFileBufSize >= FILEBUFSIZE)  
    302.     {  
    303.         printf("warning : File size is larger than BUFSIZE ");  
    304.     }  
    305.     fclose(fp);    
    306.   
    307.     RTMPMetadata metaData;  
    308.     memset(&metaData,0,sizeof(RTMPMetadata));  
    309.   
    310.     NaluUnit naluUnit;  
    311.     // 读取SPS帧  
    312.     ReadOneNaluFromBuf(naluUnit);  
    313.     metaData.nSpsLen = naluUnit.size;  
    314.     memcpy(metaData.Sps,naluUnit.data,naluUnit.size);  
    315.   
    316.     // 读取PPS帧  
    317.     ReadOneNaluFromBuf(naluUnit);  
    318.     metaData.nPpsLen = naluUnit.size;  
    319.     memcpy(metaData.Pps,naluUnit.data,naluUnit.size);  
    320.   
    321.     // 解码SPS,获取视频图像宽、高信息  
    322.     int width = 0,height = 0;  
    323.     h264_decode_sps(metaData.Sps,metaData.nSpsLen,width,height);  
    324.     metaData.nWidth = width;  
    325.     metaData.nHeight = height;  
    326.     metaData.nFrameRate = 25;  
    327.      
    328.     // 发送MetaData  
    329.     SendMetadata(&metaData);  
    330.   
    331.     unsigned int tick = 0;  
    332.     while(ReadOneNaluFromBuf(naluUnit))  
    333.     {  
    334.         bool bKeyframe  = (naluUnit.type == 0x05) ? TRUE : FALSE;  
    335.         // 发送H264数据帧  
    336.         SendH264Packet(naluUnit.data,naluUnit.size,bKeyframe,tick);  
    337.         msleep(40);  
    338.         tick +=40;  
    339.     }  
    340.   
    341.     return TRUE;  
    342. }  
    343.   
    344. bool CRTMPStream::ReadOneNaluFromBuf(NaluUnit &nalu)  
    345. {  
    346.     int i = m_nCurPos;  
    347.     while(i<m_nFileBufSize)  
    348.     {  
    349.         if(m_pFileBuf[i++] == 0x00 &&  
    350.             m_pFileBuf[i++] == 0x00 &&  
    351.             m_pFileBuf[i++] == 0x00 &&  
    352.             m_pFileBuf[i++] == 0x01  
    353.             )  
    354.         {  
    355.             int pos = i;  
    356.             while (pos<m_nFileBufSize)  
    357.             {  
    358.                 if(m_pFileBuf[pos++] == 0x00 &&  
    359.                     m_pFileBuf[pos++] == 0x00 &&  
    360.                     m_pFileBuf[pos++] == 0x00 &&  
    361.                     m_pFileBuf[pos++] == 0x01  
    362.                     )  
    363.                 {  
    364.                     break;  
    365.                 }  
    366.             }  
    367.             if(pos == nBufferSize)  
    368.             {  
    369.                 nalu.size = pos-i;    
    370.             }  
    371.             else  
    372.             {  
    373.                 nalu.size = (pos-4)-i;  
    374.             }  
    375.             nalu.type = m_pFileBuf[i]&0x1f;  
    376.             nalu.data = &m_pFileBuf[i];  
    377.   
    378.             m_nCurPos = pos-4;  
    379.             return TRUE;  
    380.         }  
    381.     }  
    382.     return FALSE;  
    383. }  

    附上SpsDecode.h文件:

    [cpp] view plaincopy
     
     
    1. #include <stdio.h>  
    2. #include <math.h>  
    3.   
    4. UINT Ue(BYTE *pBuff, UINT nLen, UINT &nStartBit)  
    5. {  
    6.     //计算0bit的个数  
    7.     UINT nZeroNum = 0;  
    8.     while (nStartBit < nLen * 8)  
    9.     {  
    10.         if (pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8))) //&:按位与,%取余  
    11.         {  
    12.             break;  
    13.         }  
    14.         nZeroNum++;  
    15.         nStartBit++;  
    16.     }  
    17.     nStartBit ++;  
    18.   
    19.   
    20.     //计算结果  
    21.     DWORD dwRet = 0;  
    22.     for (UINT i=0; i<nZeroNum; i++)  
    23.     {  
    24.         dwRet <<= 1;  
    25.         if (pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8)))  
    26.         {  
    27.             dwRet += 1;  
    28.         }  
    29.         nStartBit++;  
    30.     }  
    31.     return (1 << nZeroNum) - 1 + dwRet;  
    32. }  
    33.   
    34.   
    35. int Se(BYTE *pBuff, UINT nLen, UINT &nStartBit)  
    36. {  
    37.     int UeVal=Ue(pBuff,nLen,nStartBit);  
    38.     double k=UeVal;  
    39.     int nValue=ceil(k/2);//ceil函数:ceil函数的作用是求不小于给定实数的最小整数。ceil(2)=ceil(1.2)=cei(1.5)=2.00  
    40.     if (UeVal % 2==0)  
    41.         nValue=-nValue;  
    42.     return nValue;  
    43. }  
    44.   
    45.   
    46. DWORD u(UINT BitCount,BYTE * buf,UINT &nStartBit)  
    47. {  
    48.     DWORD dwRet = 0;  
    49.     for (UINT i=0; i<BitCount; i++)  
    50.     {  
    51.         dwRet <<= 1;  
    52.         if (buf[nStartBit / 8] & (0x80 >> (nStartBit % 8)))  
    53.         {  
    54.             dwRet += 1;  
    55.         }  
    56.         nStartBit++;  
    57.     }  
    58.     return dwRet;  
    59. }  
    60.   
    61.   
    62. bool h264_decode_sps(BYTE * buf,unsigned int nLen,int &width,int &height)  
    63. {  
    64.     UINT StartBit=0;   
    65.     int forbidden_zero_bit=u(1,buf,StartBit);  
    66.     int nal_ref_idc=u(2,buf,StartBit);  
    67.     int nal_unit_type=u(5,buf,StartBit);  
    68.     if(nal_unit_type==7)  
    69.     {  
    70.         int profile_idc=u(8,buf,StartBit);  
    71.         int constraint_set0_flag=u(1,buf,StartBit);//(buf[1] & 0x80)>>7;  
    72.         int constraint_set1_flag=u(1,buf,StartBit);//(buf[1] & 0x40)>>6;  
    73.         int constraint_set2_flag=u(1,buf,StartBit);//(buf[1] & 0x20)>>5;  
    74.         int constraint_set3_flag=u(1,buf,StartBit);//(buf[1] & 0x10)>>4;  
    75.         int reserved_zero_4bits=u(4,buf,StartBit);  
    76.         int level_idc=u(8,buf,StartBit);  
    77.   
    78.         int seq_parameter_set_id=Ue(buf,nLen,StartBit);  
    79.   
    80.         if( profile_idc == 100 || profile_idc == 110 ||  
    81.             profile_idc == 122 || profile_idc == 144 )  
    82.         {  
    83.             int chroma_format_idc=Ue(buf,nLen,StartBit);  
    84.             if( chroma_format_idc == 3 )  
    85.                 int residual_colour_transform_flag=u(1,buf,StartBit);  
    86.             int bit_depth_luma_minus8=Ue(buf,nLen,StartBit);  
    87.             int bit_depth_chroma_minus8=Ue(buf,nLen,StartBit);  
    88.             int qpprime_y_zero_transform_bypass_flag=u(1,buf,StartBit);  
    89.             int seq_scaling_matrix_present_flag=u(1,buf,StartBit);  
    90.   
    91.             int seq_scaling_list_present_flag[8];  
    92.             if( seq_scaling_matrix_present_flag )  
    93.             {  
    94.                 for( int i = 0; i < 8; i++ ) {  
    95.                     seq_scaling_list_present_flag[i]=u(1,buf,StartBit);  
    96.                 }  
    97.             }  
    98.         }  
    99.         int log2_max_frame_num_minus4=Ue(buf,nLen,StartBit);  
    100.         int pic_order_cnt_type=Ue(buf,nLen,StartBit);  
    101.         if( pic_order_cnt_type == 0 )  
    102.             int log2_max_pic_order_cnt_lsb_minus4=Ue(buf,nLen,StartBit);  
    103.         else if( pic_order_cnt_type == 1 )  
    104.         {  
    105.             int delta_pic_order_always_zero_flag=u(1,buf,StartBit);  
    106.             int offset_for_non_ref_pic=Se(buf,nLen,StartBit);  
    107.             int offset_for_top_to_bottom_field=Se(buf,nLen,StartBit);  
    108.             int num_ref_frames_in_pic_order_cnt_cycle=Ue(buf,nLen,StartBit);  
    109.   
    110.             int *offset_for_ref_frame=new int[num_ref_frames_in_pic_order_cnt_cycle];  
    111.             for( int i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ )  
    112.                 offset_for_ref_frame[i]=Se(buf,nLen,StartBit);  
    113.             delete [] offset_for_ref_frame;  
    114.         }  
    115.         int num_ref_frames=Ue(buf,nLen,StartBit);  
    116.         int gaps_in_frame_num_value_allowed_flag=u(1,buf,StartBit);  
    117.         int pic_width_in_mbs_minus1=Ue(buf,nLen,StartBit);  
    118.         int pic_height_in_map_units_minus1=Ue(buf,nLen,StartBit);  
    119.   
    120.         width=(pic_width_in_mbs_minus1+1)*16;  
    121.         height=(pic_height_in_map_units_minus1+1)*16;  
    122.   
    123.         return true;  
    124.     }  
    125.     else  
    126.         return false;  
    127. }  
     
     
  • 相关阅读:
    stm32启动代码分析
    STM32固件库详解
    ARM GCC CodeSourcery EABI下载地址
    Linux/redhat 基本网络配置
    侧边栏导航
    div滚动,页面不滚动
    自定义滚动条样式
    placeholder自定义CSS
    浏览器判断
    初始化页面垂直居中
  • 原文地址:https://www.cnblogs.com/lidabo/p/5384060.html
Copyright © 2020-2023  润新知