live555源码分析(四)RTSPServer分析
live555源码分析系列
live555源码分析(一)live555初体验
live555源码分析(二)基本组件上
live555源码分析(三)基本组件下
live555源码分析(四)RTSPServer分析
live555源码分析(五)DESCRIBE请求的处理
live555源码分析(六)SETUP和PLAY请求的处理
live555源码分析(七)播放过程
live555源码分析(八)多播
live555源码分析(四)RTSPServer分析
文章目录
- live555源码分析(四)RTSPServer分析
- 一、一个简单的Rtsp服务器
- 二、源码分析
- 2.1 RTSPServer的构造
- 2.2 客户端连接
- 2.3 客户端请求处理过程
一、一个简单的Rtsp服务器
这是一个基于live555的RTSP服务器,此RTSP服务器实现了H.264文件的单播
#include <liveMedia.hh>
#include <BasicUsageEnvironment.hh>
#include <GroupsockHelper.hh>static char const* inputFileName = "test.h264";int main(int argc, char* argv[])
{/* 创建调度器 */TaskScheduler* scheduler = BasicTaskScheduler::createNew();UsageEnvironment* env = BasicUsageEnvironment::createNew(*scheduler);/* 创建rtsp服务器 */RTSPServer* rtspServer = RTSPServer::createNew(*env, 8554);if (rtspServer == NULL){*env << "Failed to create RTSP server: " << env->getResultMsg() << "\n";return -1;}/* 创建会话 */ServerMediaSession* sms = ServerMediaSession::createNew(*env, "live", "test", "test");/* 添加子会话 */sms->addSubsession(H264VideoFileServerMediaSubsession::createNew(*env, inputFileName, True));/* 向服务器添加会话 */rtspServer->addServerMediaSession(sms);char* url = rtspServer->rtspURL(sms);*env << "Play this stream using the URL \"" << url << "\"\n";delete[] url;/* 循环处理事件 */env->taskScheduler().doEventLoop();return 0;
}
将此程序保存为h264_rtsp_server.cpp
执行下面的Makefile,可以得到rtspServer
,运行rtspServer
,会打印一个url,在vlc输入url,即可看到视频
下面将基于这个程序来讲解
二、源码分析
2.1 RTSPServer的构造
我们从创建RTSPServer
开始分析
RTSPServer::createNew
会创建一个TCP套接字,绑定好指定的端口,作为RTSP服务器的监听套接字,然后会生成RTSPServer
RTSPServer*
RTSPServer::createNew(UsageEnvironment& env, Port ourPort,UserAuthenticationDatabase* authDatabase,unsigned reclamationSeconds) {int ourSocket = setUpOurSocket(env, ourPort);if (ourSocket == -1) return NULL;return new RTSPServer(env, ourSocket, ourPort, authDatabase, reclamationSeconds);
}
RTSPServer
继承于GenericMediaServer
,我们先看GenericMediaServer
的构造函数
GenericMediaServer
::GenericMediaServer(UsageEnvironment& env, int ourSocket, Port ourPort,unsigned reclamationSeconds) {env.taskScheduler().turnOnBackgroundReadHandling(fServerSocket, incomingConnectionHandler, this);
}
该构造函数会把服务器的套接字加入事件循中,接收客户端请求
看一看incomingConnectionHandler
是如何处理客户端连接的
void GenericMediaServer::incomingConnectionHandlerOnSocket(int serverSocket) {int clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &clientAddrLen);createNewClientConnection(clientSocket, clientAddr);
}
该函数会accept接收一个客户端,然后调用createNewClientConnection
创建一个客户端连接,createNewClientConnection
是一个虚函数,它在RTSPServer
中被重写
2.2 客户端连接
由上面可知,当从vlc输入url时,会向服务器发起连接,服务器会调用createNewClientConnection
创建一个客户端连接
createNewClientConnection
在RTSPServer
中被重写,其定义如下
GenericMediaServer::ClientConnection*
RTSPServer::createNewClientConnection(int clientSocket, struct sockaddr_in clientAddr) {return new RTSPClientConnection(*this, clientSocket, clientAddr);
}
可知它创建了一个RTSPClientConnection
,查看其定义
class RTSPClientConnection: public GenericMediaServer::ClientConnection {
protected:virtual void handleRequestBytes(int newBytesRead);virtual void handleCmd_OPTIONS();virtual void handleCmd_DESCRIBE();
};
RTSPClientConnection
继承于ClientConnection
,它定义了许多命令请求处理
接下来看RTSPClientConnection
如何构造
首先看ClientConnection
的构造
GenericMediaServer::ClientConnection
::ClientConnection(GenericMediaServer& ourServer, int clientSocket, struct sockaddr_in clientAddr): fOurServer(ourServer), fOurSocket(clientSocket), fClientAddr(clientAddr) {/* 添加到事件循环中 */envir().taskScheduler().setBackgroundHandling(fOurSocket, SOCKET_READABLE|SOCKET_EXCEPTION, incomingRequestHandler, this);
}
它将客户端连接套接字加入事件循环中,监听其可读或者异常
其处理函数为incomingRequestHandler
,查看其定义
void GenericMediaServer::ClientConnection::incomingRequestHandler() {int bytesRead = readSocket(envir(), fOurSocket, &fRequestBuffer[fRequestBytesAlreadySeen], fRequestBufferBytesLeft, dummy);handleRequestBytes(bytesRead);
}
incomingRequestHandler
先读取客户发送过来的信息,然后调用handleRequestBytes
处理,handleRequestBytes
是一个虚函数,在RTSPServer
中被重写
RTSPClientConnection
的构造函数没有太多内容这里就不分析了
2.3 客户端请求处理过程
接下来分析客户端的请求处理过程,首先先来看一个一般的交互过程
OPTIONS
C–>S
OPTIONS rtsp://192.168.31.115:8554/live RTSP/1.0\r\n CSeq: 2\r\n \r\n
S–>C
RTSP/1.0 200 OK\r\n CSeq: 2\r\n Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY\r\n \r\n
DESCRIBE
C–>S
DESCRIBE rtsp://192.168.31.115:8554/live RTSP/1.0\r\n CSeq: 3\r\n Accept: application/sdp\r\n \r\n
S–>C
RTSP/1.0 200 OK\r\n CSeq: 3\r\n Content-length: 146\r\n Content-type: application/sdp\r\n \r\nv=0\r\n o=- 91565340853 1 in IP4 192.168.31.115\r\n t=0 0\r\n a=contol:*\r\n m=video 0 RTP/AVP 96\r\n a=rtpmap:96 H264/90000\r\n a=framerate:25\r\n a=control:track0\r\n
SETUP
C–>S
SETUP rtsp://192.168.31.115:8554/live/track0 RTSP/1.0\r\n CSeq: 4\r\n Transport: RTP/AVP;unicast;client_port=54492-54493\r\n \r\n
S–>C
RTSP/1.0 200 OK\r\n CSeq: 4\r\n Transport: RTP/AVP;unicast;client_port=54492-54493;server_port=56400-56401\r\n Session: 66334873\r\n \r\n
PLAY
C–>S
PLAY rtsp://192.168.31.115:8554/live RTSP/1.0\r\n CSeq: 5\r\n Session: 66334873\r\n Range: npt=0.000-\r\n \r\n
S–>C
RTSP/1.0 200 OK\r\n CSeq: 5\r\n Range: npt=0.000-\r\n Session: 66334873; timeout=60\r\n \r\n
根据这个过程,来分析live555的处理过程
首先live555是解析请求,在RTSPClientConnection::handleRequestBytes
中定义,代码如下
void RTSPServer::RTSPClientConnection::handleRequestBytes(int newBytesRead) {Boolean parseSucceeded = parseRTSPRequestString((char*)fRequestBuffer, fLastCRLF+2 - fRequestBuffer,cmdName, sizeof cmdName,urlPreSuffix, sizeof urlPreSuffix,urlSuffix, sizeof urlSuffix,cseq, sizeof cseq,sessionIdStr, sizeof sessionIdStr,contentLength);if (strcmp(cmdName, "OPTIONS") == 0) {handleCmd_OPTIONS();} else if (strcmp(cmdName, "DESCRIBE") == 0) {handleCmd_DESCRIBE(urlPreSuffix, urlSuffix, (char const*)fRequestBuffer);} else if (strcmp(cmdName, "SETUP") == 0) {clientSession= (RTSPServer::RTSPClientSession*)fOurRTSPServer.createNewClientSessionWithId();clientSession->handleCmd_SETUP(...);} else if (strcmp(cmdName, "PLAY") {clientSession->handleCmd_withinSession(...);}send(fClientOutputSocket, (char const*)fResponseBuffer, strlen((char*)fResponseBuffer), 0);
}
首先会解析请求中的命令,序列号,url,是否已经有会话ID
然后根据不同的命令做相应的处理,注意的是在SETUP阶段,会创建一个客户端会话,然后利用它来处理命令,处理命令后会将结果放回给客户端
关于命令如何解析的,这里不做讲解,这就是一个字符串处理
先看一看handleCmd_OPTIONS
void RTSPServer::RTSPClientConnection::handleCmd_OPTIONS() {snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,"RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sPublic: %s\r\n\r\n",fCurrentCSeq, dateHeader(), fOurRTSPServer.allowedCommandNames());
}
handleCmd_OPTIONS
的处理非常简单,就是返回允许请求的方法
其他请求的处理过程较为复杂,将在后面的文章单独讲解,本文就到这里了
live555源码分析(四)RTSPServer分析相关推荐
- 39 网络相关函数(七)——live555源码阅读(四)网络
39 网络相关函数(七)--live555源码阅读(四)网络 39 网络相关函数(七)--live555源码阅读(四)网络 简介 14)readSocket从套接口读取数据 recv/recvfrom ...
- live555 源码分析:RTSPServer 组件结构
前面几篇文章分析了 live555 中 RTSP 的处理逻辑,RTSP 处理有关组件的处理逻辑有点复杂,本文就再来梳理一下它们之间的关系. live555 中 RTSP 处理有关组件关系如下图: 事件 ...
- live555 源码分析:RTSPServer
live555 使用 RTSP/RTP/RTCP 协议来实现流媒体的传输,其中使用 RTSP 来建立流媒体会话,并对流媒体会话进行控制.在 live555 中,通过类 RTSPServerSuppor ...
- live555 源码分析: PLAY 的处理
在 SETUP 请求之后,客户端会发起 PLAY 请求,以请求服务器开始传输音视频数据.在 PLAY 请求执行时,一定是已经执行过 SETUP 请求,建立好了客户端会话,因而会与其它要求客户端会话已经 ...
- live555 源码分析: SETUP 的处理
SETUP 请求在 RTSP 的整个工作流程中,用于建立流媒体会话.本文分析 live555 对 SETUP 请求的处理. 在 RTSPServer::RTSPClientConnection::ha ...
- live555源码分析(一)live555初体验
live555源码分析系列 live555源码分析(一)live555初体验 live555源码分析(二)基本组件上 live555源码分析(三)基本组件下 live555源码分析(四)RTSPSer ...
- live555 源码分析:播放启动
本文分析 live555 中,流媒体播放启动,数据开始通过 RTP/RTCP 传输的过程. 如我们在 live555 源码分析:子会话 SETUP 中看到的,一个流媒体子会话的播放启动,由 Strea ...
- live555 源码分析:子会话 SDP 行生成
如我们在前文 live555 源码分析:ServerMediaSession 中看到的,H264VideoFileServerMediaSubsession 的继承层次体系如下图: 在这个继承层次体系 ...
- live555 源码分析:ServerMediaSession
在 live555 中,用一个 ServerMediaSession 表示流媒体会话,它连接了 RTSPServer 和下层流媒体传输逻辑.ServerMediaSession 和 ServerMed ...
最新文章
- view,control,service,dao,model层的关系
- MyBatis 源码解读-environmentsElement()
- 3732: Network
- java swing 案例详解_《Java Swing图形界面开发与案例详解》PDF_IT教程网
- Java ForkJoin 框架初探
- hiho一下第91周《Events Arrangement》(前半部分)
- 用maya怎么做ak47_串串香应该怎么用配料才能做得好吃
- SQL基本语法总结(含SQL代码)
- Linux下通过ssh上传、下载文件或者文件夹
- Linux快捷键的使用
- PYTHON 顺丰快递分拣小程序-极简9行代码实现分拣
- openGauss数据库备份恢复指导手册
- 穿越技术火线,聆听内心声音——暨龙泉第三届IT禅修营
- 计算机usb接口标志什么意思,笔记本上USB接口的标识
- 怎么删除网络共享多余的计算机,win10系统删除网络共享中多余的计算机的图文教程...
- 如何进行AI换脸,AI换脸从 “0“ 到 “1” 详细教程 ——从配置环境开始
- JS 点击气泡卡片自身外的区域自动关闭的代码逻辑
- 话说丢帧率系列---帧间隙
- python中numpy数组的合并_基于Python中numpy数组的合并实例讲解
- 前端加载404(Not Found)问题常用的解决方法
热门文章
- Spark SQL上海摩拜共享单车数据分析
- python udp伪造ip_Python扭曲的简单UDP转发器。保留源IP?
- 第三篇:用SOUI能做什么?
- web渗透测试----5、暴力破解漏洞--(6)VNC密码破解
- Oracle日期周详解以及周开始结束时间计算
- 机器视觉_HALCON_快速向导_1.了解HALCON
- Docker Harbor
- android rom 刷机出现的错误
- 均值-中位数-众数-极差-中程数-方差-标准差-变异系数
- html超级玛丽游戏源码,超级玛丽HTML5源代码学习------(一)