live555源代碼簡介

文章出自:http://blog.csdn.net/imliujie/archive/2008/01/30/2072657.aspx

live555源代碼簡介
liveMedia項目的源代碼包括四個基本的庫,各種測試代碼以及IVE555 Media Server。

四個基本的庫分別是UsageEnvironment&TaskScheduler,groupsock,liveMedia,BasicUsageEnvironment。

UsageEnvironment 和TaskScheduler類用于事件的調度,實現異步讀取事件的句柄的設置以及錯誤信息的輸出。另外,還有一個HashTable類定義了一個通用的 hash表,其它代碼要用到這個表。這些都是抽象類,在應用程序中基于這些類實現自己的子類。

groupsock類是對網絡接口的封裝,用于收發數據包。正如名字本身,Groupsock主要是面向多播數據的收發的,它也同時支持單播數據的收發。Groupsock定義了兩個構造函數
??? Groupsock(UsageEnvironment& env, struct in_addr const& groupAddr,
????????????? Port port, u_int8_t ttl);
??? Groupsock(UsageEnvironment& env, struct in_addr const& groupAddr,
????????????? struct in_addr const& sourceFilterAddr,
????????????? Port port);
前 者是用于SIM(source-independent multicast)組,后者用于SSM(source-specific multicast)組。groupsock庫中的Helper例程提供了讀寫socket等函數,并且屏蔽了不同的操作系統之間的區別,這是在 GroupsockHelper.cpp文件中實現的。

liveMedia庫中有一系列類,基類是Medium,這些類針對不同的流媒體類型和編碼。

各種測試代碼在testProgram目錄下,比如openRTSP等,這些代碼有助于理解liveMedia的應用。

LIVE555 Media Server是一個純粹的RTSP服務器。支持多種格式的媒體文件:

????? * TS流文件,擴展名ts。
????? * PS流文件,擴展名mpg。
????? * MPEG-4視頻基本流文件,擴展名m4e。
????? * MP3文件,擴展名mp3。
????? * WAV文件(PCM),擴展名wav。
????? * AMR音頻文件,擴展名.amr。
????? * AAC文件,ADTS格式,擴展名aac。

用live555開發應用程序
基于liveMedia的程序,需要通過繼承UsageEnvironment抽象類和TaskScheduler抽象類,定義相應的類來處理事件調度,數據讀寫以及錯誤處理。live項目的源代碼里有這些類的一個實現,這就是“BasicUsageEnvironment”庫。 BasicUsageEnvironment主要是針對簡單的控制臺應用程序,利用select實現事件獲取和處理。這個庫利用Unix或者 Windows的控制臺作為輸入輸出,處于應用程序原形或者調試的目的,可以用這個庫用戶可以開發傳統的運行與控制臺的應用。

通過使用自定義的“UsageEnvironment”和“TaskScheduler”抽象類的子類,這些應用程序就可以在特定的環境中運行,不需要做過多的修改。需要指出的是在圖形環境(GUI toolkit)下,抽象類 TaskScheduler 的子類在實現 doEventLoop()的時候應該與圖形環境自己的事件處理框架集成。

先來熟悉在liveMedia庫中Source,Sink以及 Filter等概念。Sink就是消費數據的對象,比如把接收到的數據存儲到文件,這個文件就是一個Sink。Source就是生產數據的對象,比如通過 RTP讀取數據。數據流經過多個'source'和'sink's,下面是一個示例:

????? 'source1' -> 'source2' (a filter) -> 'source3' (a filter) -> 'sink'

從其它Source接收數據的source也叫做"filters"。Module是一個sink或者一個filter。

數據接收的終點是Sink類,MediaSink是所有Sink類的基類。MediaSink的定義如下:

class MediaSink: public Medium {
public:
??? static Boolean lookupByName(UsageEnvironment& env, char const* sinkName,
??????????????????????????????? MediaSink*& resultSink);

??? typedef void (afterPlayingFunc)(void* clientData);
??? Boolean startPlaying(MediaSource& source,
???????????????????????? afterPlayingFunc* afterFunc,
???????????????????????? void* afterClientData);
??? virtual void stopPlaying();

??? // Test for specific types of sink:
??? virtual Boolean isRTPSink() const;

??? FramedSource* source() const {return fSource;}

protected:
??? MediaSink(UsageEnvironment& env); // abstract base class
??? virtual ~MediaSink();

??? virtual Boolean sourceIsCompatibleWithUs(MediaSource& source);
??????? // called by startPlaying()
??? virtual Boolean continuePlaying() = 0;
??????? // called by startPlaying()

??? static void onSourceClosure(void* clientData);
??????? // should be called (on ourselves) by continuePlaying() when it
??????? // discovers that the source we're playing from has closed.

??? FramedSource* fSource;

private:
??? // redefined virtual functions:
??? virtual Boolean isSink() const;

private:
??? // The following fields are used when we're being played:
??? afterPlayingFunc* fAfterFunc;
??? void* fAfterClientData;
};

