前面的文章中提到了通过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 plaincopy

  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 plaincopy

  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 plaincopy

  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 plaincopy

  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. }

其中,在编译过程中,需要导入rtmp对应的包和头文件,这个要自己从网上搜索下,可以参考这里http://download.csdn.net/detail/zhadenianqu/7462751

附上SpsDecode.h文件:

[cpp] view plaincopy

  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发送264到red5服务器的代码,darkdragonking亲测可用--《到H264视频通过RTMP直播》相关推荐

  1. 如何用python发送SMTP邮件(基于QQ邮箱)亲测可用

    第一步 首先我们要在QQ邮箱开通SMTP邮件,并生成授权码 设置->账户->生成授权码 通过绑定手机发送短信生成授权码,并保存授权码,一系列英文字母(等会要用) 第二步 确保自己的计算机名 ...

  2. H264视频通过RTMP直播 .

    前面的文章中提到了通过RTSP(Real Time Streaming Protocol)的方式来实现视频的直播,但RTSP方式的一个弊端是如果需要支持客户端通过网页来访问,就需要在在页面中嵌入一个A ...

  3. vue2.x 播放rtmp,hls,m3u8直播流教程,亲测可用

    网上教程挺多,但实际用起来会各种报错 大部分原因是依赖的包的版本问题,因此我这里附上亲测可用的版本; 跟着步骤一步一来就行了! step1: 在package.json文件下添加所有关于直播的依赖包, ...

  4. H264视频通过RTMP直播

    http://blog.csdn.net/firehood_/article/details/8783589 前面的文章中提到了通过RTSP(Real Time Streaming Protocol) ...

  5. rtmp/rtsp测试地址 2019/11/22日亲测可用

    今天找rtsp的测试地址发现很多都是过期的,在一堆网址里面只找到这几个可用的,需要的自取 rtmp://58.200.131.2:1935/livetv/gxtv   广西卫视,可用,但是比较卡 rt ...

  6. python定时导出已发送文件_Python链接数据库查询导出查询结果到Excel并定时发送邮件到指定邮箱,实现巡检功能(亲测可用!!!)...

    #python版本3.7 # -*- coding: utf-8 -*- """ Created on Wed Aug 1 11:35:17 2018 @author: ...

  7. Java实现的一个发送手机短信(亲测可用)

    原文地址:http://sms.webchinese.cn/api.shtml JAVA发送手机短信,流传有几种方法:(1)使用webservice接口发送手机短信,这个可以使用sina提供的webs ...

  8. SpringBoot集成Kafka集群并实现接收_发送消息操作_以及常见错误_亲测---Kafka工作笔记005

    1.注意这个过程中,很重要的是:版本,springboot的版本和spring-kafka的版本要对应起来. 2.我现在发现两个版本是没问题的,一会说明 3.还要注意yml资源文件,或者propert ...

  9. H5视频之RTMP、RTSP、HTTP协议流直播流测试地址

    转自https://blog.csdn.net/u014162133/article/details/81188410 一.RTMP.RTSP.HTTP协议 这三个协议都属于互联网 TCP/IP 五层 ...

最新文章

  1. 【复盘】小朋友的奇思妙想
  2. 分享Kali Linux 2016.2第48周镜像文件
  3. JavaScript页面校验
  4. Aroma's Search(暴力)
  5. 【SSM面向CRUD编程专栏 2】Spring相关API 数据源(连接池)的配置 注解开发 整合junit
  6. 有关asp.net技术的外文文献_医学科技论文写作中参考文献的标准格式及常见问题...
  7. python---之suplot和suplots的区别
  8. Oracle查询 rownum和rowid的区别
  9. java考试题精选30道(附答案)
  10. 工作流:一文让你学会使用flowable工作流
  11. EasyPlayer播放海康大华RTSP流时RTSPClient客户端连接兼容问题的解决
  12. 纯前端实现—用户注册登录界面
  13. Android异常 Eclipse编译应用时出现 com.android.dx.cf.iface.parseexception
  14. 不限专业和工作年限就能报考的证书有哪些?
  15. 管理QQ群,什么情况下适合用软件
  16. java:如何解决汉字在记事本中编译翻译后出现乱码
  17. 哲理短文-人生什么最重要
  18. 关于HML要玩物联网这件事 之 CC3200 TCP Client
  19. 大公司高级Android工程师技能要求
  20. VMware-ESXi、vCenter、vSphere Client、Datastorage部署

热门文章

  1. Java将字符串按照指定长度分割成字符串数组
  2. 华为nova5 pro鸿蒙,华为nova5 Pro简单上手:一款“不偏科”的真旗舰!
  3. python画黑白线条_Python实现手绘图效果实例分享
  4. navicat连不上mysql client does not support authentication protocol requested by server; consider upgrad
  5. java数组 插入,Java数组添加元素
  6. Arduino简单实例之四_PS2游戏摇杆
  7. Linux环境搭建:软件包的几种安装方式,环境变量的设置,防火墙,PHPWIND
  8. 0基础想入坑3d建模的小白,你真的了解建模了吗?
  9. Ubuntu用命令行打开网页的三种方法
  10. JavaScript 三目运算符 return不合语法