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创建一个客户端连接

createNewClientConnectionRTSPServer中被重写,其定义如下

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分析相关推荐

  1. 39 网络相关函数(七)——live555源码阅读(四)网络

    39 网络相关函数(七)--live555源码阅读(四)网络 39 网络相关函数(七)--live555源码阅读(四)网络 简介 14)readSocket从套接口读取数据 recv/recvfrom ...

  2. live555 源码分析:RTSPServer 组件结构

    前面几篇文章分析了 live555 中 RTSP 的处理逻辑,RTSP 处理有关组件的处理逻辑有点复杂,本文就再来梳理一下它们之间的关系. live555 中 RTSP 处理有关组件关系如下图: 事件 ...

  3. live555 源码分析:RTSPServer

    live555 使用 RTSP/RTP/RTCP 协议来实现流媒体的传输,其中使用 RTSP 来建立流媒体会话,并对流媒体会话进行控制.在 live555 中,通过类 RTSPServerSuppor ...

  4. live555 源码分析: PLAY 的处理

    在 SETUP 请求之后,客户端会发起 PLAY 请求,以请求服务器开始传输音视频数据.在 PLAY 请求执行时,一定是已经执行过 SETUP 请求,建立好了客户端会话,因而会与其它要求客户端会话已经 ...

  5. live555 源码分析: SETUP 的处理

    SETUP 请求在 RTSP 的整个工作流程中,用于建立流媒体会话.本文分析 live555 对 SETUP 请求的处理. 在 RTSPServer::RTSPClientConnection::ha ...

  6. live555源码分析(一)live555初体验

    live555源码分析系列 live555源码分析(一)live555初体验 live555源码分析(二)基本组件上 live555源码分析(三)基本组件下 live555源码分析(四)RTSPSer ...

  7. live555 源码分析:播放启动

    本文分析 live555 中,流媒体播放启动,数据开始通过 RTP/RTCP 传输的过程. 如我们在 live555 源码分析:子会话 SETUP 中看到的,一个流媒体子会话的播放启动,由 Strea ...

  8. live555 源码分析:子会话 SDP 行生成

    如我们在前文 live555 源码分析:ServerMediaSession 中看到的,H264VideoFileServerMediaSubsession 的继承层次体系如下图: 在这个继承层次体系 ...

  9. live555 源码分析:ServerMediaSession

    在 live555 中,用一个 ServerMediaSession 表示流媒体会话,它连接了 RTSPServer 和下层流媒体传输逻辑.ServerMediaSession 和 ServerMed ...

最新文章

  1. view,control,service,dao,model层的关系
  2. MyBatis 源码解读-environmentsElement()
  3. 3732: Network
  4. java swing 案例详解_《Java Swing图形界面开发与案例详解》PDF_IT教程网
  5. Java ForkJoin 框架初探
  6. hiho一下第91周《Events Arrangement》(前半部分)
  7. 用maya怎么做ak47_串串香应该怎么用配料才能做得好吃
  8. SQL基本语法总结(含SQL代码)
  9. Linux下通过ssh上传、下载文件或者文件夹
  10. Linux快捷键的使用
  11. PYTHON 顺丰快递分拣小程序-极简9行代码实现分拣
  12. openGauss数据库备份恢复指导手册
  13. 穿越技术火线,聆听内心声音——暨龙泉第三届IT禅修营
  14. 计算机usb接口标志什么意思,笔记本上USB接口的标识
  15. 怎么删除网络共享多余的计算机,win10系统删除网络共享中多余的计算机的图文教程...
  16. 如何进行AI换脸,AI换脸从 “0“ 到 “1” 详细教程 ——从配置环境开始
  17. JS 点击气泡卡片自身外的区域自动关闭的代码逻辑
  18. 话说丢帧率系列---帧间隙
  19. python中numpy数组的合并_基于Python中numpy数组的合并实例讲解
  20. 前端加载404(Not Found)问题常用的解决方法

热门文章

  1. Spark SQL上海摩拜共享单车数据分析
  2. python udp伪造ip_Python扭曲的简单UDP转发器。保留源IP?
  3. 第三篇:用SOUI能做什么?
  4. web渗透测试----5、暴力破解漏洞--(6)VNC密码破解
  5. Oracle日期周详解以及周开始结束时间计算
  6. 机器视觉_HALCON_快速向导_1.了解HALCON
  7. Docker Harbor
  8. android rom 刷机出现的错误
  9. 均值-中位数-众数-极差-中程数-方差-标准差-变异系数
  10. html超级玛丽游戏源码,超级玛丽HTML5源代码学习------(一)