原博文地址

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

前面的文章中提到了通过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. classCRTMPStream
  2. {
  3. public:
  4. CRTMPStream(void);
  5. ~CRTMPStream(void);
  6. public:
  7. // 连接到RTMP Server
  8. boolConnect(constchar* url);
  9. // 断开连接
  10. voidClose();
  11. // 发送MetaData
  12. boolSendMetadata(LPRTMPMetadata lpMetaData);
  13. // 发送H264数据帧
  14. boolSendH264Packet(unsignedchar*data,unsignedintsize,boolbIsKeyFrame,unsignedintnTimeStamp);
  15. // 发送H264文件
  16. boolSendH264File(constchar*pFileName);
  17. //...
  18. }

调用示例:

[cpp]  view plain copy

  1. #include <stdio.h>
  2. #include "RTMPStream\RTMPStream.h"
  3. intmain(intargc,char* argv[])
  4. {
  5. CRTMPStream rtmpSender;
  6. boolbRet = rtmpSender.Connect("rtmp://192.168.1.104/live/test");
  7. rtmpSender.SendH264File("E:\\video\\test.264");
  8. rtmpSender.Close();
  9. }



通过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. #define FILEBUFSIZE (1024 * 1024 * 10)       //  10M
  13. // NALU单元
  14. typedefstruct_NaluUnit
  15. {
  16. inttype;
  17. intsize;
  18. unsigned char*data;
  19. }NaluUnit;
  20. typedefstruct_RTMPMetadata
  21. {
  22. // video, must be h264 type
  23. unsigned intnWidth;
  24. unsigned intnHeight;
  25. unsigned intnFrameRate;// fps
  26. unsigned intnVideoDataRate;// bps
  27. unsigned intnSpsLen;
  28. unsigned charSps[1024];
  29. unsigned intnPpsLen;
  30. unsigned charPps[1024];
  31. // audio, must be aac type
  32. boolbHasAudio;
  33. unsigned intnAudioSampleRate;
  34. unsigned intnAudioSampleSize;
  35. unsigned intnAudioChannels;
  36. charpAudioSpecCfg;
  37. unsigned intnAudioSpecCfgLen;
  38. } RTMPMetadata,*LPRTMPMetadata;
  39. classCRTMPStream
  40. {
  41. public:
  42. CRTMPStream(void);
  43. ~CRTMPStream(void);
  44. public:
  45. // 连接到RTMP Server
  46. boolConnect(constchar* url);
  47. // 断开连接
  48. voidClose();
  49. // 发送MetaData
  50. boolSendMetadata(LPRTMPMetadata lpMetaData);
  51. // 发送H264数据帧
  52. boolSendH264Packet(unsignedchar*data,unsignedintsize,boolbIsKeyFrame,unsignedintnTimeStamp);
  53. // 发送H264文件
  54. boolSendH264File(constchar*pFileName);
  55. private:
  56. // 送缓存中读取一个NALU包
  57. boolReadOneNaluFromBuf(NaluUnit &nalu);
  58. // 发送数据
  59. intSendPacket(unsignedintnPacketType,unsignedchar*data,unsignedintsize,unsignedintnTimestamp);
  60. private:
  61. RTMP* m_pRtmp;
  62. unsigned char* m_pFileBuf;
  63. unsigned intm_nFileBufSize;
  64. unsigned intm_nCurPos;
  65. };


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


附上SpsDecode.h文件:

