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

2024-02-05 10:08
文章标签 视频 直播 rtmp h264 神文

本文主要是介绍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是什么头文件?



这篇关于H264视频通过RTMP直播(神文)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/680565

相关文章

流媒体平台/视频监控/安防视频汇聚EasyCVR播放暂停后视频画面黑屏是什么原因?

视频智能分析/视频监控/安防监控综合管理系统EasyCVR视频汇聚融合平台,是TSINGSEE青犀视频垂直深耕音视频流媒体技术、AI智能技术领域的杰出成果。该平台以其强大的视频处理、汇聚与融合能力,在构建全栈视频监控系统中展现出了独特的优势。视频监控管理系统EasyCVR平台内置了强大的视频解码、转码、压缩等技术,能够处理多种视频流格式,并以多种格式(RTMP、RTSP、HTTP-FLV、WebS

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

《x86汇编语言:从实模式到保护模式》视频来了

《x86汇编语言:从实模式到保护模式》视频来了 很多朋友留言,说我的专栏《x86汇编语言:从实模式到保护模式》写得很详细,还有的朋友希望我能写得更细,最好是覆盖全书的所有章节。 毕竟我不是作者,只有作者的解读才是最权威的。 当初我学习这本书的时候,只能靠自己摸索,网上搜不到什么好资源。 如果你正在学这本书或者汇编语言,那你有福气了。 本书作者李忠老师,以此书为蓝本,录制了全套视频。 试

速盾:直播 cdn 服务器带宽?

在当今数字化时代,直播已经成为了一种非常流行的娱乐和商业活动形式。为了确保直播的流畅性和高质量,直播平台通常会使用 CDN(Content Delivery Network,内容分发网络)服务器来分发直播流。而 CDN 服务器的带宽则是影响直播质量的一个重要因素。下面我们就来探讨一下速盾视角下的直播 CDN 服务器带宽问题。 一、直播对带宽的需求 高清视频流 直播通常需要传输高清视频

CRtmpServer转推流到Nginx Rtmp及SRS(SimpleRtmpServer)的经历

转自:http://blog.csdn.net/fengyily/article/details/42557841 本人一直用的是CRtmpServer服务,在CRtmpServer服务中根据自已的想法也加入了许多功能,如通过http接口来加载配置等,苦于不支持HLS,自已添加ts分片水平又有限,思来想去决定借助SimpleRtmpServer的HLS功能。说干就干,马上查找相关资源

rtmp流媒体编程相关整理2013(crtmpserver,rtmpdump,x264,faac)

转自:http://blog.163.com/zhujiatc@126/blog/static/1834638201392335213119/ 相关资料在线版(不定时更新,其实也不会很多,也许一两个月也不会改) http://www.zhujiatc.esy.es/crtmpserver/index.htm 去年在这进行rtmp相关整理,其实内容早有了,只是整理一下看着方

RTMP流媒体服务器 crtmpserver

http://www.oschina.net/p/crtmpserver crtmpserver又称rtmpd是Evostream Media Server(www.evostream.com)的社区版本采用GPLV3授权 其主要作用为一个高性能的RTMP流媒体服务器,可以实现直播与点播功能多终端支持功能,在特定情况下是FMS的良好替代品。 支持RTMP的一堆协议(RT

SAM2POINT:以zero-shot且快速的方式将任何 3D 视频分割为视频

摘要 我们介绍 SAM2POINT,这是一种采用 Segment Anything Model 2 (SAM 2) 进行零样本和快速 3D 分割的初步探索。 SAM2POINT 将任何 3D 数据解释为一系列多向视频,并利用 SAM 2 进行 3D 空间分割,无需进一步训练或 2D-3D 投影。 我们的框架支持各种提示类型,包括 3D 点、框和掩模,并且可以泛化到不同的场景,例如 3D 对象、室

树莓派5_opencv笔记27:Opencv录制视频(无声音)

今日继续学习树莓派5 8G:(Raspberry Pi,简称RPi或RasPi)  本人所用树莓派5 装载的系统与版本如下:  版本可用命令 (lsb_release -a) 查询: Opencv 与 python 版本如下: 今天就水一篇文章,用树莓派摄像头,Opencv录制一段视频保存在指定目录... 文章提供测试代码讲解,整体代码贴出、测试效果图 目录 阶段一:录制一段

基于树梅派的视频监控机器人Verybot

最近这段时间做了一个基于树梅派 ( raspberry pi ) 的视频监控机器人平台 Verybot ,现在打算把这个机器人的一些图片、视频、设计思路进行公开,并且希望跟大家一起研究相关的各种问题,下面是两张机器人的照片:         图片1:                   图片2                    这个平台的基本组成是: