当前位置: 首页 > news >正文

网站建设为中心邢台市桥西住房建设局网站

网站建设为中心,邢台市桥西住房建设局网站,做网站一年大概的盈利,wordpress可视化编辑失效RTP在和h264 RTP在和h265 RTP载荷AAC live555关于RTSP协议交互流程 live555的核心数据结构值之闭环双向链表 live555 rtsp服务器实战之createNewStreamSource 概要 rtsp在交互的过程中用到很多协议:tcp,udp,rtp,rtcp,sdp等协议#xff1b;该篇文章主要分析在live555中这些… RTP在和h264 RTP在和h265 RTP载荷AAC live555关于RTSP协议交互流程 live555的核心数据结构值之闭环双向链表 live555 rtsp服务器实战之createNewStreamSource 概要 rtsp在交互的过程中用到很多协议:tcp,udp,rtp,rtcp,sdp等协议该篇文章主要分析在live555中这些协议是什么时候被创建的什么时候被使用的等协议相关流程。 TCP服务器与客户端进行协商(OPTION DESCRIBE SETUP PLAY) UDP/TCP协议是rtsp服务器用来想客户端推流当然rtsp向客户端推流也可以使用tcp协议那么就rtsp而言使用udp推流和使用tcp推流有什么区别呢 UDP推流 tcp连接进行rtsp信令交互 创建新的udp套接字来发送rtp包 创建新的udp套接字来发送rtcp包 TCP推流 tcp连接进行rtsp信令交互 复用rtsp的tcp连接发送rtp和rtcp包 嵌入式开发一般使用udp推流实时性相对较高 RTP对视频流(h264/h265)/音频流(AAC/MP3)裸流进行封装用于网络传输 RTCP服务器和客户端用来管理流媒体协议 TCP交互协商 在程序创建RTSPServer类对象时就会创建用于信令协商的TCP协议见如下代码 //创建RTSPServer类对象 RTSPServer* rtspServer RTSPServer::createNew(*env, 8554, authDB); //createNew实现 RTSPServer* RTSPServer::createNew(UsageEnvironment env, Port ourPort,UserAuthenticationDatabase* authDatabase,unsigned reclamationSeconds) {int ourSocketIPv4 setUpOurSocket(env, ourPort, AF_INET);int ourSocketIPv6 setUpOurSocket(env, ourPort, AF_INET6);if (ourSocketIPv4 0 ourSocketIPv6 0) return NULL;return new RTSPServer(env, ourSocketIPv4, ourSocketIPv6, ourPort, authDatabase, reclamationSeconds); } 从源码可以看出创建RTSPServer类对象的时候会创建ipv4和ipv6两种套接字,因此理论上来说live555实现的rtsp服务器支持ipv4和ipv6两种网络传输。 //RTSPServer构造函数 RTSPServer::RTSPServer(UsageEnvironment env,int ourSocketIPv4, int ourSocketIPv6, Port ourPort,UserAuthenticationDatabase* authDatabase,unsigned reclamationSeconds): GenericMediaServer(env, ourSocketIPv4, ourSocketIPv6, ourPort, reclamationSeconds),fHTTPServerSocketIPv4(-1), fHTTPServerSocketIPv6(-1), fHTTPServerPort(0),fClientConnectionsForHTTPTunneling(NULL), // will get created if neededfTCPStreamingDatabase(HashTable::create(ONE_WORD_HASH_KEYS)),fPendingRegisterOrDeregisterRequests(HashTable::create(ONE_WORD_HASH_KEYS)),fRegisterOrDeregisterRequestCounter(0), fAuthDB(authDatabase),fAllowStreamingRTPOverTCP(True),fOurConnectionsUseTLS(False), fWeServeSRTP(False) { } //GenericMediaServer构造函数 GenericMediaServer ::GenericMediaServer(UsageEnvironment env, int ourSocketIPv4, int ourSocketIPv6, Port ourPort,unsigned reclamationSeconds): Medium(env),fServerSocketIPv4(ourSocketIPv4), fServerSocketIPv6(ourSocketIPv6),fServerPort(ourPort), fReclamationSeconds(reclamationSeconds),fServerMediaSessions(HashTable::create(STRING_HASH_KEYS)),fClientConnections(HashTable::create(ONE_WORD_HASH_KEYS)),fClientSessions(HashTable::create(STRING_HASH_KEYS)),fPreviousClientSessionId(0),fTLSCertificateFileName(NULL), fTLSPrivateKeyFileName(NULL) {ignoreSigPipeOnSocket(fServerSocketIPv4); // so that clients on the same host that are killed dont also kill usignoreSigPipeOnSocket(fServerSocketIPv6); // ditto// Arrange to handle connections from others:env.taskScheduler().turnOnBackgroundReadHandling(fServerSocketIPv4, incomingConnectionHandlerIPv4, this);env.taskScheduler().turnOnBackgroundReadHandling(fServerSocketIPv6, incomingConnectionHandlerIPv6, this); } 在GenericMediaServer构造函数中会把创建的fServerSocketIPv4和fServerSocketIPv6这两个套接字插入到双向闭环链表中等待doEventLoop循环处理对应的处理函数分别为incomingConnectionHandlerIPv4 incomingConnectionHandlerIPv6最终都会调用incomingConnectionHandlerOnSocket函数 void GenericMediaServer::incomingConnectionHandlerOnSocket(int serverSocket) {struct sockaddr_storage clientAddr;SOCKLEN_T clientAddrLen sizeof clientAddr;int clientSocket accept(serverSocket, (struct sockaddr*)clientAddr, clientAddrLen);if (clientSocket 0) {int err envir().getErrno();if (err ! EWOULDBLOCK) {envir().setResultErrMsg(accept() failed: );}return;}ignoreSigPipeOnSocket(clientSocket); // so that clients on the same host that are killed dont also kill usmakeSocketNonBlocking(clientSocket);increaseSendBufferTo(envir(), clientSocket, 50*1024);#ifdef DEBUGenvir() accept()ed connection from AddressString(clientAddr).val() \n; #endif// Create a new object for handling this connection:(void)createNewClientConnection(clientSocket, clientAddr); } //createNewClientConnection函数实现 GenericMediaServer::ClientConnection* RTSPServer::createNewClientConnection(int clientSocket, struct sockaddr_storage const clientAddr) {return new RTSPClientConnection(*this, clientSocket, clientAddr, fOurConnectionsUseTLS); } 在doEventLoop循环中会议中accept监视tcp连接如果有客户端连接就会创建客户端连接类RTSPClientConnection最终会把客户端套接字clientSocket传递给ClientConnection构造函数 GenericMediaServer::ClientConnection ::ClientConnection(GenericMediaServer ourServer,int clientSocket, struct sockaddr_storage const clientAddr,Boolean useTLS): fOurServer(ourServer), fOurSocket(clientSocket), fClientAddr(clientAddr), fTLS(envir()) {fInputTLS fOutputTLS fTLS;// Add ourself to our client connections table:fOurServer.fClientConnections-Add((char const*)this, this);if (useTLS) {// Perform extra processing to handle a TLS connection:fTLS.setCertificateAndPrivateKeyFileNames(ourServer.fTLSCertificateFileName,ourServer.fTLSPrivateKeyFileName);fTLS.isNeeded True;fTLS.tlsAcceptIsNeeded True; // call fTLS.accept() the next time the socket is readable}// Arrange to handle incoming requests:resetRequestBuffer();envir().taskScheduler().setBackgroundHandling(fOurSocket, SOCKET_READABLE|SOCKET_EXCEPTION, incomingRequestHandler, this); } //incomingRequestHandler函数最终调用 void GenericMediaServer::ClientConnection::incomingRequestHandler() {if (fInputTLS-tlsAcceptIsNeeded) { // we need to successfully call fInputTLS-accept() first:if (fInputTLS-accept(fOurSocket) 0) return; // either an error, or we need to try again laterfInputTLS-tlsAcceptIsNeeded False;// We can now read data, as usual:}int bytesRead;if (fInputTLS-isNeeded) {bytesRead fInputTLS-read(fRequestBuffer[fRequestBytesAlreadySeen], fRequestBufferBytesLeft);} else {struct sockaddr_storage dummy; // from address, meaningless in this casebytesRead readSocket(envir(), fOurSocket, fRequestBuffer[fRequestBytesAlreadySeen], fRequestBufferBytesLeft, dummy);}handleRequestBytes(bytesRead);//该函数实现了对 OPTION DESCRIBE SETUP等各种信令的处理逻辑 } 在构造函数中setBackgroundHandling会把客户端套接字fOurSocket和对应的处理函数incomingRequestHandler添加到闭环双链表中在doEventLoop中循环遍历客户端有信令交互就调用相关的处理函数至此用于协商的TCP协议处理流程就结束了。 关于live555的闭环双向链表参考我的另一篇文章live555的核心数据结构值之闭环双向链表-CSDN博客 UDP流媒体传输 UDP流媒体传输服务器需要创建两个四个UDP套接字用于传输音频RTP音频RTCP视频RTP视频RTCP该文档是以H264的传输为例所以只介绍视频RTP端口视频RTCP端口的创建过程音频类似 RTP,RTCP端口是在SETUP信令处理函数handleCmd_SETUP中被创建该函数最终调用了getStreamParameters函数: subsession-getStreamParameters(fOurSessionId, fOurClientConnection-fClientAddr,clientRTPPort, clientRTCPPort,fStreamStates[trackNum].tcpSocketNum, rtpChannelId, rtcpChannelId,fOurClientConnection-fTLS,destinationAddress, destinationTTL, fIsMulticast,serverRTPPort, serverRTCPPort,fStreamStates[trackNum].streamToken); 该函数将客户端的RTP端口clientRTPPort和RTCP端口clientRTCPPort都进行了处理这两个端口是客户端发送SETUP信令时携带的消息告诉服务器RTP RTCP包改往哪里发getStreamParameters也创建了服务器的RTP RTCP端口serverRTPPort, serverRTCPPort getStreamParameters内部调用了createGroupsock函数: void OnDemandServerMediaSubsession ::getStreamParameters(...) {...if (clientRTPPort.num() ! 0 || tcpSocketNum 0){ // Normal case: Create destinationsportNumBits serverPortNum;if (clientRTCPPort.num() 0){// Were streaming raw UDP (not RTP). Create a single groupsock:NoReuse dummy(envir()); // ensures that we skip over ports that are already in usefor (serverPortNum fInitialPortNum;; serverPortNum){serverRTPPort serverPortNum;rtpGroupsock createGroupsock(nullAddress(destinationAddress.ss_family), serverRTPPort);if (rtpGroupsock-socketNum() 0)break; // success}udpSink BasicUDPSink::createNew(envir(), rtpGroupsock);}else{// Normal case: Were streaming RTP (over UDP or TCP). Create a pair of// groupsocks (RTP and RTCP), with adjacent port numbers (RTP port number even).// (If were multiplexing RTCP and RTP over the same port number, it can be odd or even.)NoReuse dummy(envir()); // ensures that we skip over ports that are already in usefor (portNumBits serverPortNum fInitialPortNum;; serverPortNum){serverRTPPort serverPortNum;//创建RTP端口(rtp的UDP套接字)rtpGroupsock createGroupsock(nullAddress(destinationAddress.ss_family), serverRTPPort);if (rtpGroupsock-socketNum() 0){delete rtpGroupsock;continue; // try again}if (fMultiplexRTCPWithRTP){// Use the RTP groupsock object for RTCP as well:serverRTCPPort serverRTPPort;rtcpGroupsock rtpGroupsock;}else{// Create a separate groupsock object (with the next (odd) port number) for RTCP://RTCP端口号在RTP端口号的基础上加1serverRTCPPort serverPortNum;//创建RTCP端口(rtcp的UDP套接字)rtcpGroupsock createGroupsock(nullAddress(destinationAddress.ss_family), serverRTCPPort);if (rtcpGroupsock-socketNum() 0){delete rtpGroupsock;delete rtcpGroupsock;continue; // try again}}break; // success}unsigned char rtpPayloadType 96 trackNumber() - 1; // if dynamicrtpSink mediaSource NULL ? NULL: createNewRTPSink(rtpGroupsock, rtpPayloadType, mediaSource);if (rtpSink ! NULL){if (fParentSession-streamingUsesSRTP){rtpSink-setupForSRTP(fMIKEYStateMessage, fMIKEYStateMessageSize);}if (rtpSink-estimatedBitrate() 0)streamBitrate rtpSink-estimatedBitrate();}}... }由代码可以看出serverRTPPort的初始值是fInitialPortNum而fInitialPortNum在创建OnDemandServerMediaSubsession对象时有个默认值6970如果没有设置端口号则使用默认端口号 上面代码可以看出而RTCP端口号是在RTP的端口号的基础上加1 OnDemandServerMediaSubsession(UsageEnvironment env, Boolean reuseFirstSource,portNumBits initialPortNum 6970,Boolean multiplexRTCPWithRTP False); 当第二个客户端连接时依然是从6970开始创建所需的RTP RTCP端口号但是createGroupsock会发现6970 6971端口号被占用于是返回-1继续for循环将端口号累加 for (portNumBits serverPortNum fInitialPortNum;; serverPortNum){serverRTPPort serverPortNum;rtpGroupsock createGroupsock(nullAddress(destinationAddress.ss_family), serverRTPPort);if (rtpGroupsock-socketNum() 0){delete rtpGroupsock;continue; // try again}...} //fInitialPortNum为基数6970 第一个客户端rtp:6970 rtcp:6971 第二个客户端6970 6971 被占用createGroupsock返回-1因此for循环continue继续累加serverPortNum rtp:6972 rtcp:6973 ...... 那么怎么自定义端口号呢 我们在做rtsp服务器的时候都会创建一个类用于实现createNewStreamSource虚函数该类继承于OnDemandServerMediaSubsession而类的构造函数里会执行OnDemandServerMediaSubsession的构造函数所以如果你想要自己定义服务器的RTP端口号只需在执行OnDemandServerMediaSubsession构造函数是传入参数即可 H264LiveVideoServerMediaSubssion::H264LiveVideoServerMediaSubssion(UsageEnvironment env, Boolean reuseFirstSource): OnDemandServerMediaSubsession(env, reuseFirstSource, 1234) {} TCP流媒体传输使用的时信令交互的套接字这里不做解释关于流媒体裸流怎么打包成RTP的参考上面的文章 该文章在持续更新望持续关注
http://www.ho-use.cn/article/10814081.html

相关文章:

  • 浙江网站制作网站建设的一般过程包括哪些内容
  • 睿艺美开封做网站店名注册查询
  • 沧州市网站制作公司视频网站建设审批
  • 学做网站论坛学校网站建设项目需求报告
  • 景区网站建设方案 费用wordpress queryposts
  • 建设信用卡秒批网站安徽汽车网网站建设
  • 保定网站建设的过程163k地方门户网站系统
  • 网站上的验证码怎么做的网络运营商自动选择
  • 机构编制网站建设天水网站开发技术招聘
  • 做服务的网站吗三星网上商城官网
  • 免费打开网站东莞网站平台费用
  • 全网推广方案关键词seo
  • 网站建设框架编写目的建立英语
  • 有名的网站深圳网站建设定制开发
  • 找别人做网站的注意事项学校建立网站
  • 中建八局第一建设公司网站网站弹出
  • 哪里建网站便宜wordpress建站访问提示不安全
  • 企业介绍微网站怎么做的六数字域名做网站好不好
  • 房子装修网站公司免费邮箱如何注册
  • 中国最大的中文网站沈阳建设工程信息网 最佳中项网
  • 如何建设红色旅游网站公司网站建设需要注意哪些问题
  • 网站建设工作的函找设计网站公司
  • 企业网站建设的研究开发方法及技术路线专业做网站的软件
  • 建筑企业资质查询网站苏州企业宣传片制作公司
  • 微网站与微信的关系wordpress页面关联目录
  • ppt模板免费下载哪个网站好河南商务网站建设
  • 做网站公司需要帮客户承担广告法吗规范网站建设
  • 宁乡网站开发公司推荐360网站卫士代备案流程
  • 烟台网站建设 烟台网亿网络品牌建设找晓哥
  • 仿唧唧帝笑话门户网站源码带多条采集规则 织梦搞笑图片视频模板wordpress服务器如何使用