Live555-RTSP服務器

RTSP Server創建

RTSP服務器初始化:

RTSPServer::createNew->new RTSPServer::RTSPServer->GenericMediaServer::GenericMediaServer->turnOnBackgroundReadHandling(IPV4sock/IPV6sock,incomingConnectionHandlerIPv4)

如上流程,創建RTSP服務器對象時,初始化了IPV4和IPV6的監聽套接字;同時注冊了套接字可讀事件,設置回調incomingConnectionHandlerIPv4,

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 don't 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);
}

RTSPClientConnection又構造基類GenericMediaServer::ClientConnection對象;在基類的構造函數中調用setBackgroundHandling函數注冊連接套接字的可讀和異常事件,并設置回調函數ClientConnection::incomingRequestHandler;

當服務器接收到新連接時函數調用路徑:

incomingConnectionHandlerOnSocket->RTSPServer::createNewClientConnection->new RTSPClientConnection->GenericMediaServer::ClientConnection->setBackgroundHandling(incomingRequestHandler)

產生新連接時回調incomingConnectionHandlerOnSocket,處理連接套接字的初始化,并調用RTSPServer::createNewClientConnection創建一個RTSPClientConnection連接對象管理這個連接;并設置了回調函數incomingRequestHandler;

當連接接收到消息時:

incomingRequestHandler->handleRequestBytes

連接收到消息時會回調incomingRequestHandler函數,incomingRequestHandler函數讀取數據之后會調用handleRequestBytes函數對數據進行解析,然后調用相應的setup/opation命令進行處理恢復;

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);
}void RTSPServer::RTSPClientConnection::handleRequestBytes(int newBytesRead) {int numBytesRemaining = 0;++fRecursionCount; // 防止在處理中刪除自身do {// 1. 檢查輸入數據有效性// 2. 處理Base64解碼(如果使用HTTP隧道)// 3. 查找消息結束標記// 4. 解析請求(RTSP或HTTP)// 5. 根據命令類型處理// 6. 發送響應// 7. 處理剩余數據(管道化請求)} while (numBytesRemaining > 0);--fRecursionCount;// 檢查是否需要關閉連接或刪除自身if (!fIsActive && fScheduledDelayedTask <= 0) {if (fRecursionCount > 0) closeSockets();else delete this;}
}

ServerMediaSession類


