H264 流媒體 編碼彙總

實時傳輸協議(RTP)和實時控制協議(RTCP)

RTP是一種提供端對端傳輸服務的實時傳輸協議,用來支持在單目標廣播和多目標廣播網絡服務中傳輸實時數據,而實時數據的傳輸則由RTCP協議來監視和控制。

RTP定義在RFC

使用RTP協議的應用程序運行在RTP之上,而執行RTP的程序運行在UDP的上層,目的是爲了使用UDP的端口號和檢查和。如圖16-12所示,RTP可以看成是傳輸層的子層。由多媒體應用程序生成的聲音和電視數據塊被封裝在RTP信息包中,每個RTP信息包被封裝在UDP消息段中,然後再封裝在IP數據包中。

1889中。信息包的結構包含廣泛用於多媒體的若干個域,包括聲音點播(audio-on-demand)、影視點播(video ondemand)、因特網電話(Internettelephony)和電視會議(videoconferencing)。RTP的規格沒有對聲音和電視的壓縮格式制定標準,它可以被用來傳輸普通格式的文件。例如,WAV或者GSM(Global System forMobilecommunications)格式的聲音、MPEG-1和MPEG-2的電視,也可以用來傳輸專有格式存儲的聲音和電視文件。
 

TCP/IP模型

 

應用層(application)

傳輸層

RTP

 

UDP

 

IP

 

數據鏈路層(data link)

 

物理層(physical)

圖16-12 RTP是傳輸層上的協議

從應用開發人員的角度來看,可把RTP執行程序看成是應用程序的一部分,因爲開發人員必需把RTP集成到應用程序中。在發送端,開發人員必需把執行RTP協議的程序寫入到創建RTP信息包的應用程序中,然後應用程序把RTP信息包發送到UDP的套接接口(socketinterface),如圖16-13所示;同樣,在接收端,RTP信息包通過UDP套接接口輸入到應用程序,因此開發人員必需把執行RTP協議的程序寫入到從RTP信息包中抽出媒體數據的應用程序。

TCP/IP模型

 

應用層(application)

 

RTP

 

套接接口

UDP

 

IP

 

數據鏈路層(data link)

 

物理層(physical)

 

圖16-13 RTP和UDP之間的接口

現以用RTP傳輸聲音爲例來說明它的工作過程。假設音源的聲音是64kb/s的PCM編碼聲音,並假設應用程序取20毫秒的編碼數據爲一個數據塊(chunk),即在一個數據塊中有160個字節的聲音數據。應用程序需要爲這塊聲音數據添加RTP標題生成RTP信息包,這個標題包括聲音數據的類型、順序號和時間戳。然後RTP信息包被送到UDP套接接口,在那裏再被封裝在UDP信息包中。在接收端,應用程序從套接接口處接收RTP信息包,並從RTP信息包中抽出聲音數據塊,然後使用RTP信息包的標題域中的信息正確地譯碼和播放聲音。

如果應用程序不使用專有的方案來提供有效載荷類型(payloadtype)、順序號或者時間戳,而是使用標準的RTP協議,應用程序就更容易與其他的網絡應用程序配合運行,這是大家都希望的事情。例如,如果有兩個不同的公司都在開發因特網電話軟件,他們都把RTP合併到他們的產品中,這樣就有希望:使用不同公司電話軟件的用戶之間能夠進行通信。

這裏需要強調的是,RTP本身不提供任何機制來確保把數據及時遞送到接收端或者確保其他的服務質量,它也不擔保在遞送過程中不丟失信息包或者防止信息包的次序不被打亂。的確,RTP的封裝只是在系統端才能看到,中間的路由器並不區分那個IP數據報是運載RTP信息包的。

RTP允許給每個媒體源分配一個單獨的RTP信息包流,例如,攝像機或者麥克風。例如,有兩個團體參與的電視會議,這就可能打開4個信息包流:兩臺攝像機傳送電視流和兩個麥克風傳送聲音流。然而,許多流行的編碼技術,包括MPEG-1和MPEG-2在編碼過程中都把聲音和電視圖像捆綁在一起以形成單一的數據流,一個方向就生成一個RTP信息包流。

RTP信息包沒有被限制只可應用於單目標廣播,它們也可以在一對多(one-to-many)的多目標廣播樹或者在多對多(many-to-many)的多目標廣播樹上傳送。例如,多對多的多目標廣播,在這種應用場合下,所有發送端通常都把他們的RTP信息包流發送到具有相同多目標廣播地址的多目標廣播樹上。

16.6.2 RTP信息包標題域

RTP標題由4個信息包標題域和其他域組成:有效載荷類型(payload type)域,順序號(sequencenumber)域,時間戳(timestamp)域和同步源標識符(Synchronization SourceIdentifier)域等。RTP信息包的標題域的結構如下圖所示:

Payload

Type
(有效載荷類型)

Sequence Number

(順序號)

Timestamp

(時間戳)

Synchronization Source Identifier
(同步源標識符)

Miscellaneous Fields
(其他)

 

1. 有效載荷類型

RTP信息包中的有效載荷域(Payload TypeField)的長度爲7位,因此RTP可支持128種不同的有效載荷類型。對於聲音流,這個域用來指示聲音使用的編碼類型,例如PCM、自適應增量調製或線性預測編碼等等。如果發送端在會話或者廣播的中途決定改變編碼方法,發送端可通過這個域來通知接收端。表16-01列出了目前RTP所能支持的聲音有效載荷類型。

表16-01目前RTP所能支持的聲音有效載荷類型

有效載荷號

聲音類型

採樣率(kHz)

數據率(kb/s)

0

PCM mu-law

8

64

1

1016

8

4.8

2

G.721

8

32

3

GSM

8

32

6

DVI

16

64

7

LPC

8

2.4

9

G.722

8

48~64

14

MPEG Audio

90

-

15

G.728

8

16

對電視流,有效載荷類型可以用來指示電視編碼的類型,例如motion JPEG,MPEG-1,MPEG-2或者H.231等等。發送端也可以在會話或者期間隨時改變電視的編碼方法。表16-02列出了目前RTP所能支持的某些電視有效載荷類型。

表16-02目前RTP所能支持的聲音有效載荷類型

有效載荷號

電視格式

26

Motion JPEG

28

-

31

H.261

32

MPEG-1 video

33

MPEG-2 video

 

2. 順序號

順序號(Sequence NumberField)域的長度爲16位。每發送一個RTP信息包順序號就加1,接收端可以用它來檢查信息包是否有丟失以及按順序號處理信息包。例如,接收端的應用程序接收到一個RTP信息包流,這個RTP信息包在順序號86和89之間有一個間隔,接收端就知道信息包87和88已經丟失,並且採取措施來處理丟失的數據。

3. 時間戳

時間戳(Timestamp)域的長度爲32字節。它反映RTP數據信息包中第一個字節的採樣時刻(時間)。接收端可以利用這個時間戳來去除由網絡引起的信息包的抖動,並且在接收端爲播放提供同步功能。

4. 同步源標識符

同步源標識符(SynchronizationSourceIdentifier,SSRC)域的長度爲32位。它用來標識RTP信息包流的起源,在RTP會話或者期間的每個信息包流都有一個清楚的SSRC。SSRC不是發送端的IP地址,而是在新的信息包流開始時源端隨機分配的一個號碼。

16.6.3 實時傳輸控制協議

實時傳輸控制協議(Real-timeControl Protocol,RTCP)也定義在1996年提出的RFC1889中。多媒體網絡應用把RTCP和RTP一起使用,尤其是在多目標廣播中更具吸引力。當從一個或者多個發送端向多個接收端廣播聲音或者電視時,也就是在RTP會話期間,每個參與者週期性地向所有其他參與者發送RTCP控制信息包,如圖16-14所示。RTCP用來監視服務質量和傳送有關與會者的信息。對於RTP會話或者廣播,通常使用單個多目標廣播地址,屬於這個會話的所有RTP和RTCP信息包都使用這個多目標廣播地址,通過使用不同的端口號可把RTP信息包和RTCP信息包區分開來。

RTCP的主要功能是爲應用程序提供會話質量或者廣播性能質量的信息。每個RTCP信息包不封裝聲音數據或者電視數據,而是封裝發送端和/或者接收端的統計報表。這些信息包括髮送的信息包數目、丟失的信息包數目和信息包的抖動等情況,這些反饋信息對發送端、接收端或者網絡管理員都是很有用的。RTCP規格沒有指定應用程序應該使用這個反饋信息做什麼,這完全取決於應用程序開發人員。例如,發送端可以根據反饋信息來修改傳輸速率,接收端可以根據反饋信息判斷問題是本地的、區域性的還是全球性的,網絡管理員也可以使用RTCP信息包中的信息來評估網絡用於多目標廣播的性能。

16.6.4 實時流放協議

實時流放協議(Real-Time StreamingProtocol,RTSP)是一個剛開始開發的協議,它的設想描述在RFC

播放的數據流被分成許多信息包,信息包的大小很適用於客戶機和服務器之間的帶寬。當客戶機已經接收到足夠多的信息包之後,用戶軟件就可開始播放一個信息包,同時對另一個信息包解壓縮和接收第三個信息包。這樣用戶就不需要把整個媒體文件從服務器上下載之後就可立即播放。廣播源可以是現場的數據流也可以是存儲的數據流。

RTSP協議想要提供控制多種應用數據傳送的功能,提供一種選擇傳送通道的方法,例如UDP, TCP,IP多目標廣播通道,以及提供一種基於RTP協議的遞送方法。正在設計的RTSP將工作在RTP的上層,用來控制和傳送實時的內容。

RTSP能夠與資源保留協議一起使用,用來設置和管理保留帶寬的流式會話或者廣播。

2326文件中。RTSP是應用級的實時流放協議,它主要目標是爲單目標廣播和多目標廣播上的流式多媒體應用提供牢靠的播放性能,以及支持不同廠家提供的客戶機和服務機之間的協同工作能力。



在windows使用vs2008編譯live555

在windows使用vs2008編譯live555
1.live555 源代碼簡介
liveMedia項目的源代碼包括四個基本的庫,各種測試代碼以及IVE555 Media Server。

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

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

groupsock類是對網絡接口的封裝,用於收發數據包。正如名字本身,Groupsock主要是面向多播數據的收發的,它也同時支持單播數據的收發。Groupsock定義了兩個構造函數
 
 Groupsock(UsageEnvironment& env, struct in_addrconst& groupAddr,
           Port port,u_int8_t ttl);
   Groupsock(UsageEnvironment& env, struct in_addrconst& groupAddr,
           structin_addr const& sourceFilterAddr,
           Portport);
前者是用於SIM(source-independent multicast)組,後者用於SSM(source-specificmulticast)組。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。
2.在windows下編譯live555
  (1).下載 live555,http://www.live555.com/
    (2). 編輯win32config,TOOLS32=C:\Program Files\Microsoft Visual Studio9.0\VC
       即保證這個路徑是你的Vs2008路徑。
    (3). 編輯"LINK_OPTS_0 =$(linkdebug) msvcirt.lib" in win32config to "LINK_OPTS_0 =$(linkdebug) msvcrt.lib",由於編譯器所要LINK的運行庫不一樣了
    (4).修改groupsock/makefile.head,替換"INCLUDES = -Iinclude-I../UsageEnvironment/include" 爲"INCLUDES = -Iinclude-I../UsageEnvironment/include -DNO_STRSTREAM".
    (5).運行genWindowsMakefiles.cmd 生成VS能夠編譯的*.mak文件
    (6).將以下內容保存爲live/compile.bat
call "C:\Program Files\Microsoft Visual Studio9\VC\vcvarsall.bat"
cd liveMedia
nmake /B -f liveMedia.mak
cd ../groupsock
nmake /B -f groupsock.mak
cd ../UsageEnvironment
nmake /B -f UsageEnvironment.mak
cd ../BasicUsageEnvironment
nmake /B -f BasicUsageEnvironment.mak
cd ../testProgs
nmake /B -f testProgs.mak
cd ../mediaServer
nmake /B -f mediaServer.mak

有關這一點來說,建議把vs2008的編譯環境加入到環境變量中,那麼以後需用命令行編譯程序都可行了,可以參考 http://blog.chinaunix.net/u3/94873/showart_1907792.html的前部分設置VS2008的環境設置。
    (7).在命令行下運行compile.bat,就會看到很多編譯過程出現在CMD中了。

以上的編譯並不是 DEBUG模式,要調試時,應先在win32config加入一行"NODEBUG=1"
進行編譯後,可以在要調試的程序路徑下輸入如:C:\works\VCCode\video\live555-latest\live\testProgs>devenvopenRTSP.exe,這樣就會把相關的調試環境搭建起來進行調試了。


字體大小:

live555庫的應用指南

Real Time Streaming Protocol或者RTSP(實時流媒體協議),是由 Real network和Netscape共同提出的如何有效地在IP網絡上傳輸流媒體數據的應用層協議。RTSP提供一種可擴展的框架,使能夠提供能控制的,按需傳輸實時數據,比如音頻和視頻文件。源數據可以包括現場數據的反饋和存貯的文件。rtsp對流媒體提供了諸如暫停,快進等控制,而它本身並不傳輸數據,rtsp作用相當於流媒體服務器的遠程控制。傳輸數據可以通過傳輸層的tcp,udp協議,rtsp也提供了基於rtp傳輸機制的一些有效的方法。

 
   RTSP協議是一個非常類似HTTP協議的流控制協議。它們都使用純文本來發送信息,而且rtsp協議的語法也和HTTP類似。Rtsp一開始這樣設計,也是爲了能夠兼容使用以前寫的HTTP協議分析代 碼 。這是個好消息。

它們主要的區別是HTTP協議是沒有狀態的, http協議在發送一個命令後,連接會斷開,而且命令之間沒有依賴性。不同的是RTSP的命令需要知道現在正處於一個什麼狀態,也就是說rtsp的命令總是按照順序來發送,某個命令總在另外一個命令之前要發送。Rtsp不管處於什麼狀態都不會去斷掉連接。

HTTP 協議默 認使用80端口,而RTSP默認使用554端口。如果一些服務器因爲某些安全的原因而封掉了這個端口,那代理和防火牆可能不讓RTSP消息通過,需要管理員去放開554端口,而使得rtsp協議能通過。

基本類
在Mplayer中如果使用live選項進行編譯,則需要安裝live555庫。live555實現RTP/RTSP功能。

使用環境(usageEnvironment):UsageEnvironment和TaskScheduler類用在調度不同事件。還有HashTable類定義,這些都是抽象基類。在使用過程中可以利用環境的特定功能。
groupsock:封裝網絡接口和socket。特別是還封裝了multicast應用,這個multicast並不是Mbone意義的multicast,而是將多個寫而不讀socket組合處理,用來模擬multicast。
liveMedia:定義一個類棧,根類是Medium類-不同的流類型和編解碼器。
BasicUsageEnvironment:定義一個usageEnvironment的實現,這個裏面除了有一個TaskScheduler以外,都是一些說明性的東西。TaskSheduler裏面是一些調度相關的函數,其中doEventLoop是主控函數,定義爲純虛函數。
testProgs:目錄下是一個簡單的實現,使用了BasicUsageEnvironment來展示如何使用這些庫。
BasicTaskScheduler0:主要成員變量有fdelayQueue, fReadHandlers,fLastHandledSocketNum;這裏主要的處理函數是scheduleDelayedTask,通過定時器觸發一個時間,比如RTCP包的發送等。
BasicTaskScheduler:中又添加了fMaxNumSockets和fReadSet。其中freadHandlers類中定義一個鏈表,將所有的句柄,對應的處理函數 和處理函數參數作鏈接成一個鏈表,通過成員函數assignHandler管理。這裏面主要的函數是turnOnBackgroundReadHandling,這個函數把句柄和處理函數註冊到select中,這樣可以完成數據包的等待及其處理操作。
MediaSession類中定義了一個mediaSubSession鏈表;MediaSubSession中又SessionId,服務端口號,rtp/rtcp ChannelId和MediaSink指針,等等一些參數信息。

H.264
1. 基類
Medium:定義媒體名字和環境信息,處理任務名,靜態函數close和lookupByName和一些虛函數來指明該medium類型,是媒體幀的基類。
MediaSource類:實現基類中medium類型的虛函數,
FramedSoruce:定義了getNextFrame和doGetNextFrame純虛函數是使用到的一些變量。
2. 相關類
H264VideoStreamFramer;H264VideoFileSink:H264VideoRTPSource:H264VideoRTPSinik
H.264利用NAL封裝數據,通過RTP傳輸數據包。相關的處理在RTPSource/Sink中。

Mplayer
從RTSP或者SIP中渠道SDP描述,然後調用Live555中的mediaSession類創建Session。通過成員函數initializeWithSDP分析SDP描述。

OpenRTSP
1. Client
1. 創建TaskScheduler和UsageEnvironment實例;
2. 調用createClient創建media實例;

在openRTSP.c中,main完成配置以後,開始如下循環:
startPlayingStreams();
env->taskScheduler().doEventLoop(); // does notreturn
在BasicTaskScheduler0類中,定義爲while(1) SingleStep();
SingleStep的處理是通過select監聽一組句柄,這組句柄通過iter組成的鏈表串接起來,對每個句柄有處理函數,如果有句柄上有數據,那麼調用對應的處理函數。

2. liev555mediaserver
創建過程:
1. 創建TaskScheduler:這裏僅僅初始化一個fdset並且socket數目初始化爲0。
2. 以TaskScheduler爲參數創建UsageEnvironment對象。
3. 以前述environment和服務端口號(554/8554)以及用戶認證對象爲參數創建 RTSPServer對象,這裏是用子類DynamicRTSPServer的創建函數創建。在createNew成員函數中建立socket,分配發送緩衝區,和創建RTSPServer對象。這裏通過turnOnBackgroundReadHandling函數將要處理的句柄和處理函數關聯起來。
4. 執行env->taskScheduler().doEventLoop();

從RFC2326中可以看出通常的交互流程是發送describe,然後發送setup,再play。所以以請求MPG多媒體URI爲例分析如下:
C->M: DESCRIBE rtsp://foo/twister RTSP/1.0
CSeq: 1

M->C: RTSP/1.0 200 OK
CSeq: 1
Content-Type: application/sdp
Content-Length: 164

v=0
o=- 2890844256 2890842807 IN IP4 172.16.2.93
s=RTSP Session
i=An Example of RTSP Session Usage
a=control:rtsp://foo/twister
t=0 0
m=audio 0 RTP/AVP 0
a=control:rtsp://foo/twister/audio
m=video 0 RTP/AVP 26
a=control:rtsp://foo/twister/video

C->M: SETUP rtsp://foo/twister/audio RTSP/1.0
CSeq: 2
Transport: RTP/AVP;unicast;client_port=8000-8001

M->C: RTSP/1.0 200 OK
CSeq: 2
Transport: RTP/AVP;unicast;client_port=8000-8001;
server_port=9000-9001
Session: 12345678

C->M: SETUP rtsp://foo/twister/video RTSP/1.0
CSeq: 3
Transport: RTP/AVP;unicast;client_port=8002-8003
Session: 12345678

M->C: RTSP/1.0 200 OK
CSeq: 3
Transport: RTP/AVP;unicast;client_port=8002-8003;
server_port=9004-9005
Session: 12345678

C->M: PLAY rtsp://foo/twister RTSP/1.0
CSeq: 4
Range: npt=0-
Session: 12345678

M->C: RTSP/1.0 200 OK
CSeq: 4
Session: 12345678
RTP-Info: url=rtsp://foo/twister/video;
seq=9810092;rtptime=3450012

C->M: PAUSE rtsp://foo/twister/video RTSP/1.0
CSeq: 5
Session: 12345678

M->C: RTSP/1.0 460 Only aggregate operationallowed
CSeq: 5

C->M: PAUSE rtsp://foo/twister RTSP/1.0
CSeq: 6
Session: 12345678

M->C: RTSP/1.0 200 OK
CSeq: 6
Session: 12345678

C->M: SETUP rtsp://foo/twister RTSP/1.0
CSeq: 7
Transport: RTP/AVP;unicast;client_port=10000

M->C: RTSP/1.0 459 Aggregate operation notallowed
CSeq: 7


函數 handleCmd_DESCRIBE處理describe請求,生成含SDP信息響應消息,lookupServerMediaSession函數是虛函數,在創建RTSPServer對象時,用的是子類DynamicRTSPServer的創建函數,所以上述函數使用的是類DynamicRTSPServer中的定義。函數打開,並且分析流媒體文件。createNewSMS根據請求的文件後綴來調用對應的處理函數。如果是MPG,那麼創建ServerMediaSession對象並添加到RTSPserver中,這個對象是可以通過Hash類定位的。然後創建一個Mpeg1or2FileServerDemux對象demux,然後將創建demux對象中的音頻,視頻子會話對象並且通過函數 addSubsession將他們添加到ServerMediaSession中鏈表中。響應函數會依次調用會話中註冊的子會話的 sdpLines函數以取得SDP信息。sdpLines是一個純虛函數,如果URI指定的MPG文件,那麼sdpLines 函數在OnDemandServerMediaSubsession中定義實現。此時,對每個子會話那麼會創建一個sink對象。對應MPG文件,在MPEG1or2DemuxedServerMediaSubsession類定義的createNewRTPSink會創建對象:
音頻:MPEG1or2AudioRTPSink::AudioRTPSink::MultiFramedRTPSink::RTPSink::MediaSink::Media
視頻:MPEG1or2VideoRTPSink::VideoRTPSink::MultiFramedRTPSink::RTPSink::MediaSink::Media
而SDP信息的獲取在函數 setSDPLinesFromRTPSink中處理。(AudioRTPSink指定媒體類型,時間標籤頻率和載荷格式名“MPA”,視頻名字是“MPV")
這裏類結構 MPEG1or2DemuxedServerMediaSubsession::OnDemandServerMediaSubsession ::ServerMediaSubsession::Medium

函數 handleCmd_SETUP處理setup請求,

MPEG1or2Demux類是mpeg相關的一個主要類,創建該類時會分析媒體文件。該類定義中有個數組,OutputDescriptorfOutput[256];MPEG1or2Demux的構造函數中初始化。

在windows使用vs2008編譯live555


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

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

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

groupsock類是對網絡接口的封裝,用於收發數據包。正如名字本身,Groupsock主要是面向多播數據的收發的,它也同時支持單播數據的收發。Groupsock定義了兩個構造函數
Groupsock(UsageEnvironment& env, struct in_addrconst& groupAddr,
Port port, u_int8_t ttl);
Groupsock(UsageEnvironment& env, struct in_addrconst& groupAddr,
struct in_addr const& sourceFilterAddr,
Port port);
前 者是用於SIM(source-independent multicast)組,後者用於SSM(source-specificmulticast)組。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。
2.在windows下編譯live555
(1).下載 live555,http://www.live555.com/
(2). 編輯 win32config,TOOLS32=C:\Program Files\Microsoft VisualStudio 9.0\VC
即保證這個路徑是你的Vs2008 路徑。
(3). 編輯"LINK_OPTS_0 = $(linkdebug) msvcirt.lib" in win32config to"LINK_OPTS_0 = $(linkdebug) msvcrt.lib",由於編譯器所要LINK的運行庫不一樣了
(4). 修改groupsock/makefile.head,替換"INCLUDES = -Iinclude-I../UsageEnvironment/include" 爲"INCLUDES = -Iinclude-I../UsageEnvironment/include -DNO_STRSTREAM".
(5). 運行genWindowsMakefiles.cmd 生成VS能夠編譯的*.mak文件
(6). 將以下內容保存爲live/compile.bat
call "C:\Program Files\Microsoft Visual Studio9\VC\vcvarsall.bat"
cd liveMedia
nmake /B -f liveMedia.mak
cd ../groupsock
nmake /B -f groupsock.mak
cd ../UsageEnvironment
nmake /B -f UsageEnvironment.mak
cd ../BasicUsageEnvironment
nmake /B -f BasicUsageEnvironment.mak
cd ../testProgs
nmake /B -f testProgs.mak
cd ../mediaServer
nmake /B -f mediaServer.mak

有 關這一點來說,建議把vs2008的編譯環境加入到環境變量中,那麼以後需用命令行編譯程序都可行了,可以參考 http://blog.chinaunix.net/u3/94873/showart_1907792.html的前部分設置VS2008的環境設置。
(7). 在命令行下運行compile.bat,就會看到很多編譯過程出現在CMD中了。

以上的編譯並不是 DEBUG模式,要調試時,應先在win32config加入一行"NODEBUG=1"
進行編譯後,可以在要調試的程序路徑下輸入如:C:\works\VCCode\video\live555-latest\live\testProgs>devenvopenRTSP.exe,這樣就會把相關的調試環境搭建起來進行調試了。

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

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

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

groupsock類是對網絡接口的封裝,用於收發數據包。正如名字本身,Groupsock主要是面向多播數據的收發的,它也同時支持單播數據的收發。Groupsock定義了兩個構造函數
Groupsock(UsageEnvironment& env, struct in_addrconst& groupAddr,
Port port, u_int8_t ttl);
Groupsock(UsageEnvironment& env, struct in_addrconst& groupAddr,
struct in_addr const& sourceFilterAddr,
Port port);
前者是用於SIM(source-independent multicast)組,後者用於SSM(source-specificmulticast)組。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 baseclass
virtual ~MediaSink();

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

static void onSourceClosure(void* clientData);
// should be called (on ourselves) by continuePlaying() whenit
// 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()" worksby arranging for an 'after getting' function to be called (from anevent handler) when new data becomes available for thecaller.

注意,任何應用程序都要處理從'sources'到'sinks'的數據流,但是並非每個這樣的數據流都與從網絡接口收發數據相對應。
比如,一個服務器應用程序發送RTP數據包的時候用到一個或多 個"RTPSink" modules。這些"RTPSink"modules以別的方式接收數據,通常是文件 "*Source" modules (e.g., to read data from afile), 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消息給客戶端,客戶端接收到該消息後釋放資源,程序退出。

}

淺談vlc模塊管理方式-插件


vlc中所有的模塊均以動態庫(插件)方式來管理,就連main模塊也不例外。可以在windows下查看vlc安裝目錄下plugin目錄,裏面包含了所有的動態庫。當vlc啓動的時候,主模塊採用動態加入的方式.

具體實現如下:

 

   If you have alook at include/modules_inner.h, you can see on line 97 that itdeclares a new function. This function's name is defined by__VLC_SYMBOL(vlc_entry). __VLC_SYMBOL is defined a few lines aboveas the concatenation of "vlc_entry" with MODULE_NAME (theCONCATENATE macro inserts the double underscore). MODULE_NAME isdefined by the compiler at compile time using a -D command lineflag except in the case of the main libvlc module (which is the oneyou're looking at) where it defines the name at line 31 ofsrc/libvlc.c. This file then includes src/libvlc.h which calls thevlc_module_begin() macro on line 1177. So we now have a validfunction called vlc_entry__main. When the main plugin isinitialized in the __module_LoadMain() in src/misc/modules.c, itgives that function as the second argument to theAllocateBuiltinModule() on line 327 which will then call thefunction on line 1212.

   上面一段是老外解釋的,還是說的比較清楚了,後來我仔細看了下,自己也做了相關的試驗。其實他的核心就是採用宏定義將該模塊的入口函數導出,以讓其他函數調用。同時入口函數裏面初始化了於該模塊相關的所有函數指針。

   主模塊的庫是libvlc。在modules_in.h中,通過宏定義,導出了vlc_entry__MODULE_NAME函數,MODULE_NAME的宏定義在libvlc.c的31行,(#define MODULE_NAMEmain)這樣也就說明了該模塊的入口函數是vlc_entry__main。在modules.c中存在函數__module_InitBank,該函數最後調用module_LoadMain,在module_LoadMain中,調用了AllocateBuiltinModule函數(AllocateBuiltinModule( p_this, vlc_entry__main);),此處明確指出了需要調用主模塊的入口函數vlc_entry__main,哈哈,看到了吧,此處說明了main模塊要載入了,果然在AllocateBuiltinModule函數中存在調用pf_entry( p_module)1212行,該調用實質是vlc_entry__main的調用,現在一切真像大白了。

    除了主模塊的載入外,其他模塊的載入和主模塊有點不同。他們不是通過這樣直接指定模塊名字調用相應的函數指針的方式,而是採用在動態庫中直接找到_vlc_entry*函數的地址,並調用該函數完成具體模塊的初始化工作。具體的函數調用流程如下:

    1。通過__module_Need(modules.h)找到需要載入的模塊;

    2。在上面函數中通過AllocatePlugin(Modules.h)函數來完成載入;

    3.在AllocatePlugin函數中,CallEntry實現具體的模塊入口的調用,其實現原理就是通過在動態庫文件中查找_vlc_entry*函數的地址(C語言風格的動態庫)。

    4。回到最上層的__module_Need函數中,調用模塊初始化的pf_activate來激活,最後當需要卸載時,調用pf_deactivate函數即可。

    以上就是vlc獨特的管理模塊的方式,只是一個大概的原理,具體裏面還有很多數據結構還未仔細研究,不過可以看的出vlc這樣做的好處能比較靈活的管理各種模塊,並動態改變。雖然代碼都有C寫的,但是實現後的靈活度還是很高的。

TS流、ES流、PES流介紹分析

IP數據報有首部和數據兩部分組成的,首部的前一部分是固定長度20字節,是所有IP數據報必須具有的。首部包括:總長度、標識、MF、DF、片偏移。

數字信號實際傳送的是數據流,一般數據流包括以下三種:

ES流:也叫基本碼流,包含視頻、音頻或數據的連續碼流。
PES流:也叫打包的基本碼流,是將基本的碼流ES流根據需要分成長度不等的數據包,並加上包頭就形成了打包的基本碼流PES流。

TS流:也叫傳輸流,是由固定長度爲188字節的包組成,含有獨立時基的一個或多個節目,適用於誤碼較多的環境。liveMedia項目(http://www.live555.com/)的源代碼包括四個基本的庫,各種測試代碼以及MediaServer。四個基本的庫分別是: UsageEnvironment&TaskScheduler,groupsock, liveMedia和BasicUsageEnvironment。

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

groupsock類是對網絡接口的封裝,用於收發數據包。正如名字本身,groupsock主要是面向多播數據的收發的,它也同時支持單播數據的收發。

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

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

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類的基類。Sink類實現對數據的處理是通過實現純虛函數continuePlaying(),通常情況下continuePlaying調用fSource->getNextFrame來爲Source設置數據緩衝區,處理數據的回調函數等,fSource是MediaSink的類型爲FramedSource*的類成員。

基本控制流程

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

應用程序是事件驅動的,使用如下方式的循環
while (1) {
通過查找讀網絡句柄的列表和延遲隊列(delay queue)來發現需要完成的任務
完成這個任務
}
對於每個sink,在進入這個循環之前,應用程序通常調用下面的方法來啓動需要做的生成任務: 

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

Each 'source' module's implementation of "doGetNextFrame()" worksby arranging for an 'after getting' function to be called (from anevent handler) when new data becomes available for thecaller.

Note that the flow of data from 'sources' to 'sinks' happens withineach application, and doesn't necessarily correspond to the sendingor receiving of network packets. For example, a server application(such as "testMP3Streamer") that sends RTP packets will do so usingone or more "RTPSink" modules. These "RTPSink" modules receive datafrom other, "*Source" modules (e.g., to read data from a file),and, as a side effect, transmit RTP packets.

live555代碼解讀之一:RTSP連接的建立過程
RTSPServer類用於構建一個RTSP服務器,該類同時在其內部定義了一個RTSPClientSession類,用於處理單獨的客戶會話。

首先創建RTSP服務器(具體實現類是DynamicRTSPServer),在創建過程中,先建立Socket(ourSocket)在TCP的554端口進行監聽,然後把連接處理函數句柄(RTSPServer::incomingConnectionHandler)和socket句柄傳給任務調度器(taskScheduler)。

任務調度器把socket句柄放入後面select調用中用到的socket句柄集(fReadSet)中,同時將socket句柄和incomingConnectionHandler句柄關聯起來。接着,主程序開始進入任務調度器的主循環(doEventLoop),在主循環中調用系統函數select阻塞,等待網絡連接。

當RTSP客戶端輸入(rtsp://192.168.1.109/1.mpg)連接服務器時,select返回對應的scoket,進而根據前面保存的對應關係,可找到對應處理函數句柄,這裏就是前面提到的incomingConnectionHandler了。在incomingConnectionHandler中創建了RTSPClientSession,開始對這個客戶端的會話進行處理。

live555代碼解讀之二:DESCRIBE請求消息處理過程

RTSP服務器收到客戶端的DESCRIBE請求後,根據請求URL(rtsp://192.168.1.109/1.mpg),找到對應的流媒體資源,返回響應消息。live555中的ServerMediaSession類用來處理會話中描述,它包含多個(音頻或視頻)的子會話描述(ServerMediaSubsession)。

上節我們談到RTSP服務器收到客戶端的連接請求,建立了RTSPClientSession類,處理單獨的客戶會話。在建立RTSPClientSession的過程中,將新建立的socket句柄(clientSocket)和RTSP請求處理函數句柄RTSPClientSession::incomingRequestHandler傳給任務調度器,由任務調度器對兩者進行一對一關聯。當客戶端發出RTSP請求後,服務器主循環中的select調用返回,根據socket句柄找到對應的incomingRequestHandler,開始消息處理。先進行消息的解析,如果發現請求是DESCRIBE則進入handleCmd_DESCRIBE函數。根據客戶端請求URL的後綴(例如是1.mpg),調用成員函數DynamicRTSPServer::lookupServerMediaSession查找對應的流媒體信息ServerMediaSession。如果ServerMediaSession不存在,但是本地存在1.mpg文件,則創建一個新的ServerMediaSession。在創建ServerMediaSession過程中,根據文件後綴.mpg,創建媒體MPEG-1or2的解複用器(MPEG1or2FileServerDemux)。再由MPEG1or2FileServerDemux創建一個子會話描述MPEG1or2DemuxedServerMediaSubsession。最後由ServerMediaSession完成組裝響應消息中的SDP信息(SDP組裝過程見下面的描述),然後將響應消息發給客戶端,完成一次消息交互。
SDP消息組裝過程:
ServerMediaSession負責產生會話公共描述信息,子會話描述由MPEG1or2DemuxedServerMediaSubsession產生。MPEG1or2DemuxedServerMediaSubsession在其父類成員函數OnDemandServerMediaSubsession::sdpLines()中生成會話描述信息。在sdpLines()實現裏面,創建一個虛構(dummy)的FramedSource(具體實現類爲MPEG1or2AudioStreamFramer和MPEG1or2VideoStreamFramer)和RTPSink(具體實現類爲MPEG1or2AudioRTPSink和MPEG1or2VideoRTPSink),最後調用setSDPLinesFromRTPSink(...)成員函數生成子會話描述。


以上涉及到的類以及繼承關係:
Medium <- ServerMediaSession
Medium <- ServerMediaSubsession <-OnDemandServerMediaSubsession <-MPEG1or2DemuxedServerMediaSubsession
Medium <- MediaSource <- FramedSouse<- FramedFileSource <-ByteStreamFileSource
Medium <- MediaSource <- FramedSouse<- MPEG1or2DemuxedElementaryStream
Medium <- MPEG1or2FileServerDemux
Medium <- MPEG1or2Demux
Medium <- MediaSource <- FramedSouse<- MPEG1or2DemuxedElementaryStream
Medium <- MediaSource <- FramedSouse<- FramedFilter <-MPEGVideoStreamFramer <-MPEG1or2VideoStreamFramer
Medium <- MediaSink <- RTPSink<- MultiFramedRTPSink <- VideoRTPSink<- MPEG1or2VideoRTPSink

live555代碼解讀之三:SETUP 和PLAY請求消息處理過程


前面已經提到RTSPClientSession類,用於處理單獨的客戶會話。其類成員函數handleCmd_SETUP()處理客戶端的SETUP請求。調用parseTransportHeader()對SETUP請求的傳輸頭解析,調用子會話(這裏具體實現類爲OnDemandServerMediaSubsession)的getStreamParameters()函數獲取流媒體發送傳輸參數。將這些參數組裝成響應消息,返回給客戶端。

獲取發送傳輸參數的過程:調用子會話(具體實現類MPEG1or2DemuxedServerMediaSubsession)的createNewStreamSource(...)創建MPEG1or2VideoStreamFramer,選擇發送傳輸參數,並調用子會話的createNewRTPSink(...)創建MPEG1or2VideoRTPSink。同時將這些信息保存在StreamState類對象中,用於記錄流的狀態。

客戶端發送兩個SETUP請求,分別用於建立音頻和視頻的RTP接收。

PLAY請求消息處理過程

RTSPClientSession類成員函數handleCmd_PLAY()處理客戶端的播放請求。首先調用子會話的startStream(),內部調用MediaSink::startPlaying(...),然後是MultiFramedRTPSink::continuePlaying(),接着調用MultiFramedRTPSink::buildAndSendPacket(...)。buildAndSendPacke內部先設置RTP包頭,內部再調用MultiFramedRTPSink::packFrame()填充編碼幀數據。
packFrame內部通過 FramedSource::getNextFrame(),接着MPEGVideoStreamFramer::doGetNextFrame(),再接着經過MPEGVideoStreamFramer::continueReadProcessing(),FramedSource::afterGetting(...),  MultiFramedRTPSink::afterGettingFrame(...),  MultiFramedRTPSink::afterGettingFrame1(...)等一系列繁瑣調用,最後到了 MultiFramedRTPSink::sendPacketIfNecessary(),這裏才真正發送RTP數據包。然後是計算下一個數據包發送時間,把MultiFramedRTPSink::sendNext(...)函數句柄傳給任務調度器,作爲一個延時事件調度。在主循環中,當MultiFramedRTPSink::sendNext()被調度時,又開始調用MultiFramedRTPSink::buildAndSendPacket(...)開始新的發送數據過程,這樣客戶端可以源源不斷的收到服務器傳來的RTP包了。


發送RTP數據包的間隔計算方法:
Update the time at which the next packet should be sent, based onthe duration of the frame that we just packed into it.

涉及到一些類有:

MPEGVideoStreamFramer: A filter that breaks up an MPEG videoelementary stream into headers and frames

MPEG1or2VideoStreamFramer: A filter that breaks up an MPEG 1 or 2video elementary stream into frames for: Video_Sequence_Header,GOP_Header, Picture_Header

MPEG1or2DemuxedElementaryStream: A MPEG 1 or 2 Elementary Stream,demultiplexed from a Program Stream

MPEG1or2Demux: Demultiplexer for a MPEG 1 or 2 Program Stream

ByteStreamFileSource: A file source that is a plain byte stream(rather than frames)

MPEGProgramStreamParser: Class for parsing MPEG programstream

StreamParser: Abstract class for parsing a byte stream

StreamState:A class that represents the state of an ongoing stream
複合/分離的過程稱爲系統復接/分接,據傳輸媒體的質量不同,MPEG-2中定義了兩種複合信息流:傳送流(TS)和節目流(PS:ProgramStream)




RTSP點播消息流程

Real Time Streaming Protocol或者RTSP(實時流媒體協議),是由Real network 和Netscape共同提出的如何有效地在IP網絡上傳輸流媒體數據的應用層協議。RTSP提供一種可擴展的框架,使能夠提供可控制的,按需傳輸實時數據,比如音頻和視頻文件。源數據可以包括現場數據的反饋和存貯的文件。rtsp對流媒體提供了諸如暫停,快進等控制,而它本身並不傳輸數據,rtsp作用相當於流媒體服務器的遠程控制。傳輸數據可以 

通過傳輸層的tcp,udp協議,rtsp也提供了基於rtp傳輸機制的一些有效的方法。

RTSP消息格式: 

RTSP的消息有兩大類,一是請求消息(request),一是迴應消息(response),兩種消息的格式不同. 

請求消息: 

方法 URI RTSP版本 CR LF 

消息頭 CR LF CR LF 

消息體 CR LF 

其中方法包括OPTION迴應中所有的命令,URI是接受方的地址,例如 

:rtsp://192.168.20.136 

RTSP版本一般都是 RTSP/1.0.每行後面的CRLF表示回車換行,需要接受端有相應的解 

析,最後一個消息頭需要有兩個CR LF 

迴應消息: 

RTSP版本 狀態碼 解釋 CR LF 

消息頭 CR LF CR LF 

消息體 CR LF 

其中RTSP版本一般都是RTSP/1.0,狀態碼是一個數值,200表示成功,解釋是與狀態碼對應 

的文本解釋. 

簡單的rtsp交互過程: 

C表示rtsp客戶端,S表示rtsp服務端 

1.C->S:OPTION request//詢問S有哪些方法可用 

1.S->C:OPTION response//S迴應信息中包括提供的所有可用方法 

 

2.C->S:DESCRIBE request//要求得到S提供的媒體初始化描述信息 

2.S->C:DESCRIBE response//S迴應媒體初始化描述信息,主要是sdp 

 

3.C->S:SETUP request//設置會話的屬性,以及傳輸模式,提醒S建立會 

話 

3.S->C:SETUP response//S建立會話,返回會話標識符,以及會話相關信息 

 

 

4.C->S:PLAY request //C請求播放 

4.S->C:PLAY response//S迴應該請求的信息 

 

S->C:發送流媒體數據 

5.C->S:TEARDOWN request//C請求關閉會話 

5.S->C:TEARDOWN response//S迴應該請求 

 

上述的過程是標準的、友好的rtsp流程,但實際的需求中並不一定按部就班來。 

其中第3和4步是必需的!第一步,只要服務器客戶端約定好,有哪些方法可用,則option請求可以不要。第二步,如果我們有其他途徑得到媒體初始化描述信息(比如http請求等等),則我們也不需要通過rtsp中的describe請求來完成。第五步,可以根據系統需求的設計來決定是否需要。 

 

rtsp中常用方法: 

 

1.OPTION 

目的是得到服務器提供的可用方法: 

OPTIONS rtsp://192.168.20.136:5000/xxx666RTSP/1.0 

CSeq: 1 //每個消息都有序號來標記,第一個包通常是option請求消息 

User-Agent: VLC media player (LIVE555 Streaming Mediav2005.11.10) 

 

服務器的迴應信息包括提供的一些方法,例如: 

RTSP/1.0 200 OK 

Server: UServer 0.9.7_rc1 

Cseq: 1 //每個迴應消息的cseq數值和請求消息的cseq相對應 

Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE,SCALE, 

GET_PARAMETER //服務器提供的可用的方法 

2.DESCRIBE 

C向S發起DESCRIBE請求,爲了得到會話描述信息(SDP): 

DESCRIBE rtsp://192.168.20.136:5000/xxx666RTSP/1.0 

 

CSeq: 2 

token: 

Accept: application/sdp 

User-Agent: VLC media player (LIVE555 Streaming Mediav2005.11.10) 

 

服務器迴應一些對此會話的描述信息(sdp): 

RTSP/1.0 200 OK 

Server: UServer 0.9.7_rc1 

Cseq: 2 

x-prev-url: rtsp://192.168.20.136:5000 

x-next-url: rtsp://192.168.20.136:5000 

x-Accept-Retransmit: our-retransmit 

x-Accept-Dynamic-Rate: 1 

Cache-Control: must-revalidate 

Last-Modified: Fri, 10 Nov 2006 12:34:38GMT 

Date: Fri, 10 Nov 2006 12:34:38 GMT 

Expires: Fri, 10 Nov 2006 12:34:38 GMT 

Content-Base:rtsp://192.168.20.136:5000/xxx666/ 

Content-Length: 344 

Content-Type: application/sdp 

 

v=0 //以下都是sdp信息 

o=OnewaveUServerNG 1451516402 1025358037 IN IP4192.168.20.136 

s=/xxx666 

u=http:/// 

e=admin@ 

c=IN IP4 0.0.0.0 

t=0 0 

a=isma-compliance:1,1.0,1 

 

a=range:npt=0- 

m=video 0 RTP/AVP 96//m表示媒體描述,下面是對會話中視頻通道的媒體描述 

a=rtpmap:96 MP4V-ES/90000 

a=fmtp:96 

profile-level-id=245;config=000001B0F5000001B509000001000000012000C888B0E0E0FA62D089028307 

 

a=control:trackID=0//trackID=0表示視頻流用的是通道0 

 

3.SETUP 

客戶端提醒服務器建立會話,並確定傳輸模式: 

SETUP rtsp://192.168.20.136:5000/xxx666/trackID=0RTSP/1.0 

CSeq: 3 

Transport:RTP/AVP/TCP;unicast;interleaved=0-1 

User-Agent: VLC media player (LIVE555 Streaming Mediav2005.11.10) 

//uri中帶有trackID=0,表示對該通道進行設置。Transport參數設置了傳輸模式,包 

的結構。接下來的數據包頭部第二個字節位置就是interleaved,它的值是每個通道都 

不同的,trackID=0的interleaved值有兩個0或1,0表示rtp包,1表示rtcp包,接受端 

根據interleaved的值來區別是哪種數據包。 

 

服務器迴應信息: 

RTSP/1.0 200 OK 

Server: UServer 0.9.7_rc1 

Cseq: 3 

Session: 6310936469860791894 //服務器迴應的會話標識符 

Cache-Control: no-cache 

Transport:RTP/AVP/TCP;unicast;interleaved=0-1;ssrc=6B8B4567 

4.PLAY 

客戶端發送播放請求: 

PLAY rtsp://192.168.20.136:5000/xxx666RTSP/1.0 

CSeq: 4 

Session: 6310936469860791894 

Range: npt=0.000- //設置播放時間的範圍 

User-Agent: VLC media player (LIVE555 Streaming Mediav2005.11.10) 

服務器迴應信息: 

RTSP/1.0 200 OK 

Server: UServer 0.9.7_rc1 

Cseq: 4 

Session: 6310936469860791894 

Range: npt=0.000000- 

RTP-Info:url=trackID=0;seq=17040;rtptime=1467265309 

//seq和rtptime都是rtp包中的信息 

5.TEARDOWN 

客戶端發起關閉請求: 

TEARDOWN rtsp://192.168.20.136:5000/xxx666RTSP/1.0 

CSeq: 5 

Session: 6310936469860791894 

User-Agent: VLC media player (LIVE555 Streaming Mediav2005.11.10) 

服務器迴應: 

RTSP/1.0 200 OK 

Server: UServer 0.9.7_rc1 

Cseq: 5 

Session: 6310936469860791894 

Connection: Close 

 

以上方法都是交互過程中最爲常用的,其它還有一些重要的方法如 

get/set_parameter,pause,redirect等等 

ps: 

sdp的格式 

v=<version> 

o=<username><session id><version> <networktype> <address type><address> 

s=<sessionname> 

i=<sessiondescription> 

u=<URI> 

e=<emailaddress> 

p=<phonenumber> 

c=<network type><address type><connectionaddress> 

b=<modifier>:<bandwidth-value> 

t=<start time><stop time> 

r=<repeat interval><active duration><list of offsets fromstart-time> 

z=<adjustment time><offset> <adjustmenttime> <offset>.... 

k=<method> 

k=<method>:<encryptionkey> 

a=<attribute> 

a=<attribute>:<value> 

m=<media><port><transport> <fmtlist> 

v = (協議版本) 

o = (所有者/創建者和會話標識符) 

s = (會話名稱) 

i = * (會話信息) 

u = * (URI 描述) 

e = * (Email 地址) 

p = * (電話號碼) 

c = * (連接信息) 

b = * (帶寬信息) 

z = * (時間區域調整) 

k = * (加密密鑰) 

a = * (0 個或多個會話屬性行) 

時間描述: 

t = (會話活動時間) 

r = * (0或多次重複次數) 

媒體描述: 

m = (媒體名稱和傳輸地址) 

i = * (媒體標題) 

c = * (連接信息 — 如果包含在會話層則該字段可選) 

b = * (帶寬信息) 

k = * (加密密鑰) 

a = * (0 個或多個媒體屬性行) 

參考文章:rfc2326(rtsp);rfc2327(sdp) 

RTSP點播消息流程實例(客戶端:VLC, RTSP服務器:LIVE555 MediaServer) 

 

1)C(Client)-> M(MediaServer) 

OPTIONS rtsp://192.168.1.109/1.mpgRTSP/1.0 

CSeq: 1 

user-Agent: VLC media player(LIVE555 Streaming Mediav2007.02.20) 

 

1)M -> C 

RTSP/1.0 200 OK 

CSeq: 1 

Date: wed, Feb 20 2008 07:13:24 GMT 

Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY,PAUSE 

 

2)C -> M 

DESCRIBE rtsp://192.168.1.109/1.mpgRTSP/1.0 

CSeq: 2 

Accept: application/sdp 

User-Agent: VLC media player(LIVE555 Streaming Mediav2007.02.20) 

 

2)M -> C 

RTSP/1.0 200 OK 

CSeq: 2 

Date: wed, Feb 20 2008 07:13:25 GMT 

Content-Base: rtsp://192.168.1.109/1.mpg/ 

Content-type: application/sdp 

Content-length: 447 

v=0 

o =- 2284269756 1 IN IP4 192.168.1.109 

s=MPEG-1 or 2 program Stream, streamed by the LIVE555 MediaServer 

i=1.mpg 

t=0 0 

a=tool:LIVE555 Streaming Media v2008.02.08 

a=type:broadcast 

a=control:* 

a=range:npt=0-66.181 

a=x-qt-text-nam:MPEG-1 or Program Stream, streamed by theLIVE555 Media Server 

a=x-qt-text-inf:1.mpg 

m=video 0 RTP/AVP 32 

c=IN IP4 0.0.0.0 

a=control:track1 

m=audio 0 RTP/AVP 14 

c=IN IP4 0.0.0.0 

a=control:track2 

 

3)C -> M 

SETUP rtsp://192.168.1.109/1.mpg/track1RTSP/1.0 

CSeq: 3 

Transport: RTP/AVP;unicast;client_port=1112-1113 

User-Agent: VLC media player(LIVE555 Streaming Mediav2007.02.20) 

 

3)M -> C 

RTSP/1.0 200 OK 

CSeq: 3 

Date: wed, Feb 20 2008 07:13:25 GMT 

Transport:RTP/AVP;unicast;destination=192.168.1.222;source=192.168.1.109;client_port=1112-1113;server_port=6970-6971 

Session: 3 

 

4)C -> M 

SETUP rtsp://192.168.1.109/1.mpg/track2RTSP/1.0 

CSeq: 4 

Transport: RTP/AVP;unicast;client_port=1114-1115 

Session: 3 

User-Agent: VLC media player(LIVE555 Streaming Mediav2007.02.20) 

 

4)M -> C 

RTSP/1.0 200 OK 

CSeq: 4 

Date: wed, Feb 20 2008 07:13:25 GMT 

Transport:RTP/AVP;unicast;destination=192.168.1.222;source=192.168.1.109;client_port=1114-1115;server_port=6972-6973 

Session: 3 

 

5)C -> M 

PLAY rtsp://192.168.1.109/1.mpg/ RTSP/1.0 

CSeq: 5 

Session: 3 

Range: npt=0.000- 

User-Agent: VLC media player(LIVE555 Streaming Mediav2007.02.20) 

 

5)M -> C 

RTSP/1.0 200 OK 

CSeq: 5 

Range: npt=0.000- 

Session: 3 

RTP-Info:url=rtsp://192.168.1.109/1.mpg/track1;seq=9200;rtptime=214793785,url=rtsp://192.168.1.109/1.mpg/track2;seq=12770;rtptime=31721



TS流與PS流的區別在於TS流的包結構是固定長度的,而PS流的包結構是可變長度。PS包與TS包在結構上的這種差異,導致了它們對傳輸誤碼具有不同的抵抗能力,因而應用的環境也有所不同。TS碼流由於採用了固定長度的包結構,當傳輸誤碼破壞了某一TS包的同步信息時,接收機可在固定的位置檢測它後面包中的同步信息,從而恢復同步,避免了信息丟失。而PS包由於長度是變化的,一旦某一PS包的同步信息丟失,接收機無法確定下一包的同步位置,就會造成失步,導致嚴重的信息丟失。因此,在信道環境較爲惡劣,傳輸誤碼較高時,一般採用TS碼流;而在信道環境較好,傳輸誤碼較低時,一般採用PS碼流由於TS碼流具有較強的抵抗傳輸誤碼的能力,因此目前在傳輸媒體中進行傳輸的MPEG-2碼流基本上都採用了TS碼流的包

格。


用live555開發流媒體播放器應用程序的方法



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章