[cpp]  view plain copy

  1. #include <stdio.h>
  2. #include <math.h>
  3. UINTUe(BYTE*pBuff,UINTnLen,UINT&nStartBit)
  4. {
  5. //计算0bit的个数
  6. UINTnZeroNum = 0;
  7. while(nStartBit < nLen * 8)
  8. {
  9. if(pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8)))//&:按位与,%取余
  10. {
  11. break;
  12. }
  13. nZeroNum++;
  14. nStartBit++;
  15. }
  16. nStartBit ++;
  17. //计算结果
  18. DWORDdwRet = 0;
  19. for(UINTi=0; i<nZeroNum; i++)
  20. {
  21. dwRet <<= 1;
  22. if(pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8)))
  23. {
  24. dwRet += 1;
  25. }
  26. nStartBit++;
  27. }
  28. return(1 << nZeroNum) - 1 + dwRet;
  29. }
  30. intSe(BYTE*pBuff,UINTnLen,UINT&nStartBit)
  31. {
  32. intUeVal=Ue(pBuff,nLen,nStartBit);
  33. doublek=UeVal;
  34. intnValue=ceil(k/2);//ceil函数:ceil函数的作用是求不小于给定实数的最小整数。ceil(2)=ceil(1.2)=cei(1.5)=2.00
  35. if(UeVal % 2==0)
  36. nValue=-nValue;
  37. returnnValue;
  38. }
  39. DWORDu(UINTBitCount,BYTE* buf,UINT&nStartBit)
  40. {
  41. DWORDdwRet = 0;
  42. for(UINTi=0; i<BitCount; i++)
  43. {
  44. dwRet <<= 1;
  45. if(buf[nStartBit / 8] & (0x80 >> (nStartBit % 8)))
  46. {
  47. dwRet += 1;
  48. }
  49. nStartBit++;
  50. }
  51. returndwRet;
  52. }
  53. boolh264_decode_sps(BYTE* buf,unsignedintnLen,int&width,int&height)
  54. {
  55. UINTStartBit=0;
  56. intforbidden_zero_bit=u(1,buf,StartBit);
  57. intnal_ref_idc=u(2,buf,StartBit);
  58. intnal_unit_type=u(5,buf,StartBit);
  59. if(nal_unit_type==7)
  60. {
  61. intprofile_idc=u(8,buf,StartBit);
  62. intconstraint_set0_flag=u(1,buf,StartBit);//(buf[1] & 0x80)>>7;
  63. intconstraint_set1_flag=u(1,buf,StartBit);//(buf[1] & 0x40)>>6;
  64. intconstraint_set2_flag=u(1,buf,StartBit);//(buf[1] & 0x20)>>5;
  65. intconstraint_set3_flag=u(1,buf,StartBit);//(buf[1] & 0x10)>>4;
  66. intreserved_zero_4bits=u(4,buf,StartBit);
  67. intlevel_idc=u(8,buf,StartBit);
  68. intseq_parameter_set_id=Ue(buf,nLen,StartBit);
  69. if( profile_idc == 100 || profile_idc == 110 ||
  70. profile_idc == 122 || profile_idc == 144 )
  71. {
  72. intchroma_format_idc=Ue(buf,nLen,StartBit);
  73. if( chroma_format_idc == 3 )
  74. intresidual_colour_transform_flag=u(1,buf,StartBit);
  75. intbit_depth_luma_minus8=Ue(buf,nLen,StartBit);
  76. intbit_depth_chroma_minus8=Ue(buf,nLen,StartBit);
  77. intqpprime_y_zero_transform_bypass_flag=u(1,buf,StartBit);
  78. intseq_scaling_matrix_present_flag=u(1,buf,StartBit);
  79. intseq_scaling_list_present_flag[8];
  80. if( seq_scaling_matrix_present_flag )
  81. {
  82. for(inti = 0; i < 8; i++ ) {
  83. seq_scaling_list_present_flag[i]=u(1,buf,StartBit);
  84. }
  85. }
  86. }
  87. intlog2_max_frame_num_minus4=Ue(buf,nLen,StartBit);
  88. intpic_order_cnt_type=Ue(buf,nLen,StartBit);
  89. if( pic_order_cnt_type == 0 )
  90. intlog2_max_pic_order_cnt_lsb_minus4=Ue(buf,nLen,StartBit);
  91. elseif( pic_order_cnt_type == 1 )
  92. {
  93. intdelta_pic_order_always_zero_flag=u(1,buf,StartBit);
  94. intoffset_for_non_ref_pic=Se(buf,nLen,StartBit);
  95. intoffset_for_top_to_bottom_field=Se(buf,nLen,StartBit);
  96. intnum_ref_frames_in_pic_order_cnt_cycle=Ue(buf,nLen,StartBit);
  97. int*offset_for_ref_frame=newint[num_ref_frames_in_pic_order_cnt_cycle];
  98. for(inti = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ )
  99. offset_for_ref_frame[i]=Se(buf,nLen,StartBit);
  100. delete[] offset_for_ref_frame;
  101. }
  102. intnum_ref_frames=Ue(buf,nLen,StartBit);
  103. intgaps_in_frame_num_value_allowed_flag=u(1,buf,StartBit);
  104. intpic_width_in_mbs_minus1=Ue(buf,nLen,StartBit);
  105. intpic_height_in_map_units_minus1=Ue(buf,nLen,StartBit);
  106. width=(pic_width_in_mbs_minus1+1)*16;
  107. height=(pic_height_in_map_units_minus1+1)*16;
  108. returntrue;
  109. }
  110. else
  111. returnfalse;
  112. }