class ServerMediaSession: public Medium {
public:static ServerMediaSession* createNew(UsageEnvironment& env,char const* streamName = NULL,char const* info = NULL,char const* description = NULL,Boolean isSSM = False,char const* miscSDPLines = NULL);//通過名稱在全局介質注冊表中查找ServerMediaSession對象static Boolean lookupByName(UsageEnvironment& env,char const* mediumName,ServerMediaSession*& resultSession);//動態構建SDP描述文件:char* generateSDPDescription(int addressFamily); // based on the entire session// Note: The caller is responsible for freeing the returned string//獲取流名稱char const* streamName() const { return fStreamName; }//添加子會話,使用??鏈表結構??管理子會話,為每個子會話分配自動遞增的fTrackNumberBoolean addSubsession(ServerMediaSubsession* subsession);unsigned numSubsessions() const { return fSubsessionCounter; }void testScaleFactor(float& scale); // sets "scale" to the actual supported scalefloat duration() const;// a result == 0 means an unbounded session (the default)// a result < 0 means: subsession durations differ; the result is -(the largest).// a result > 0 means: this is the duration of a bounded sessionvirtual void noteLiveness();// called whenever a client - accessing this media - notes liveness.// The default implementation does nothing, but subclasses can redefine this - e.g., if you// want to remove long-unused "ServerMediaSession"s from the server.unsigned referenceCount() const { return fReferenceCount; }void incrementReferenceCount() { ++fReferenceCount; }void decrementReferenceCount() { if (fReferenceCount > 0) --fReferenceCount; }Boolean& deleteWhenUnreferenced() { return fDeleteWhenUnreferenced; }void deleteAllSubsessions();// Removes and deletes all subsessions added by "addSubsession()", returning us to an 'empty' state// Note: If you have already added this "ServerMediaSession" to a server then, before calling this function,//   you must first close any client connections that use it,//   by calling "GenericMediaServer::closeAllClientSessionsForServerMediaSession()".Boolean streamingUsesSRTP; // by default, FalseBoolean streamingIsEncrypted; // by default, Falseprotected://初始化成員變量,包括會話名稱、信息、描述等。如果沒有提供info或description,則使用庫名稱和版本號。記錄創建時間(用于SDP的o=行)。ServerMediaSession(UsageEnvironment& env, char const* streamName,char const* info, char const* description,Boolean isSSM, char const* miscSDPLines);// called only by "createNew()"virtual ~ServerMediaSession();private: // redefined virtual functionsvirtual Boolean isServerMediaSession() const;private:Boolean fIsSSM;// 是否SSM(源特定組播)// Linkage fields:friend class ServerMediaSubsessionIterator;ServerMediaSubsession* fSubsessionsHead;// 媒體子會話鏈表頭ServerMediaSubsession* fSubsessionsTail;// 鏈表尾unsigned fSubsessionCounter;char* fStreamName;// 會話名稱(如"liveVideo")char* fInfoSDPString;// SDP中的會話信息char* fDescriptionSDPString;// SDP中的描述信息char* fMiscSDPLines;// 自定義SDP參數struct timeval fCreationTime;unsigned fReferenceCount;Boolean fDeleteWhenUnreferenced;
};class ServerMediaSubsessionIterator {
public:ServerMediaSubsessionIterator(ServerMediaSession& session);virtual ~ServerMediaSubsessionIterator();ServerMediaSubsession* next(); // NULL if nonevoid reset();private:ServerMediaSession& fOurSession;ServerMediaSubsession* fNextPtr;
};//表示??單條媒體軌道??(如音頻流/視頻流),繼承關系:
class ServerMediaSubsession: public Medium {
public:unsigned trackNumber() const { return fTrackNumber; }char const* trackId();virtual char const* sdpLines(int addressFamily) = 0;virtual void getStreamParameters(unsigned clientSessionId, // instruct sockaddr_storage const& clientAddress, // inPort const& clientRTPPort, // inPort const& clientRTCPPort, // inint tcpSocketNum, // in (-1 means use UDP, not TCP)unsigned char rtpChannelId, // in (used if TCP)unsigned char rtcpChannelId, // in (used if TCP)TLSState* tlsState, // in (used if TCP)struct sockaddr_storage& destinationAddress, // in outu_int8_t& destinationTTL, // in outBoolean& isMulticast, // outPort& serverRTPPort, // outPort& serverRTCPPort, // outvoid*& streamToken // out) = 0;virtual void startStream(unsigned clientSessionId, void* streamToken,TaskFunc* rtcpRRHandler,void* rtcpRRHandlerClientData,unsigned short& rtpSeqNum,unsigned& rtpTimestamp,ServerRequestAlternativeByteHandler* serverRequestAlternativeByteHandler,void* serverRequestAlternativeByteHandlerClientData) = 0;virtual void pauseStream(unsigned clientSessionId, void* streamToken);virtual void seekStream(unsigned clientSessionId, void* streamToken, double& seekNPT,double streamDuration, u_int64_t& numBytes);// This routine is used to seek by relative (i.e., NPT) time.// "streamDuration", if >0.0, specifies how much data to stream, past "seekNPT".  (If <=0.0, all remaining data is streamed.)// "numBytes" returns the size (in bytes) of the data to be streamed, or 0 if unknown or unlimited.virtual void seekStream(unsigned clientSessionId, void* streamToken, char*& absStart, char*& absEnd);// This routine is used to seek by 'absolute' time.// "absStart" should be a string of the form "YYYYMMDDTHHMMSSZ" or "YYYYMMDDTHHMMSS.<frac>Z".// "absEnd" should be either NULL (for no end time), or a string of the same form as "absStart".// These strings may be modified in-place, or can be reassigned to a newly-allocated value (after delete[]ing the original).virtual void nullSeekStream(unsigned clientSessionId, void* streamToken,double streamEndTime, u_int64_t& numBytes);// Called whenever we're handling a "PLAY" command without a specified start time.virtual void setStreamScale(unsigned clientSessionId, void* streamToken, float scale);virtual float getCurrentNPT(void* streamToken);virtual FramedSource* getStreamSource(void* streamToken);virtual void getRTPSinkandRTCP(void* streamToken,RTPSink*& rtpSink, RTCPInstance*& rtcp) = 0;// Returns pointers to the "RTPSink" and "RTCPInstance" objects for "streamToken".// (This can be useful if you want to get the associated 'Groupsock' objects, for example.)// You must not delete these objects, or start/stop playing them; instead, that is done// using the "startStream()" and "deleteStream()" functions.virtual void deleteStream(unsigned clientSessionId, void*& streamToken);virtual void testScaleFactor(float& scale); // sets "scale" to the actual supported scalevirtual float duration() const;// returns 0 for an unbounded session (the default)// returns > 0 for a bounded sessionvirtual void getAbsoluteTimeRange(char*& absStartTime, char*& absEndTime) const;// Subclasses can reimplement this iff they support seeking by 'absolute' time.protected: // we're a virtual base classServerMediaSubsession(UsageEnvironment& env);virtual ~ServerMediaSubsession();char const* rangeSDPLine() const;// returns a string to be delete[]dServerMediaSession* fParentSession;u_int32_t fSRTP_ROC; // horrible hack for SRTP; when the ROC changes, regenerate the SDPprivate:friend class ServerMediaSession;friend class ServerMediaSubsessionIterator;ServerMediaSubsession* fNext;unsigned fTrackNumber; // within an enclosing ServerMediaSessionchar const* fTrackId;
};#endif

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/88676.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/88676.shtml
英文地址,請注明出處:http://en.pswp.cn/web/88676.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Redis Stack擴展功能

Redis JSONRedisJSON是Redis的一個擴展模塊&#xff0c;它提供了對JSON數據的原生支持。常用操作&#xff1a;-- 設置一個JSON數據JSON.SET user $ {"name":"loulan","age":18}## key是user&#xff0c;value就是一個JSON數據。其中$表示JSON數據…

Takebishi旗下智能硬件網關產品devicegateway詳細介紹

一、產品概述 DeviceGateway是由日本Takebishi公司研發的一款專業工業物聯網&#xff08;IIoT&#xff09;硬件網關產品&#xff0c;專為實現現場工業設備與云端平臺、IT系統之間的高效、安全數據傳輸而設計。作為一款可靠的硬件網關&#xff0c;DeviceGateway具有即插即用、穩…

單向鏈表反轉 如何實現

單向鏈表反轉的實現方法 ? https://www.zhihu.com/question/441865393/answer/3208578798 ? 單向鏈表反轉是數據結構中的經典問題&#xff0c;在面試和實際開發中經常遇到。以下是 多種實現方式&#xff08;包括遞歸和迭代&#xff09;&#xff0c;以 Go 語言為例。1. 單向鏈…

php+vue+Laravel音樂媒體播放及周邊產品運營平臺-nodejs-計算機畢業設計

目錄具體實現截圖課程項目技術路線開發技術介紹設計思路流程PHP核心代碼部分展示詳細視頻演示/源碼獲取##項目介紹網絡技術的廣泛應用顯著地推動了生活服務的信息化進程。結合音樂流媒體與周邊產品的運營需求&#xff0c;構建一套音樂媒體播放及周邊產品運營平臺&#xff0c;成…

Python爬蟲實戰:研究xlwt 和 xlrd 庫相關技術

1. 引言 1.1 研究背景與意義 隨著電子商務的快速發展,電商平臺積累了海量的商品數據。如何從這些數據中提取有價值的信息,為商家提供決策支持,成為電商領域的重要研究方向。傳統人工采集和分析數據的方式效率低下,且容易出現錯誤。自動化數據采集與分析系統能夠通過爬蟲技…

【QGC】深入解析 QGC 配置管理

引言 在軟件開發中&#xff0c;配置管理是一項至關重要的任務&#xff0c;它能幫助我們靈活地管理應用程序的各種參數和設置。QGroundControl&#xff08;QGC&#xff09;作為一款強大的開源無人機地面站軟件&#xff0c;其配置管理系統設計精巧&#xff0c;值得我們深入學習。…

ChatGPT,從規則到強化學習

要了解 ChatGPT&#xff08;Chat Generative Pre-training Transformer&#xff09;&#xff0c;我們不得不先看看 NLP 自然語言處理&#xff08;Natural Language Processing&#xff09;。因為 ChatGPT 屬于 NLP 領域&#xff0c;而 NLP 則又是人工智能的一個分支。 那么什么…

【目標檢測之Ultralytics預測框顏色修改】

在 Ultralytics YOLOv8 中修改預測框顏色為紅色&#xff0c;以下是三種實用方案&#xff1a;方案 1&#xff1a;直接修改 plot() 方法的 colors 參數 在調用 results.plot() 時直接指定顏色參數&#xff1a; from ultralytics import YOLO# 加載模型 model YOLO("yolov8n…

讓 VSCode 調試器像 PyCharm 一樣顯示 Tensor Shape、變量形狀、變量長度、維度信息

文章目錄&#x1f3af; 目標&#xff1a;在 VS Code 調試器中自動顯示這些變量信息&#x1f50d; 原理簡介?? 其他方案的局限性? 方案一&#xff1a;重寫 __repr__? 方案二&#xff1a;向 debugpy 注冊自定義變量顯示器&#xff08;StrPresentationProvider&#xff09;? …

pip國內鏡像源一覽

以下是2025年主流pip國內鏡像源完整清單及配置指南&#xff0c;綜合多個權威來源整理的最新數據&#xff1a;一、核心鏡像源推薦&#xff08;2025年穩定可用&#xff09;?阿里云鏡像?https://mirrors.aliyun.com/pypi/simple/優勢&#xff1a;依托阿里云CDN&#xff0c;全國平…

當大模型遇見毫米波:用Wi-Fi信號做“透視”的室內語義SLAM實踐——從CSI到神經輻射場的端到端開源方案

作者 | Blossom.118 2025-07-12 關鍵詞&#xff1a;CSI-SLAM、神經輻射場、毫米波、Transformer、數字孿生、開源 ---- 1. 為什么要“無攝像頭”語義SLAM&#xff1f; ? 隱私紅線&#xff1a;歐盟GDPR 2024修訂版把“攝像頭點云”列入高風險生物特征&#xff0c;落地成本高。…

脈沖神經網絡膜電位泄漏系數學習:開啟時空動態特征提取的新篇章

脈沖神經網絡膜電位泄漏系數學習&#xff1a;開啟時空動態特征提取的新篇章 摘要 脈沖神經網絡&#xff08;Spiking Neural Networks, SNNs&#xff09;作為第三代神經網絡模型&#xff0c;憑借其事件驅動、高生物逼真度和潛在的超低功耗特性&#xff0c;已成為類腦計算與高效人…

SSRF(ctfshow)

web351-358這部分的題目都是明文的&#xff0c;按照題目要求繞過就行了<?php error_reporting(0); highlight_file(__FILE__); $url$_POST[url]; $xparse_url($url); if($x[scheme]http||$x[scheme]https){ if(!preg_match(/localhost|127\.0\.|\。/i, $url)){ $chcurl_ini…

亞矩陣云手機:重構物流供應鏈,讓跨境包裹“飛”得更快更準

在跨境電商“時效即生命”的競爭中&#xff0c;物流信息滯后、清關效率低下、成本居高不下已成為商家最頭疼的“三座大山”。傳統模式下&#xff0c;人工更新物流狀態耗時易錯&#xff0c;跨境包裹常因清關延誤遭客戶投訴&#xff0c;而高昂的物流成本更直接吞噬利潤。亞矩陣云…

HTML(5) 代碼規范

HTML(5) 代碼規范 引言 HTML(HyperText Markup Language)是一種用于創建網頁的標準標記語言。HTML5 作為最新的 HTML 標準,自 2014 年正式發布以來,已經成為了構建現代網頁應用的基礎。本文將詳細介紹 HTML5 代碼規范,包括結構、語法、屬性以及最佳實踐等內容,旨在幫助…

【PTA數據結構 | C語言版】順序棧的3個操作

本專欄持續輸出數據結構題目集&#xff0c;歡迎訂閱。 文章目錄題目代碼題目 請編寫程序&#xff0c;將 n1 個整數順序壓入容量為 n 的棧&#xff0c;隨后執行 n1 次取頂并出棧的操作。 輸入格式&#xff1a; 輸入首先在第一行給出正整數 n&#xff08;≤10^4 &#xff09;&a…

使用Pycharm集成開發工具遠程調試部署在虛擬機上的flask項目:超級詳細的完整指南

本文將詳細介紹如何通過PyCharm Professional版遠程調試部署在虛擬機(這里以Ubuntu為例)中的Flask項目。這種開發方式特別適合需要在接近生產環境調試的場景。 虛擬機網絡配置 這里用到的是VMware的NAT&#xff0c;即網絡地址轉換模式&#xff0c;要保證你Linux虛擬機的IP&…

UE制作的 AI 交互數字人嵌入到 Vue 開發的信息系統中的方法和步驟

要將 UE(Unreal Engine,虛幻引擎)制作的 AI 交互數字人嵌入到 Vue 開發的信息系統首頁中運行,可以參考以下方法步驟以及涉及的軟件工具: 準備工作 軟件工具 Unreal Engine:用于創建和編輯 AI 交互數字人,需要在 UE 中完成數字人的建模、綁定骨骼、添加 AI 交互邏輯等工…

基于elementUI的el-autocomplete組件的自動補全下拉框實踐

<template><div :class"$options.name"><el-autocompletestyle"width: 100%"ref"autocomplete":popper-class"${$options.name}-el-autocomplete"v-model"inputSearchValue":placeholder"輸入關鍵詞...…

Gameplay - 獨立游戲Celeste的Player源碼

TGA2018最佳獨立游戲《蔚藍》的一些公開代碼&#xff1b;主要是Player部分的代碼&#xff1a;using System; using System.Collections; using System.Collections.Generic; using Monocle; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input;namespace Cel…