RTMP直播 浏览器通过jwplayer播放
原博文地址
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提供的接口如下。
- classCRTMPStream
- {
- public:
- CRTMPStream(void);
- ~CRTMPStream(void);
- public:
- // 连接到RTMP Server
- boolConnect(constchar* url);
- // 断开连接
- voidClose();
- // 发送MetaData
- boolSendMetadata(LPRTMPMetadata lpMetaData);
- // 发送H264数据帧
- boolSendH264Packet(unsignedchar*data,unsignedintsize,boolbIsKeyFrame,unsignedintnTimeStamp);
- // 发送H264文件
- boolSendH264File(constchar*pFileName);
- //...
- }
调用示例:
- #include <stdio.h>
- #include "RTMPStream\RTMPStream.h"
- intmain(intargc,char* argv[])
- {
- CRTMPStream rtmpSender;
- boolbRet = rtmpSender.Connect("rtmp://192.168.1.104/live/test");
- rtmpSender.SendH264File("E:\\video\\test.264");
- rtmpSender.Close();
- }
通过JwPlayer播放效果如下:
最后附上RTMPStream完整的代码:
- /********************************************************************
- 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单元
- typedefstruct_NaluUnit
- {
- inttype;
- intsize;
- unsigned char*data;
- }NaluUnit;
- typedefstruct_RTMPMetadata
- {
- // video, must be h264 type
- unsigned intnWidth;
- unsigned intnHeight;
- unsigned intnFrameRate;// fps
- unsigned intnVideoDataRate;// bps
- unsigned intnSpsLen;
- unsigned charSps[1024];
- unsigned intnPpsLen;
- unsigned charPps[1024];
- // audio, must be aac type
- boolbHasAudio;
- unsigned intnAudioSampleRate;
- unsigned intnAudioSampleSize;
- unsigned intnAudioChannels;
- charpAudioSpecCfg;
- unsigned intnAudioSpecCfgLen;
- } RTMPMetadata,*LPRTMPMetadata;
- classCRTMPStream
- {
- public:
- CRTMPStream(void);
- ~CRTMPStream(void);
- public:
- // 连接到RTMP Server
- boolConnect(constchar* url);
- // 断开连接
- voidClose();
- // 发送MetaData
- boolSendMetadata(LPRTMPMetadata lpMetaData);
- // 发送H264数据帧
- boolSendH264Packet(unsignedchar*data,unsignedintsize,boolbIsKeyFrame,unsignedintnTimeStamp);
- // 发送H264文件
- boolSendH264File(constchar*pFileName);
- private:
- // 送缓存中读取一个NALU包
- boolReadOneNaluFromBuf(NaluUnit &nalu);
- // 发送数据
- intSendPacket(unsignedintnPacketType,unsignedchar*data,unsignedintsize,unsignedintnTimestamp);
- private:
- RTMP* m_pRtmp;
- unsigned char* m_pFileBuf;
- unsigned intm_nFileBufSize;
- unsigned intm_nCurPos;
- };
- /********************************************************************
- 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,
- };
- intInitSockets()
- {
- #ifdef WIN32
- WORDversion;
- WSADATA wsaData;
- version = MAKEWORD(1, 1);
- return(WSAStartup(version, &wsaData) == 0);
- #else
- returnTRUE;
- #endif
- }
- inlinevoidCleanupSockets()
- {
- #ifdef WIN32
- WSACleanup();
- #endif
- }
- char* put_byte(char*output, uint8_t nVal )
- {
- output[0] = nVal;
- returnoutput+1;
- }
- char* put_be16(char*output, uint16_t nVal )
- {
- output[1] = nVal & 0xff;
- output[0] = nVal >> 8;
- returnoutput+2;
- }
- char* put_be24(char*output,uint32_t nVal )
- {
- output[2] = nVal & 0xff;
- output[1] = nVal >> 8;
- output[0] = nVal >> 16;
- returnoutput+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;
- returnoutput+4;
- }
- char* put_be64(char*output, uint64_t nVal )
- {
- output=put_be32( output, nVal >> 32 );
- output=put_be32( output, nVal );
- returnoutput;
- }
- char* put_amf_string(char*c,constchar*str )
- {
- uint16_t len = strlen( str );
- c=put_be16( c, len );
- memcpy(c,str,len);
- returnc+len;
- }
- char* put_amf_double(char*c,doubled )
- {
- *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];
- }
- returnc+8;
- }
- CRTMPStream::CRTMPStream(void):
- m_pRtmp(NULL),
- m_nFileBufSize(0),
- m_nCurPos(0)
- {
- m_pFileBuf = newunsignedchar[FILEBUFSIZE];
- memset(m_pFileBuf,0,FILEBUFSIZE);
- InitSockets();
- m_pRtmp = RTMP_Alloc();
- RTMP_Init(m_pRtmp);
- }
- CRTMPStream::~CRTMPStream(void)
- {
- Close();
- WSACleanup();
- delete[] m_pFileBuf;
- }
- boolCRTMPStream::Connect(constchar* url)
- {
- if(RTMP_SetupURL(m_pRtmp, (char*)url)<0)
- {
- returnFALSE;
- }
- RTMP_EnableWrite(m_pRtmp);
- if(RTMP_Connect(m_pRtmp, NULL)<0)
- {
- returnFALSE;
- }
- if(RTMP_ConnectStream(m_pRtmp,0)<0)
- {
- returnFALSE;
- }
- returnTRUE;
- }
- voidCRTMPStream::Close()
- {
- if(m_pRtmp)
- {
- RTMP_Close(m_pRtmp);
- RTMP_Free(m_pRtmp);
- m_pRtmp = NULL;
- }
- }
- intCRTMPStream::SendPacket(unsignedintnPacketType,unsignedchar*data,unsignedintsize,unsignedintnTimestamp)
- {
- if(m_pRtmp == NULL)
- {
- returnFALSE;
- }
- 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);
- intnRet = RTMP_SendPacket(m_pRtmp,&packet,0);
- RTMPPacket_Free(&packet);
- returnnRet;
- }
- boolCRTMPStream::SendMetadata(LPRTMPMetadata lpMetaData)
- {
- if(lpMetaData == NULL)
- {
- returnfalse;
- }
- charbody[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 );
- intindex = p-body;
- SendPacket(RTMP_PACKET_TYPE_INFO,(unsigned char*)body,p-body,0);
- inti = 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;
- returnSendPacket(RTMP_PACKET_TYPE_VIDEO,(unsignedchar*)body,i,0);
- }
- boolCRTMPStream::SendH264Packet(unsignedchar*data,unsignedintsize,boolbIsKeyFrame,unsignedintnTimeStamp)
- {
- if(data == NULL && size<11)
- {
- returnfalse;
- }
- unsigned char*body =newunsignedchar[size+9];
- inti = 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);
- boolbRet = SendPacket(RTMP_PACKET_TYPE_VIDEO,body,i+size,nTimeStamp);
- delete[] body;
- returnbRet;
- }
- boolCRTMPStream::SendH264File(constchar*pFileName)
- {
- if(pFileName == NULL)
- {
- returnFALSE;
- }
- 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(unsignedchar), 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,获取视频图像宽、高信息
- intwidth = 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 inttick = 0;
- while(ReadOneNaluFromBuf(naluUnit))
- {
- boolbKeyframe = (naluUnit.type == 0x05) ? TRUE : FALSE;
- // 发送H264数据帧
- SendH264Packet(naluUnit.data,naluUnit.size,bKeyframe,tick);
- msleep(40);
- tick +=40;
- }
- returnTRUE;
- }
- boolCRTMPStream::ReadOneNaluFromBuf(NaluUnit &nalu)
- {
- inti = m_nCurPos;
- while(i<m_nFileBufSize)
- {
- if(m_pFileBuf[i++] == 0x00 &&
- m_pFileBuf[i++] == 0x00 &&
- m_pFileBuf[i++] == 0x00 &&
- m_pFileBuf[i++] == 0x01
- )
- {
- intpos = 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;
- returnTRUE;
- }
- }
- returnFALSE;
- }
附上SpsDecode.h文件:
- #include <stdio.h>
- #include <math.h>
- UINTUe(BYTE*pBuff,UINTnLen,UINT&nStartBit)
- {
- //计算0bit的个数
- UINTnZeroNum = 0;
- while(nStartBit < nLen * 8)
- {
- if(pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8)))//&:按位与,%取余
- {
- break;
- }
- nZeroNum++;
- nStartBit++;
- }
- nStartBit ++;
- //计算结果
- DWORDdwRet = 0;
- for(UINTi=0; i<nZeroNum; i++)
- {
- dwRet <<= 1;
- if(pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8)))
- {
- dwRet += 1;
- }
- nStartBit++;
- }
- return(1 << nZeroNum) - 1 + dwRet;
- }
- intSe(BYTE*pBuff,UINTnLen,UINT&nStartBit)
- {
- intUeVal=Ue(pBuff,nLen,nStartBit);
- doublek=UeVal;
- intnValue=ceil(k/2);//ceil函数:ceil函数的作用是求不小于给定实数的最小整数。ceil(2)=ceil(1.2)=cei(1.5)=2.00
- if(UeVal % 2==0)
- nValue=-nValue;
- returnnValue;
- }
- DWORDu(UINTBitCount,BYTE* buf,UINT&nStartBit)
- {
- DWORDdwRet = 0;
- for(UINTi=0; i<BitCount; i++)
- {
- dwRet <<= 1;
- if(buf[nStartBit / 8] & (0x80 >> (nStartBit % 8)))
- {
- dwRet += 1;
- }
- nStartBit++;
- }
- returndwRet;
- }
- boolh264_decode_sps(BYTE* buf,unsignedintnLen,int&width,int&height)
- {
- UINTStartBit=0;
- intforbidden_zero_bit=u(1,buf,StartBit);
- intnal_ref_idc=u(2,buf,StartBit);
- intnal_unit_type=u(5,buf,StartBit);
- if(nal_unit_type==7)
- {
- intprofile_idc=u(8,buf,StartBit);
- intconstraint_set0_flag=u(1,buf,StartBit);//(buf[1] & 0x80)>>7;
- intconstraint_set1_flag=u(1,buf,StartBit);//(buf[1] & 0x40)>>6;
- intconstraint_set2_flag=u(1,buf,StartBit);//(buf[1] & 0x20)>>5;
- intconstraint_set3_flag=u(1,buf,StartBit);//(buf[1] & 0x10)>>4;
- intreserved_zero_4bits=u(4,buf,StartBit);
- intlevel_idc=u(8,buf,StartBit);
- intseq_parameter_set_id=Ue(buf,nLen,StartBit);
- if( profile_idc == 100 || profile_idc == 110 ||
- profile_idc == 122 || profile_idc == 144 )
- {
- intchroma_format_idc=Ue(buf,nLen,StartBit);
- if( chroma_format_idc == 3 )
- intresidual_colour_transform_flag=u(1,buf,StartBit);
- intbit_depth_luma_minus8=Ue(buf,nLen,StartBit);
- intbit_depth_chroma_minus8=Ue(buf,nLen,StartBit);
- intqpprime_y_zero_transform_bypass_flag=u(1,buf,StartBit);
- intseq_scaling_matrix_present_flag=u(1,buf,StartBit);
- intseq_scaling_list_present_flag[8];
- if( seq_scaling_matrix_present_flag )
- {
- for(inti = 0; i < 8; i++ ) {
- seq_scaling_list_present_flag[i]=u(1,buf,StartBit);
- }
- }
- }
- intlog2_max_frame_num_minus4=Ue(buf,nLen,StartBit);
- intpic_order_cnt_type=Ue(buf,nLen,StartBit);
- if( pic_order_cnt_type == 0 )
- intlog2_max_pic_order_cnt_lsb_minus4=Ue(buf,nLen,StartBit);
- elseif( pic_order_cnt_type == 1 )
- {
- intdelta_pic_order_always_zero_flag=u(1,buf,StartBit);
- intoffset_for_non_ref_pic=Se(buf,nLen,StartBit);
- intoffset_for_top_to_bottom_field=Se(buf,nLen,StartBit);
- intnum_ref_frames_in_pic_order_cnt_cycle=Ue(buf,nLen,StartBit);
- int*offset_for_ref_frame=newint[num_ref_frames_in_pic_order_cnt_cycle];
- for(inti = 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;
- }
- intnum_ref_frames=Ue(buf,nLen,StartBit);
- intgaps_in_frame_num_value_allowed_flag=u(1,buf,StartBit);
- intpic_width_in_mbs_minus1=Ue(buf,nLen,StartBit);
- intpic_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;
- returntrue;
- }
- else
- returnfalse;
- }
RTMP直播 浏览器通过jwplayer播放相关推荐
- C++ RTMP直播流播放器
抛开flash,自己开发实现C++ RTMP直播流播放器 众所周知,RTMP是以flash为客户端播放器的直播协议,主要应用在B/S形式的场景中.本人研究并用C++开发实现了RTMP直播流协议的播放器 ...
- 浏览器不支持flash插件之后,h5播放rtmp直播流的解决方案
浏览器不支持flash插件之后,h5播放rtmp直播流的解决方案使用http-flv 原文链接 目录: 相关资源: 背景 几种视频流比较 http-flv搭配flv.js播放方案 flv.js延迟问题 ...
- 如何实现web浏览器无插件播放视频监控直播?
很多年前,监控视频的直播只能够进行单一的服务器传输,而如今,很多网站已经可以观看视频直播了,不过大多网站观看视频直播的时候还是需要下载插件,有时候就会碰到系统不兼容.版本不对应等问题,那么能不能实现w ...
- php七牛云rtmp直播推流,GitHub - jangocheng/FlutterQiniucloudLivePlugin: Flutter 七牛云直播云 推流/播放 SDK集成...
flutter_qiniucloud_live_plugin Flutter 七牛云直播云插件,支持IOS.Android客户端 Getting Started 集成七牛云直播云推流.观看等功能 功能 ...
- java rtmp推流_视频直播生成推流和播放地址的Java代码示例
概述 直播推流地址和播放地址本身没有API接口,需要在客户端自行拼接地址,然后使用推流工具或者播放器对其推流或播放.本文主要介绍如何生成直播的推流以及播放地址. 详细信息 视频直播生成推流和播放地址的 ...
- 用安卓RTMP直播推流进行音频侦听时,出现播放几秒后就无法播放问题的解决方法
Real Time Messaging Protocol(RTMP)即实时消息传输协议,是 Adobe 公司开发的一个基于 TCP 的应用层协议,目前国内的视频云服务都是以 RTMP 为主要推流协议. ...
- RTMP 在浏览器端播放
RTSP.RTMP 也有很多在说的.然而我就是总结下我最近在使用RTMP的理解. 首先说一下RTMP协议的定义, 实时消息协议(英语:Real-Time Messaging Protocol,缩写RT ...
- Vue 播放rtmp直播流
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 Vue 播放rtmp直播流 前言 一.vueVideo.vue封装 二.调用方式 前言 该组件是在vue-video-player基础 ...
- PLDroidPlayer 是 Pili 直播 SDK 的安卓播放器。支持所有直播常用的格式,如:RTMP、HLS、FLV。拥有优秀的功能和特性,如:首屏秒开、追帧优化、丰富的数据和状态回调、硬解软解
PLDroidPlayer 是 Pili 直播 SDK 的安卓播放器.支持所有直播常用的格式,如:RTMP.HLS.FLV.拥有优秀的功能和特性,如:首屏秒开.追帧优化.丰富的数据和状态回调.硬解软解 ...
最新文章
- 机器学习问题的十个实例【转】
- 深度学习 - 相关名词概念
- 博士大佬为机器学习总结的人工智能入门指南!
- 上传自动显示图片 代码
- Linux 上安装 appium
- Hystrix之外健壮微服务的新选择:Sentinel 发布首个生产版本 1
- JAVA_HOME系统环境变量
- linux ssh无需密码,linux下 ssh 实现无需密码的远程登陆
- ORA-28000: the account is locked
- 技术实践:教你用Python搭建gRPC服务
- 三年白干!程序员因违反《竞业协议》赔偿腾讯97.6万元,返还15.8万元
- 【jQuery笔记Part3】02-jQuery抖动效果
- 顺序链表,动态数组实现
- 最新sql 2008安装说明 以及 重设sql server 2008 R2的登录密码
- 布尔逻辑_了解Go中的布尔逻辑
- java基础——常用类
- 平生事,此时凝睇,谁会凭栏意!(4)
- linux环境下安装node
- 一本超越期待的 C++ 书——简评 Boost程序库完全开发指南 深入C++ 准 标准库
- 去中心化借贷协议Trister’s Lend全面内测并提交合约代码安全审计
热门文章
- 高等数值计算方法学习笔记第6章【解线性代数方程组的迭代方法(高维稀疏矩阵)】
- Cesium Label 被建筑物遮挡问题
- numpy.random 中rand和randn 函数的区别
- html hover效果下拉个框,CSS实现Hover下拉菜单的方法
- JAVAWEB NOTE 1
- 眼科疾病可视化分析报告/Pycharm爬虫/数据处理/csv/plt画图
- r9s可不可以升级到Android7,oppoR9s更新了假的安卓7.1
- 【我的Android进阶之旅】解决Android项目编译报错: Program type already present : com.xxx.xxxx.BuildConfig
- C语言学习—数组指针和指针数组的区别
- 计算机模拟装货,重型卡车货物驾驶模拟器