RTMP直播 浏览器通过jwplayer播放相关推荐

  1. C++ RTMP直播流播放器

    抛开flash,自己开发实现C++ RTMP直播流播放器 众所周知,RTMP是以flash为客户端播放器的直播协议,主要应用在B/S形式的场景中.本人研究并用C++开发实现了RTMP直播流协议的播放器 ...

  2. 浏览器不支持flash插件之后,h5播放rtmp直播流的解决方案

    浏览器不支持flash插件之后,h5播放rtmp直播流的解决方案使用http-flv 原文链接 目录: 相关资源: 背景 几种视频流比较 http-flv搭配flv.js播放方案 flv.js延迟问题 ...

  3. 如何实现web浏览器无插件播放视频监控直播?

    很多年前,监控视频的直播只能够进行单一的服务器传输,而如今,很多网站已经可以观看视频直播了,不过大多网站观看视频直播的时候还是需要下载插件,有时候就会碰到系统不兼容.版本不对应等问题,那么能不能实现w ...

  4. php七牛云rtmp直播推流,GitHub - jangocheng/FlutterQiniucloudLivePlugin: Flutter 七牛云直播云 推流/播放 SDK集成...

    flutter_qiniucloud_live_plugin Flutter 七牛云直播云插件,支持IOS.Android客户端 Getting Started 集成七牛云直播云推流.观看等功能 功能 ...

  5. java rtmp推流_视频直播生成推流和播放地址的Java代码示例

    概述 直播推流地址和播放地址本身没有API接口,需要在客户端自行拼接地址,然后使用推流工具或者播放器对其推流或播放.本文主要介绍如何生成直播的推流以及播放地址. 详细信息 视频直播生成推流和播放地址的 ...

  6. 用安卓RTMP直播推流进行音频侦听时,出现播放几秒后就无法播放问题的解决方法

    Real Time Messaging Protocol(RTMP)即实时消息传输协议,是 Adobe 公司开发的一个基于 TCP 的应用层协议,目前国内的视频云服务都是以 RTMP 为主要推流协议. ...

  7. RTMP 在浏览器端播放

    RTSP.RTMP 也有很多在说的.然而我就是总结下我最近在使用RTMP的理解. 首先说一下RTMP协议的定义, 实时消息协议(英语:Real-Time Messaging Protocol,缩写RT ...

  8. Vue 播放rtmp直播流

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 Vue 播放rtmp直播流 前言 一.vueVideo.vue封装 二.调用方式 前言 该组件是在vue-video-player基础 ...

  9. PLDroidPlayer 是 Pili 直播 SDK 的安卓播放器。支持所有直播常用的格式,如:RTMP、HLS、FLV。拥有优秀的功能和特性,如:首屏秒开、追帧优化、丰富的数据和状态回调、硬解软解

    PLDroidPlayer 是 Pili 直播 SDK 的安卓播放器.支持所有直播常用的格式,如:RTMP.HLS.FLV.拥有优秀的功能和特性,如:首屏秒开.追帧优化.丰富的数据和状态回调.硬解软解 ...

最新文章

  1. 机器学习问题的十个实例【转】
  2. 深度学习 - 相关名词概念
  3. 博士大佬为机器学习总结的人工智能入门指南!
  4. 上传自动显示图片 代码
  5. Linux 上安装 appium
  6. Hystrix之外健壮微服务的新选择:Sentinel 发布首个生产版本 1
  7. JAVA_HOME系统环境变量
  8. linux ssh无需密码,linux下 ssh 实现无需密码的远程登陆
  9. ORA-28000: the account is locked
  10. 技术实践:教你用Python搭建gRPC服务
  11. 三年白干!程序员因违反《竞业协议》赔偿腾讯97.6万元,返还15.8万元
  12. 【jQuery笔记Part3】02-jQuery抖动效果
  13. 顺序链表,动态数组实现
  14. 最新sql 2008安装说明 以及 重设sql server 2008 R2的登录密码
  15. 布尔逻辑_了解Go中的布尔逻辑
  16. java基础——常用类
  17. 平生事,此时凝睇,谁会凭栏意!(4)
  18. linux环境下安装node
  19. 一本超越期待的 C++ 书——简评 Boost程序库完全开发指南 深入C++ 准 标准库
  20. 去中心化借贷协议Trister’s Lend全面内测并提交合约代码安全审计

热门文章

  1. 高等数值计算方法学习笔记第6章【解线性代数方程组的迭代方法(高维稀疏矩阵)】
  2. Cesium Label 被建筑物遮挡问题
  3. numpy.random 中rand和randn 函数的区别
  4. html hover效果下拉个框,CSS实现Hover下拉菜单的方法
  5. JAVAWEB NOTE 1
  6. 眼科疾病可视化分析报告/Pycharm爬虫/数据处理/csv/plt画图
  7. r9s可不可以升级到Android7,oppoR9s更新了假的安卓7.1
  8. 【我的Android进阶之旅】解决Android项目编译报错: Program type already present : com.xxx.xxxx.BuildConfig
  9. C语言学习—数组指针和指针数组的区别
  10. 计算机模拟装货,重型卡车货物驾驶模拟器