Sink 類實現對數據的處理是通過實現純虛函數continuePlaying(),通常情況下continuePlaying調用 fSource->getNextFrame來為Source設置數據緩沖區,處理數據的回調函數等,fSource是MediaSink的類型為 FramedSource*的類成員;

基于liveMedia的應用程序的控制流程如下:

應用程序是事件驅動的,使用如下方式的循環

????? while (1) {
????????? 通過查找讀網絡句柄的列表和延遲隊列(delay queue)來發現需要完成的任務
????????? 完成這個任務
????? }

對于每個sink,在進入這個循環之前,應用程序通常調用下面的方法來啟動需要做的生成任務:

????? someSinkObject->startPlaying();

任何時候,一個Module需要獲取數據都通過調用剛好在它之前的那個Module的FramedSource::getNextFrame()方法。這是通過純虛函數FramedSource:oGetNextFrame()實現的,每一個Source module都有相應的實現。

Each 'source' module's implementation of "doGetNextFrame()" works by arranging for an 'after getting' function to be called (from an event handler) when new data becomes available for the caller.

注意,任何應用程序都要處理從'sources'到'sinks'的數據流,但是并非每個這樣的數據流都與從網絡接口收發數據相對應。
比 如,一個服務器應用程序發送RTP數據包的時候用到一個或多個"RTPSink" modules。這些"RTPSink" modules以別的方式接收數據,通常是文件 "*Source" modules (e.g., to read data from a file), and, as a side effect, transmit RTP packets.

一個簡單的RTSP客戶端程序
在另一個文章里,給出了這個簡單的客戶端的程序的代碼,可以通過修改Makefile來裁剪liveMedia,使得這個客戶端最小化。此客戶端已經正常運行。

首先是OPTION
然后是DESCRIBE
????? 建立Media Session,調用的函數是 MediaSession::createNew,在文件liveMedia/MediaSession.cpp中實現。
????? 為這個Media Session建立RTPSource,這是通過調用 MediaSubsession::initiate來實現的的,這個方法在liveMedia/MediaSession.cpp中實現。
在然后是SETUP
最后是PLAY

rtp數據的句柄:MultiFramedRTPSource::networkReadHandler 在liveMedia/MultiFramedRTPSource.cpp中
rtcp數據處理的句柄:RTCPInstance::incomingReportHandler 在liveMedia/RTCP.cpp中

rtp數據處理的句柄的設置:MultiFramedRTPSource:oGetNextFrame 在liveMedia/MultiFramedRTPSource.cpp中, 被FileSink::continuePlaying調用在FileSink.cpp中.

rtcp數據處理的句柄設置fRTCPInstance = RTCPInstance::createNew 在/liveMedia/MediaSession.cpp中調用,
createNew調用了構造函數RTCPInstance::RTCPInstance,這個構造函數有如下調用
TaskScheduler::BackgroundHandlerProc* handler = (TaskScheduler::BackgroundHandlerProc*)&incomingReportHandler;??


*********************************************************************************************************************
通過分析live庫提供的例子程序OpenRTSP,可以清晰地了解客戶端接收來自網絡上媒體數據的過程。注意,RTP協議和RTCP協議接收的數據分別是視音頻數據和發送/接收狀況的相關信息,其中,RTP協議只負責接收數據,而RTCP協議除了接收服務器的消息之外,還要向服務器反饋。
A.??????? main函數流程
main(int argc,char *argv[])
{
1.??????????? 創建BasicTaskScheduler對象
2.??????????? 創建BisicUsageEnvironment對象
3.??????????? 分析argv參數,(最簡單的用法是:openRTSP rtsp://172.16.24.240/mpeg4video.mp4)以便在下面設置一些相關參數
4.??????????? 創建RTSPClient對象
5.??????????? 由RTSPClient對象向服務器發送OPTION消息并接受回應
6.??????????? 產生SDPDescription字符串(由RTSPClient對象向服務器發送DESCRIBE消息并接受回應,根據回應的信息產生SDPDescription字符串,其中包括視音頻數據的協議和解碼器類型)
7.??????????? 創建MediaSession對象(根據SDPDescription在MediaSession中創建和初始化MediaSubSession子會話對象)
8.??????????? while循環中配置所有子會話對象(為每個子會話創建RTPSource和RTCPInstance對象,并創建兩個GroupSock對象,分別對應 RTPSource和RTCPInstance對象,把在每個GroupSock對象中創建的socket描述符置入 BasicTaskScheduler::fReadSet中,RTPSource對象的創建的依據是SDPDescription,例如對于MPEG4 文件來說,視音頻RTPSource分別對應MPEG4ESVideoRTPSource和MPEG4GenericRTPSource對象。 RTCPInstance對象在構造函數中完成將Socket描述符、處理接收RTCP數據的函數 (RTCPInstance::incomingReportHandler)以及RTCPInstance本身三者綁定在一個 HandlerDescriptor對象中,并置入BasicTaskScheduler::fReadHandler中。完成綁定后會向服務器發送一條消息。)
9.??????????? 由RTSPClient對象向服務器發送SETUP消息并接受回應。
10.??????? while循環中為每個子會話創建接收器(FileSink對象),在FileSink對象中根據子會話的codec等屬性缺省產生記錄視音頻數據的文件名,視音頻文件名分別為:video-MP4V-ES-1和audio-MPEG4-GENERIC-2,無后綴名
11.??????? while循環中為每個子會話的視音頻數據裝配相應的接收函數,將每個子會話中的RTPSource中的GroupSock對象中的SOCKET描述符,置入BasicTaskScheduler::fReadSet中,并將描述符、處理接收RTP數據的函數 (MultiFramedRTPSource::networkReadHandler)以及RTPSource本身三者綁定在一個 HandlerDescriptor對象中,并置入BasicTaskScheduler::fReadHandler中,并將FileSink的緩沖區和包含寫入文件操作的一個函數指針配置給RTPSource對象,這個緩沖區將會在networkReadHandler中接收來自網絡的視音頻數據(分析和去掉RTP包頭的工作由RTPSource完成),而這個函數指針在networkReadHandler中被調用以完成將緩沖區中的數據寫入文件。
12.??????? 由RTSPClient對象向服務器發送PLAY消息并接受回應。
13.??????? 進入while循環,調用BasicTaskScheduler::SingleStep()函數接受數據,直到服務器發送TREADOWN消息給客戶端,客戶端接收到該消息后釋放資源,程序退出。

}

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

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

相關文章

并發無鎖隊列學習(單生產者單消費者模型)

1、引言 本文介紹單生產者單消費者模型的隊列。依據寫入隊列的內容是定長還是變長,分為單生產者單消費者定長隊列和單生產者單消費者變長隊列兩種。單生產者單消費者模型的隊列操作過程是不須要進行加鎖的。生產者通過寫索引控制入隊操作,消費者通過讀索…

ecshop 收貨人信息電話必填改為手機必填

首先通過在flow.dwt中,查找flow.php?stepconsignee中的關鍵字 consignee(結算中心)查找所在模板/Library/consignee.lbi 大概57行 把必填去掉,其次 在js/shopping_flow.js里邊注釋掉 if (Utils.isEmpty(frm.elements[‘tel’].v…

流媒體傳輸協議

1.流媒體( Streaming Media) 1.1流媒體概念 流媒體技術是網絡技術和多媒體技術發展到一定階段的產物。術語流媒體既可以指在網上傳輸連續時基媒體的流式技術,也可以指使用流式技術的連續時基媒體本身。在網上傳輸音頻、視頻等多媒體信息目前主要有兩種方式:下載和流…

關閉瀏覽器網頁觸發事件_淺析瀏覽器渲染和 script 加載

前言前端代碼離不開瀏覽器環境,理解 js、css 代碼如何在瀏覽器中工作是非常重要的。如何優化渲染過程中的回流,重繪?script 腳本在頁面中是怎么個加載順序?了解這些對前端性能優化起著非常大的作用。借著這篇文章,讓自…

Open vSwitch實驗常用命令

1. 基本架構 ovs-vsctl: 管理ovsdb-server的配置,提供OVSDB的配置方法,包括創建和刪除網橋、端口等; ovs-ofctl: 提供ovs-vswitchd的流表配置方法; ovs-dpctl: 配置OVS內核模塊,提供緩存流表的操作方法&#xff1b…

記IOS8中碰到的一個JS bug

IOS8的JS版本過低導致 var id "123"; var temp1 {id, "left": "200"}; // error in IOS8 var temp2 {"id":id, "left": "200"};平時還是多寫ES5的代碼,es6的語法總能碰到兼容的坑。 改了好幾天。…

Emmet的html語法

Emmet的html語法 所有操作按下“tab”鍵即可瞬間完成 元素 1.在編輯器中輸入元素名稱,即可自動補全生成 HTML 標簽,即使不是標準的 HTML 標簽。 2.輸入:! 或者 html:5 或者 html:4s 或者 html:4t 將自動補全html基本結構 嵌套操作 1.使用…

RTP Payload Format for H.264 Video

H.264 RTP協議的封裝格式rfc3984 英文原版:http://tools.ietf.org/html/rfc3984 部分中文翻譯: H.264 視頻 RTP 負載格式 1. 網絡抽象層單元類型 (NALU) NAL單元1字節包頭負載 NALU 頭由一個字節組成, 它的語法如下: —————|0|1|2|3|4|5|6|7|------…

js字符串、數組和數字常用方法總結

https://github.com/AnHyun/blog/issues/3 一、string 常用方法: 1.substring(start開始位置的索引,end結束位置索引) 截取的位置不包含結束位置的字符,只寫一個參數表示從開始位置截取到最后,輸入負值時將負值變為0,哪個較小作為開始位置 va…

Oracle 存儲過程錯誤之PLS-00201: 必須聲明標識符

轉自:http://blog.csdn.net/u010678947/article/details/20702149 錯誤: ORA-06550: 第 1 行, 第 7 列: PLS-00201: 必須聲明標識符ZUO.PROCE_TESTORA-06550: 第 1 行, 第 7 列: PL/SQL: Statement ignored 解決方法: (1&#x…

mysql中如何把兩個查詢結果列數不同并成一張表_MySQL

引言本文整理了MySQL相關的知識,方便以后查閱。 基礎架構下圖是 MySQL 的一個簡要架構圖,從下圖你可以很清晰的看到用戶的 SQL 語句在 MySQL 內部是如何執行的。 先簡單介紹一下下圖涉及的一些組件的基本作用幫助大家理解這幅圖。 - 連接器: …

JavaWeb筆記01-XML

今日內容 XML 概念語法解析 XML: 概念: Extensible Markup Language 可擴展標記語言 可擴展:標簽都是自定義的.<user><student> 功能 存儲數據 配置文件在網絡中傳輸 一個故事 由于瀏覽器之間的競爭,導致HTML發展的十分不順利 用戶:唉,這怎么報錯了呢?…

centos下如何使用sendmail發送郵件

最近在實施服務端日志監控腳本&#xff0c;需要對異常情況發送郵件通知相關責任人&#xff0c;記錄下centos通過sendmail發送郵件的配置過程。一. 安裝sendmail和mailx1、安裝sendmail&#xff1a;1): centos下可以安裝命令:yum install -y sendmail service sendmail start yu…

H.263 H.263+ Payload Type

h263 rtp協議封裝協議英文版&#xff1a;rfc4629:http://tools.ietf.org/html/rfc4629 以下文章是部分參考翻譯&#xff1a; 文章出處&#xff1a; http://blog.csdn.net/zblue78/archive/2009/04/09/4059414.aspxGeneral H.263 Payload Header The H.263 payload header is s…

OC 中 load 方法和 initialize 方法的異同

(void)load; 當類對象被引入項目時, runtime 會向每一個類對象發送 load 消息load 方法會在每一個類甚至分類被引入時僅調用一次,調用的順序:父類優先于子類, 子類優先于分類load 方法不會被類自動繼承 (void)initialize; 也是在第一次使用這個類的時候會調用這個方法 轉載于:h…

scrapy框架_Python學習之Scrapy框架

爬蟲界江湖地位No.1說起Python&#xff0c;不得不說到它的爬蟲應用&#xff0c;由于Python的短小精悍&#xff0c;用它來開發爬蟲應用是最合適不過了&#xff0c;基于Python抓取網頁的庫有很多&#xff0c;例如requests,beatifulsoup等等&#xff0c;但是要說到有哪一個框架&am…

JavaWeb筆記03-Servlet

今日內容 ServletHTTP協議Request Servlet 概念 步驟 執行原理 生命周期 Servlet3.0注解配置 Servlet的體系結構 Servlet – 接口 GenericServlet – 抽象類:將Servlet接口中其他方法做了默認空實現,只將service()方法作為抽象 將來定義Servlet類時候,可以繼承Generic…

Android開發中無處不在的設計模式——動態代理模式

繼續更新設計模式系列。寫這個模式的主要原因是近期看到了動態代理的代碼。 先來回想一下前5個模式&#xff1a; - Android開發中無處不在的設計模式——單例模式 - Android開發中無處不在的設計模式——Builder模式 - Android開發中無處不在的設計模式——觀察者模式 - A…

用于MPEG-4視聽流的RTP負載格式

MPEG-4的rtp協議封裝英文原版 RFC 3016&#xff1a;http://www.rfc-editor.org/rfc/rfc3016.txt中文翻譯&#xff1a;組織&#xff1a;中國互動出版網&#xff08;http://www.china-pub.com/&#xff09;RFC文檔中文翻譯計劃&#xff08;http://www.china-pub.com/compters/emo…

pycharm python 模板配置_windows下pycharm安裝、創建文件、配置默認模板

本文為大家分享了windows下pycharm安裝、創建文件、配置默認模板的具體步驟&#xff0c;供大家參考&#xff0c;具體內容如下步驟&#xff1a;下包 —->安裝——>創建文件—->定制模板一、下包官方地址這里有企業版和社區版&#xff0c;老司機都知道社區版是免費的&am…