本文主要是介绍H264视频通过RTMP直播(神文),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
http://blog.csdn.net/firehood_/article/details/8783589
H264视频通过RTMP直播
2013-04-10 23:29 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)即可观看,而且对平台也没什么限制,还可以方便的通过手机观看。 调用示例:
通过JwPlayer播放效果如下:
视频通过RTMP方式发布需要一个RTMP Server(常见的有FMS、Wowza Media Server, 开源的有CRtmpServer、Red5等),原始视频只要按照RTMP协议发送给RTMP Server就可以RTMP视频流的发布了。为了便于视频的打包发布,封装了一个RTMPStream,目前只支持发送H264的视频文件。可以直接发送H264数据帧或H264文件,RTMPStream提供的接口如下。
[cpp] view plain copy
- class CRTMPStream
- {
- public:
- CRTMPStream(void);
- ~CRTMPStream(void);
- public:
- // 连接到RTMP Server
- bool Connect(const char* url);
- // 断开连接
- void Close();
- // 发送MetaData
- bool SendMetadata(LPRTMPMetadata lpMetaData);
- // 发送H264数据帧
- bool SendH264Packet(unsigned char *data,unsigned int size,bool bIsKeyFrame,unsigned int nTimeStamp);
- // 发送H264文件
- bool SendH264File(const char *pFileName);
- //...
- }
[cpp] view plain copy
- #include <stdio.h>
- #include "RTMPStream\RTMPStream.h"
- int main(int argc,char* argv[])
- {
- CRTMPStream rtmpSender;
- bool bRet = rtmpSender.Connect("rtmp://192.168.1.104/live/test");
- rtmpSender.SendH264File("E:\\video\\test.264");
- rtmpSender.Close();
- }
通过JwPlayer播放效果如下:
最后附上RTMPStream完整的代码:
[cpp] view plain copy
- /********************************************************************
- filename: RTMPStream.h
- created: 2013-04-3
- author: firehood
- purpose: 发送H264视频到RTMP Server,使用libRtmp库
- *********************************************************************/
- #pragma once
- #include "rtmp.h"
- #include "rtmp_sys.h"
- #include "amf.h"
- #include <stdio.h>
- #define FILEBUFSIZE (1024 * 1024 * 10) // 10M
- // NALU单元
- typedef struct _NaluUnit
- {
- int type;
- int size;
- unsigned char *data;
- }NaluUnit;
- typedef struct _RTMPMetadata
- {
- // video, must be h264 type
- unsigned int nWidth;
- unsigned int nHeight;
- unsigned int nFrameRate; // fps
- unsigned int nVideoDataRate; // bps
- unsigned int nSpsLen;
- unsigned char Sps[1024];
- unsigned int nPpsLen;
- unsigned char Pps[1024];
- // audio, must be aac type
- bool bHasAudio;
- unsigned int nAudioSampleRate;
- unsigned int nAudioSampleSize;
- unsigned int nAudioChannels;
- char pAudioSpecCfg;
- unsigned int nAudioSpecCfgLen;
- } RTMPMetadata,*LPRTMPMetadata;
- class CRTMPStream
- {
- public:
- CRTMPStream(void);
- ~CRTMPStream(void);
- public:
- // 连接到RTMP Server
- bool Connect(const char* url);
- // 断开连接
- void Close();
- // 发送MetaData
- bool SendMetadata(LPRTMPMetadata lpMetaData);
- // 发送H264数据帧
- bool SendH264Packet(unsigned char *data,unsigned int size,bool bIsKeyFrame,unsigned int nTimeStamp);
- // 发送H264文件
- bool SendH264File(const char *pFileName);
- private:
- // 送缓存中读取一个NALU包
- bool ReadOneNaluFromBuf(NaluUnit &nalu);
- // 发送数据
- int SendPacket(unsigned int nPacketType,unsigned char *data,unsigned int size,unsigned int nTimestamp);
- private:
- RTMP* m_pRtmp;
- unsigned char* m_pFileBuf;
- unsigned int m_nFileBufSize;
- unsigned int m_nCurPos;
- };
[cpp] view plain copy
- /********************************************************************
- filename: RTMPStream.cpp
- created: 2013-04-3
- author: firehood
- purpose: 发送H264视频到RTMP Server,使用libRtmp库
- *********************************************************************/
- #include "RTMPStream.h"
- #include "SpsDecode.h"
- #ifdef WIN32
- #include <windows.h>
- #endif
- #ifdef WIN32
- #pragma comment(lib,"WS2_32.lib")
- #pragma comment(lib,"winmm.lib")
- #endif
- enum
- {
- 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:AVC
- body[i++] = 0x00; // AVC sequence header
- body[i++] = 0x00;
- body[i++] = 0x00;
- body[i++] = 0x00; // fill in 0;
- // AVCDecoderConfigurationRecord.
- body[i++] = 0x01; // configurationVersion
- body[i++] = lpMetaData->Sps[1]; // AVCProfileIndication
- body[i++] = lpMetaData->Sps[2]; // profile_compatibility
- body[i++] = lpMetaData->Sps[3]; // AVCLevelIndication
- body[i++] = 0xff; // lengthSizeMinusOne
- // sps nums
- body[i++] = 0xE1; //&0x1f
- // sps data length
- body[i++] = lpMetaData->nSpsLen>>8;
- body[i++] = lpMetaData->nSpsLen&0xff;
- // sps data
- memcpy(&body[i],lpMetaData->Sps,lpMetaData->nSpsLen);
- i= i+lpMetaData->nSpsLen;
- // pps nums
- body[i++] = 0x01; //&0x1f
- // pps data length
- body[i++] = lpMetaData->nPpsLen>>8;
- body[i++] = lpMetaData->nPpsLen&0xff;
- // sps data
- memcpy(&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 NALU
- body[i++] = 0x00;
- body[i++] = 0x00;
- body[i++] = 0x00;
- // NALU size
- body[i++] = size>>24;
- body[i++] = size>>16;
- body[i++] = size>>8;
- body[i++] = size&0xff;;
- // NALU data
- memcpy(&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)
- {
- if(m_pFileBuf[i++] == 0x00 &&
- m_pFileBuf[i++] == 0x00 &&
- m_pFileBuf[i++] == 0x00 &&
- m_pFileBuf[i++] == 0x01
- )
- {
- int pos = i;
- while (pos<m_nFileBufSize)
- {
- if(m_pFileBuf[pos++] == 0x00 &&
- m_pFileBuf[pos++] == 0x00 &&
- m_pFileBuf[pos++] == 0x00 &&
- m_pFileBuf[pos++] == 0x01
- )
- {
- break;
- }
- }
- if(pos == nBufferSize)
- {
- nalu.size = pos-i;
- }
- else
- {
- nalu.size = (pos-4)-i;
- }
- nalu.type = m_pFileBuf[i]&0x1f;
- nalu.data = &m_pFileBuf[i];
- m_nCurPos = pos-4;
- return TRUE;
- }
- }
- return FALSE;
- }
附上SpsDecode.h文件:
[cpp] view plain copy
- #include <stdio.h>
- #include <math.h>
- UINT Ue(BYTE *pBuff, UINT nLen, UINT &nStartBit)
- {
- //计算0bit的个数
- UINT nZeroNum = 0;
- while (nStartBit < nLen * 8)
- {
- if (pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8))) //&:按位与,%取余
- {
- break;
- }
- nZeroNum++;
- nStartBit++;
- }
- nStartBit ++;
- //计算结果
- DWORD dwRet = 0;
- for (UINT i=0; i<nZeroNum; i++)
- {
- dwRet <<= 1;
- if (pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8)))
- {
- dwRet += 1;
- }
- nStartBit++;
- }
- return (1 << nZeroNum) - 1 + dwRet;
- }
- int Se(BYTE *pBuff, UINT nLen, UINT &nStartBit)
- {
- int UeVal=Ue(pBuff,nLen,nStartBit);
- double k=UeVal;
- int nValue=ceil(k/2);//ceil函数:ceil函数的作用是求不小于给定实数的最小整数。ceil(2)=ceil(1.2)=cei(1.5)=2.00
- if (UeVal % 2==0)
- nValue=-nValue;
- return nValue;
- }
- DWORD u(UINT BitCount,BYTE * buf,UINT &nStartBit)
- {
- DWORD dwRet = 0;
- for (UINT i=0; i<BitCount; i++)
- {
- dwRet <<= 1;
- if (buf[nStartBit / 8] & (0x80 >> (nStartBit % 8)))
- {
- dwRet += 1;
- }
- nStartBit++;
- }
- return dwRet;
- }
- bool h264_decode_sps(BYTE * buf,unsigned int nLen,int &width,int &height)
- {
- UINT StartBit=0;
- int forbidden_zero_bit=u(1,buf,StartBit);
- int nal_ref_idc=u(2,buf,StartBit);
- int nal_unit_type=u(5,buf,StartBit);
- if(nal_unit_type==7)
- {
- int profile_idc=u(8,buf,StartBit);
- int constraint_set0_flag=u(1,buf,StartBit);//(buf[1] & 0x80)>>7;
- int constraint_set1_flag=u(1,buf,StartBit);//(buf[1] & 0x40)>>6;
- int constraint_set2_flag=u(1,buf,StartBit);//(buf[1] & 0x20)>>5;
- int constraint_set3_flag=u(1,buf,StartBit);//(buf[1] & 0x10)>>4;
- int reserved_zero_4bits=u(4,buf,StartBit);
- int level_idc=u(8,buf,StartBit);
- int seq_parameter_set_id=Ue(buf,nLen,StartBit);
- if( profile_idc == 100 || profile_idc == 110 ||
- profile_idc == 122 || profile_idc == 144 )
- {
- int chroma_format_idc=Ue(buf,nLen,StartBit);
- if( chroma_format_idc == 3 )
- int residual_colour_transform_flag=u(1,buf,StartBit);
- int bit_depth_luma_minus8=Ue(buf,nLen,StartBit);
- int bit_depth_chroma_minus8=Ue(buf,nLen,StartBit);
- int qpprime_y_zero_transform_bypass_flag=u(1,buf,StartBit);
- int seq_scaling_matrix_present_flag=u(1,buf,StartBit);
- int seq_scaling_list_present_flag[8];
- if( seq_scaling_matrix_present_flag )
- {
- for( int i = 0; i < 8; i++ ) {
- seq_scaling_list_present_flag[i]=u(1,buf,StartBit);
- }
- }
- }
- int log2_max_frame_num_minus4=Ue(buf,nLen,StartBit);
- int pic_order_cnt_type=Ue(buf,nLen,StartBit);
- if( pic_order_cnt_type == 0 )
- int log2_max_pic_order_cnt_lsb_minus4=Ue(buf,nLen,StartBit);
- else if( pic_order_cnt_type == 1 )
- {
- int delta_pic_order_always_zero_flag=u(1,buf,StartBit);
- int offset_for_non_ref_pic=Se(buf,nLen,StartBit);
- int offset_for_top_to_bottom_field=Se(buf,nLen,StartBit);
- int num_ref_frames_in_pic_order_cnt_cycle=Ue(buf,nLen,StartBit);
- int *offset_for_ref_frame=new int[num_ref_frames_in_pic_order_cnt_cycle];
- for( int i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ )
- offset_for_ref_frame[i]=Se(buf,nLen,StartBit);
- delete [] offset_for_ref_frame;
- }
- int num_ref_frames=Ue(buf,nLen,StartBit);
- int gaps_in_frame_num_value_allowed_flag=u(1,buf,StartBit);
- int pic_width_in_mbs_minus1=Ue(buf,nLen,StartBit);
- int pic_height_in_map_units_minus1=Ue(buf,nLen,StartBit);
- width=(pic_width_in_mbs_minus1+1)*16;
- height=(pic_height_in_map_units_minus1+1)*16;
- return true;
- }
- else
- return false;
- }
- 顶
- 21
- 踩
- 0
- 上一篇RTSP流媒体播放器实现
- 下一篇H264视频编码成MP4文件
- 猜你在找
- 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的编译与运行
这篇关于H264视频通过RTMP直播(神文)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!
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是什么头文件?