首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > 移动开发 >

H264视频透过RTMP发送

2013-04-12 
H264视频通过RTMP发送前面的文章中提到了通过RTSP(Real Time Streaming Protocol)的方式来实现视频的直播,

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提供的接口如下。


最后附上RTMPStream完整的代码:

/******************************************************************** filename:   RTMPStream.cppcreated:    2013-04-3author:     firehood purpose:    发送H264视频到RTMP Server,使用libRtmp库*********************************************************************/ #include "RTMPStream.h"#include "SpsDecode.h"#ifdef WIN32  #include <windows.h>#endifenum{FLV_CODECID_H264 = 7,};int InitSockets()  {  #ifdef WIN32  WORD version;  WSADATA wsaData;  version = MAKEWORD(1, 1);  return (WSAStartup(version, &wsaData) == 0);  #else  return TRUE;  #endif  }  inline void CleanupSockets()  {  #ifdef WIN32  WSACleanup();  #endif  }  char * put_byte( char *output, uint8_t nVal )  {  output[0] = nVal;  return output+1;  }  char * put_be16(char *output, uint16_t nVal )  {  output[1] = nVal & 0xff;  output[0] = nVal >> 8;  return output+2;  }  char * put_be24(char *output,uint32_t nVal )  {  output[2] = nVal & 0xff;  output[1] = nVal >> 8;  output[0] = nVal >> 16;  return output+3;  }  char * put_be32(char *output, uint32_t nVal )  {  output[3] = nVal & 0xff;  output[2] = nVal >> 8;  output[1] = nVal >> 16;  output[0] = nVal >> 24;  return output+4;  }  char *  put_be64( char *output, uint64_t nVal )  {  output=put_be32( output, nVal >> 32 );  output=put_be32( output, nVal );  return output;  }  char * put_amf_string( char *c, const char *str )  {  uint16_t len = strlen( str );  c=put_be16( c, len );  memcpy(c,str,len);  return c+len;  }  char * put_amf_double( char *c, double d )  {  *c++ = AMF_NUMBER;  /* type: Number */  {  unsigned char *ci, *co;  ci = (unsigned char *)&d;  co = (unsigned char *)c;  co[0] = ci[7];  co[1] = ci[6];  co[2] = ci[5];  co[3] = ci[4];  co[4] = ci[3];  co[5] = ci[2];  co[6] = ci[1];  co[7] = ci[0];  }  return c+8;  }CRTMPStream::CRTMPStream(void):m_pRtmp(NULL),m_nFileBufSize(0),m_nCurPos(0){m_pFileBuf = new unsigned char[FILEBUFSIZE];memset(m_pFileBuf,0,FILEBUFSIZE);InitSockets();m_pRtmp = RTMP_Alloc();  RTMP_Init(m_pRtmp);  }CRTMPStream::~CRTMPStream(void){Close();WSACleanup();  delete[] m_pFileBuf;}bool CRTMPStream::Connect(const char* url){if(RTMP_SetupURL(m_pRtmp, (char*)url)<0){return FALSE;}RTMP_EnableWrite(m_pRtmp);if(RTMP_Connect(m_pRtmp, NULL)<0){return FALSE;}if(RTMP_ConnectStream(m_pRtmp,0)<0){return FALSE;}return TRUE;}void CRTMPStream::Close(){if(m_pRtmp){RTMP_Close(m_pRtmp);RTMP_Free(m_pRtmp);m_pRtmp = NULL;}}int CRTMPStream::SendPacket(unsigned int nPacketType,unsigned char *data,unsigned int size,unsigned int nTimestamp){if(m_pRtmp == NULL){return FALSE;}RTMPPacket packet;RTMPPacket_Reset(&packet);RTMPPacket_Alloc(&packet,size);packet.m_packetType = nPacketType;packet.m_nChannel = 0x04;  packet.m_headerType = RTMP_PACKET_SIZE_LARGE;  packet.m_nTimeStamp = nTimestamp;  packet.m_nInfoField2 = m_pRtmp->m_stream_id;packet.m_nBodySize = size;memcpy(packet.m_body,data,size);int nRet = RTMP_SendPacket(m_pRtmp,&packet,0);RTMPPacket_Free(&packet);return nRet;}bool CRTMPStream::SendMetadata(LPRTMPMetadata lpMetaData){if(lpMetaData == NULL){return false;}char body[1024] = {0};;        char * p = (char *)body;  p = put_byte(p, AMF_STRING );p = put_amf_string(p , "@setDataFrame" );p = put_byte( p, AMF_STRING );p = put_amf_string( p, "onMetaData" );p = put_byte(p, AMF_OBJECT );  p = put_amf_string( p, "copyright" );  p = put_byte(p, AMF_STRING );  p = put_amf_string( p, "firehood" );  p =put_amf_string( p, "width");p =put_amf_double( p, lpMetaData->nWidth);p =put_amf_string( p, "height");p =put_amf_double( p, lpMetaData->nHeight);p =put_amf_string( p, "framerate" );p =put_amf_double( p, lpMetaData->nFrameRate); p =put_amf_string( p, "videocodecid" );p =put_amf_double( p, FLV_CODECID_H264 );p =put_amf_string( p, "" );p =put_byte( p, AMF_OBJECT_END  );int index = p-body;SendPacket(RTMP_PACKET_TYPE_INFO,(unsigned char*)body,p-body,0);int i = 0;body[i++] = 0x17; // 1:keyframe  7:AVCbody[i++] = 0x00; // AVC sequence headerbody[i++] = 0x00;body[i++] = 0x00;body[i++] = 0x00; // fill in 0;// AVCDecoderConfigurationRecord.body[i++] = 0x01; // configurationVersionbody[i++] = lpMetaData->Sps[1]; // AVCProfileIndicationbody[i++] = lpMetaData->Sps[2]; // profile_compatibilitybody[i++] = lpMetaData->Sps[3]; // AVCLevelIndication     body[i++] = 0xff; // lengthSizeMinusOne      // sps numsbody[i++] = 0xE1; //&0x1f// sps data lengthbody[i++] = lpMetaData->nSpsLen>>8;body[i++] = lpMetaData->nSpsLen&0xff;// sps datamemcpy(&body[i],lpMetaData->Sps,lpMetaData->nSpsLen);i= i+lpMetaData->nSpsLen;// pps numsbody[i++] = 0x01; //&0x1f// pps data length body[i++] = lpMetaData->nPpsLen>>8;body[i++] = lpMetaData->nPpsLen&0xff;// sps datamemcpy(&body[i],lpMetaData->Pps,lpMetaData->nPpsLen);i= i+lpMetaData->nPpsLen;return SendPacket(RTMP_PACKET_TYPE_VIDEO,(unsigned char*)body,i,0);}bool CRTMPStream::SendH264Packet(unsigned char *data,unsigned int size,bool bIsKeyFrame,unsigned int nTimeStamp){if(data == NULL && size<11){return false;}unsigned char *body = new unsigned char[size+9];int i = 0;if(bIsKeyFrame){body[i++] = 0x17;// 1:Iframe  7:AVC}else{body[i++] = 0x27;// 2:Pframe  7:AVC}body[i++] = 0x01;// AVC NALUbody[i++] = 0x00;body[i++] = 0x00;body[i++] = 0x00;// NALU sizebody[i++] = size>>24;body[i++] = size>>16;body[i++] = size>>8;body[i++] = size&0xff;;// NALU datamemcpy(&body[i],data,size);bool bRet = SendPacket(RTMP_PACKET_TYPE_VIDEO,body,i+size,nTimeStamp);delete[] body;return bRet;}bool CRTMPStream::SendH264File(const char *pFileName){if(pFileName == NULL){return FALSE;}FILE *fp = fopen(pFileName, "rb");  if(!fp)  {  printf("ERROR:open file %s failed!",pFileName);}  fseek(fp, 0, SEEK_SET);m_nFileBufSize = fread(m_pFileBuf, sizeof(unsigned char), FILEBUFSIZE, fp);if(m_nFileBufSize >= FILEBUFSIZE){printf("warning : File size is larger than BUFSIZE\n");}fclose(fp);  RTMPMetadata metaData;memset(&metaData,0,sizeof(RTMPMetadata));    NaluUnit naluUnit;// 读取SPS帧    ReadOneNaluFromBuf(naluUnit);metaData.nSpsLen = naluUnit.size;memcpy(metaData.Sps,naluUnit.data,naluUnit.size);// 读取PPS帧ReadOneNaluFromBuf(naluUnit);metaData.nPpsLen = naluUnit.size;memcpy(metaData.Pps,naluUnit.data,naluUnit.size);// 解码SPS,获取视频图像宽、高信息int width = 0,height = 0;    h264_decode_sps(metaData.Sps,metaData.nSpsLen,width,height);metaData.nWidth = width;    metaData.nHeight = height;metaData.nFrameRate = 25;   // 发送MetaData    SendMetadata(&metaData);unsigned int tick = 0;while(ReadOneNaluFromBuf(naluUnit)){bool bKeyframe  = (naluUnit.type == 0x05) ? TRUE : FALSE;// 发送H264数据帧SendH264Packet(naluUnit.data,naluUnit.size,bKeyframe,tick);msleep(40);tick +=40;}return TRUE;}bool CRTMPStream::ReadOneNaluFromBuf(NaluUnit &nalu){int i = m_nCurPos;while(i<m_nFileBufSize-4){if(m_pFileBuf[i++] == 0x00 &&m_pFileBuf[i++] == 0x00 &&m_pFileBuf[i++] == 0x00 &&m_pFileBuf[i++] == 0x01){int pos = i;while (pos<m_nFileBufSize-4){if(m_pFileBuf[pos++] == 0x00 &&m_pFileBuf[pos++] == 0x00 &&m_pFileBuf[pos++] == 0x00 &&m_pFileBuf[pos++] == 0x01){break;}}nalu.type = m_pFileBuf[i]&0x1f;nalu.size = (pos-4)-i;nalu.data = &m_pFileBuf[i];m_nCurPos = pos-4;return TRUE;}}return FALSE;}



热点排行