H264视频通过RTMP直播(神文)

http://blog.csdn.net/firehood_/article/details/8783589



 

H264视频通过RTMP直播

  20999人阅读  评论(45)  收藏  举报
本文章已收录于: 
       前面的文章中提到了通过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 plain  copy
  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 plain  copy
  1. #include <stdio.h>    
  2. #include "RTMPStream\RTMPStream.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 plain  copy
  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 plain  copy
  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\n");  
  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 plain  copy
  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.                 forint 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.             forint 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. }  



21
0
 
 
猜你在找
WEB前端整套教程html+divcss+javascript+jquery+html5
[颠覆传统所学]web开发级Centos颠覆实战(上)
Part 23:Cocos2d-x开发实战-移植-从Win32到Windows Phone8
Java分布式架构: Spring搭建RESTful web Service
Windows Server 2012 DHCP Server 管理
浅谈iOS视频开发 - 小书sky
iOS第三方直播的集成
iOS视频开发
流媒体协议 之 RTMP
最纯粹的直播技术实战01-FFmpeg的编译与运行
查看评论
28楼  茶凉半截 2016-09-09 17:37发表 [回复]
编译没有问题,总是在
// 读取PPS帧 
ReadOneNaluFromBuf(naluUnit);
metaData.nPpsLen = naluUnit.size;
memcpy(metaData.Pps, naluUnit.data, naluUnit.size);
memcpy这里中断是怎么回事?
27楼  酒酿fuck小圆子 2015-11-26 14:48发表 [回复]
楼主 我现在想推送264 和aac两路流 , 那我是不是要createstream 两个来推送,还是只要connectstream之后,直接往这个id里面推
26楼  lo踏ve 2015-05-04 13:31发表 [回复]
博主,你这篇文章是不是只发布了视频数据,而没有发布音频数据呢?
25楼  hssmy 2015-03-21 13:46发表 [回复]
多谢啦,直接用你代码了,发布成功了。
Re:  lo踏ve 2015-05-03 21:24发表 [回复]
回复hssmy:你发布的flv文件,还是原始的h264数据流?
24楼  lanruosidehuli 2014-07-21 18:04发表 [回复]
楼主,我根据你的代码可以正常发布h264和aac数据,但是h264是场编码时,播放的话高度只是场的高度,不是完整帧的高度,麻烦问下楼主有遇到这种问题吗?
23楼  ybsun2010 2014-06-11 10:35发表 [回复]
大神能不能补充下AAC的发送过程?谢谢了
22楼  y317215133y 2014-06-04 17:36发表 [回复]
我将H264码流发送到AMS后进行直播,但是在播放过程中,关闭直播,再开始直播时,却无法播放是怎么回事?
21楼  youngalmond11 2014-05-13 15:13发表 [回复]
试了下,连接FMS成功,可以观看,谢谢分享……
(nBufferSize、m_nFileBufSize 如9楼说的需要改下)
20楼  spy32 2014-05-12 21:37发表 [回复]
楼主好样的,测试文件发送没问题,等采集和压缩搞定了试试发送数据帧,感谢楼主无私奉献。学习了。
19楼  精分患者 2014-04-19 18:56发表 [回复]
为什么我调试的时候程序在RTMP_ConnectStream(m_pRtmp,0)这个函数这里就停止不动了呢??求大神帮忙啊,因为这个都快疯了啊!!!
18楼  嵌入式软件专家 2014-02-26 17:18发表 [回复]
楼主我这边编出来后,推出去后视频播放时卡,请问是什么情况。我是把这个代码移植到嵌入式板子下使用的。
Re:  y317215133y 2014-07-30 15:05发表 [回复]
回复嵌入式软件专家:我也是这样啊,不知怎么解决
17楼  阳光梦 2013-12-27 15:49发表 [回复]
你好啊,请教:当网页上面flash播放器关闭了,但是网页未关闭,怎样让flash与adobe服务器断开连接呢?
16楼  阳光梦 2013-12-21 15:24发表 [回复]
您好,请教下:rtmp发送视频时候假如帧率为15,那么
while(ReadOneNaluFromBuf(naluUnit))
{
bool bKeyframe = (naluUnit.type == 0x05) ? TRUE : FALSE;
// 发送H264数据帧
SendH264Packet(naluUnit.data,naluUnit.size,bKeyframe,tick);
//
msleep(40);
tick +=40;
}
时间戳改写多大呢?
Re:  firehood 2013-12-23 09:53发表 [回复]
回复阳光梦:如果帧率为25.即25每秒. 所以tick=1s/25=0.04s=40ms.同理,如果帧率为15.tick=1s/15=0.067s=67ms
15楼  tmcrazy 2013-10-14 14:21发表 [回复]
14楼  fengsehng 2013-10-10 22:29发表 [回复]
楼主快给我发源代码吧。我弄了好久了。。。。无语啊2235978660@qq.com
13楼  fengsehng 2013-10-10 10:59发表 [回复]
lz,我是初学者,我运行你的程序好几天了,还没成功,麻烦你把源代码给我一份吧。我的邮箱2235978660@qq.com.
12楼  fengsehng 2013-10-05 22:41发表 [回复]
lz写的很详细,但不知道这些头文件是哪里的
#include "rtmp.h" 
#include "rtmp_sys.h" 
#include "amf.h"
下载网上的libstmp吗?求lz贴出来一份吧
11楼  梓洋may 2013-09-30 11:32发表 [回复]
您好,最近在研究rtmp播放器,rtmpdump源码好像只支持flv格式(VP6编码文件),不支持f4v格式(H264编码文件),请教您,有什么办法可以解决吗?研究代码中......RTMP_ConnectStream失败,什么原因呢?三克油!
10楼  hcit_ld 2013-07-23 09:49发表 [回复]
ERROR: RTMP_ReadPacket, failed to read RTMP packet header
连接服务器成功!
ERROR: WriteN, RTMP send error 10038 (140 bytes)
ERROR: WriteN, RTMP send error 10038 (134 bytes)
ERROR: WriteN, RTMP send error 10038 (140 bytes)
ERROR: WriteN, RTMP send error 10038 (140 bytes)
ERROR: WriteN, RTMP send error 10038 (140 bytes)
ERROR: WriteN, RTMP send error 10038 (140 bytes)
ERROR: WriteN, RTMP send error 10038 (140 bytes)
ERROR: WriteN, RTMP send error 10038 (140 bytes)
ERROR: WriteN, RTMP send error 10038 (140 bytes)
ERROR: WriteN, RTMP send error 10038 (140 bytes)
ERROR: WriteN, RTMP send error 10038 (140 bytes)
ERROR: WriteN, RTMP send error 10038 (140 bytes)
ERROR: WriteN, RTMP send error 10038 (140 bytes)
ERROR: WriteN, RTMP send error 10038 (140 bytes)

这是什么问题呢?
9楼  wangsky2 2013-06-21 14:45发表 [回复]
if(pos == nBufferSize) 

nalu.size = pos-i; 


nBufferSize:这里是什么意思呢?
Re:  wangsky2 2013-06-21 15:00发表 [回复]
回复wangsky2:应该是:m_nFileBufSize 这个吧??
8楼  ningmengqq 2013-06-08 15:33发表 [回复]
你好,对于你的这个工程我自己试着编译过,只是因为没有SpsDecode.h这个头文件所以不通过,但是这应该与这个工程影响不大,从工程上看似乎只是用来获得264文件视频图像的宽与高。因此我注释掉该头文件以及下面的h264_decode_sps(metaData.Sps,metaData.nSpsLen,width,height); 
而固定填上视频的宽与高,在运行程序的时候发现有能正确连接到red5,但是却不能从red5上读取,请大哥指教到底哪儿可能出了问题
Re:  firehood 2013-06-09 16:34发表 [回复]
回复ningmengqq:你可以用FMS试试,或者在检查一下原始的H264视频格式是否正确。
7楼  zijinzelan2012 2013-06-08 11:12发表 [回复]
lz,程序写得非常好,非常清晰,学习了,但是我找不到SpsDecode.h头文件,问下楼主这是哪里的,能发我一份吗?
Re:  firehood 2013-06-09 16:28发表 [回复]
回复zijinzelan2012:SpsDecode.h已添加到文章后面
6楼  行业达人 2013-06-03 10:18发表 [回复]
按照这个代码编译出来的程序,可以正常连接FMS,也能够发送数据,但是客户端无法观看。好像是封包的格式不对,请博主介绍一下。谢谢!
Re:  酷夏至末 2013-12-24 16:25发表 [回复]
回复行业达人:你好!我根据博主的代码,然后发送H264编码文件到red5上,也是客户端不能播放。请问你最后是怎么解决的呢?谢谢
Re:  firehood 2013-06-03 16:10发表 [回复]
回复行业达人:你可以检查一下原始的H264视频格式是否正确。是否包含SPS和PPS信息。我用FMS、CRtmpServer测试过,没有问题。
Re:  ningmengqq 2013-06-08 15:37发表 [回复]
回复firehood:原始264文件应该正确,因为包含了SPS和PPS,后面就是直接的视频数据,而且用专用的264播放器是能够直接播放的
5楼  行业达人 2013-05-25 12:00发表 [回复]
程序写得很清晰!
楼主能否发表文章介绍一下SPS和PPS,毕竟这个在RTMP开发中难住了很多人。
Re:  firehood 2013-06-03 16:12发表 [回复]
回复行业达人:关于SPS和PPS,可以查看相应的H264文档,我就没必要介绍了。
4楼  ZibbL 2013-05-16 16:29发表 [回复]
LZ,问个问题,不是在是分片包的时候才把body[0] 设置为17吗,为什么你这直接用关键帧或非关键帧判断?
3楼  子虚 2013-05-14 23:17发表 [回复]
程序写得很好,我现在要发送实时AAC音频到Red5,我看RTMPMetadata中也定义了AAC的信息,能讲一下AAC元数据是什么格式吗?开始的音频信息怎么发送?每次用RTMP_SendPacket()发送的帧是纯AAC数据还是加点其它信息?
Re:  firehood 2013-05-15 11:38发表 [回复]
回复子虚:目前接口只实现了发送H264视频,ACC音频发送还没有实现,不过实现起来应该不难,你可以研究一下。
2楼  明月惊鹊 2013-05-05 12:39发表 [回复]
我来了~~嚎嚎嚎嚎
1楼  daijinqiu2008 2013-04-28 11:49发表 [回复]
你这里面的SpsDecode.h是什么头文件?



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值