• 沒有找到結果。

Streaming Server 任務中包含了 RTSP 信令解析、媒體影音檔案格式的判斷、

封包切割封裝以及傳送的時間控制,其中封包的傳送時間控制在伺服器的多工系 統中是相得值得研究的議題。

如我們在第四章中提到的,在 Client-Server 架構的應用中,最大的問題往往 是收送速率匹配的問題,而此問題衍生出來的研究便是去探討如何有效因應網路 頻寬的動態來調整 Server 的傳輸速率,也就是當目前網路頻寬使用率不高時,

Server 可以動態提高傳輸速率以增加 QoS 的品質;反之當目前網路頻寬使用率 很高(網路擁塞)時,Server 可以降低傳輸速率,但仍須維持基本 QoS 的品質。

而在我們目前的研究中尚未考慮到頻寬使用率的問題,Server 在傳送封包時 只是按照一個固定的時間(如每 1/29.97 秒)將所有要傳送的封包傳至用戶端,一 旦發生網路擁塞時也許在 1/29.97 秒內,封包未能傳達到用戶端,導致用戶端發 生很嚴重的間隔或連線中斷。例如手機在通話的過程中,如果 Channel 不好將會 使得通話品質受到影響,或者收訊時好時壞,但以上的情形都是用戶端最不想看 到的情形。

以串流伺服器的應用來說,很重要的考量因素便是如何提供一個穩定的影像 作,並考慮 Buffer 的大小來決定是否繼續進行切割封裝,而這個 Scheduling

Mechanism 的機制是我們可以去控制的,也就是要確保在 BandWidth/Channel 不 佳的情況下,Server 如何維持穩定的多工連線品質(QoS),這也是本論文的研究 目地。

而後 Home/Traffic Surveillance/Office System 的應用將無所不在,其產 品如 IPCam、STB(Set Top Box)以及 VOIP 相關的嵌入式產品其背後都需要有『小 而美』的軟體來維持系統的穩定運作,而應用面不同其多工排程演算法

(Scheduling Mechanism for Multiplexing)便需要適應環境而變,如何提供一 個更精緻的多工排程演算法將會是本論文以後的研究方向。

參考文獻 [1] http://ffmpeg.mplayerhq.hu/

[2] http://www.live555.com/

[3] http://www.videolan.org/vlc/

[4] http://www.faqs.org/rfcs/rfc2616.html RFC 2616 - Hypertext Transfer Protocol – HTTP/1.1

[5] http://www.youtube.com [6] http://www.nuuo.com

[7] http://www.mingw.org/download.shtml [8] http://www.libsdl.org/download-1.2.php

[9] H.Schulzrinne , A.Rao, and R.Lanphier, "Real Time Streaming Protocol(RTSP)", RFC2326,April 1998

[10] H. Schulzrinne, Columbia University, “RTP:A Transport Protocol for Real-Time ",RFC3550. Titl , July2003

[11] E.COMER , L.STEVENS , “INTERNETWORKING with TCP/IP", Volume 3 Publisher :Prentice Hall

[12] 陳重嘉,experience in software development concepts,disciplines and cases [13] 吳宗修,Analysis of Streaming Server’s Properties,國立交通大學,96學年度 [14] UNIX網路程式設計,網路應用程式設計介面Socket與XTI

作者:W. Richard Stevens ,譯者:林慶德,出版:培生

[15] 多媒體通訊,原理‧標準‧與系統第二版

作者:戴顯權、陳瀅如、王春清編著,出版:紳藍

[16] Silberschatz , Galvin and Gagne , “Operating System Principles", SIXTH EDITION , Publisher :WILEY

[17] William Stallings , Operation Systems:Internals and Design Principles, 5th ed. , Publisher:Prentice Hall , 2004

附錄 一:如何在 windows 下去編譯以及執行 ffserver

Step[1] 連上http://www.mingw.org/download.shtml 網頁,下載 MinGW-5.0.2 及 MSYSmys-1.0.10 套件。

Step[2] 先安裝 MinGW-5.0.2,之後再將解壓縮後的 MSYSmsys-1.0.10 安裝在 MinGW-5.0.2 裡的 bin 資料夾內。

Step[3] 連上http://ffmpeg.mplayerhq.hu/download.html 網頁,下載 Ffmpeg 的 source code。

Step[4] 開啟 Msys 的執行檔,進入 Ffmpeg 的目錄下鍵入 ./configure --enable-memalign-hack

make make install

Setp[5] 根據上面的步驟可以成功的編譯出 ffmpeg.exe 檔 與 ffserver.exe 檔。

Step[6] 想要編譯出 ffplay.exe 檔,必須要安裝 SDL(Simple DirectMedia Layer) 從此http://www.libsdl.org/download-1.2.php 網頁中下載。

Setp[7] For (Mingw32) SDL-devel-1.2.11-mingw32.tar.gz 版本下載的網頁,下載 SDL 後將它解壓,之後會看到 bin , include , lib , share,四個資料夾,將這 四個資料夾 copy 到 MinGW 的目錄下‧把原來的檔復蓋過去。之後在 Window 底下使用 MinGW 去編譯。

Step[8] 進入 MinGW 的 bin 目錄下修改 i386-mingw32msvc-sdl-config 文件的第 一行為 Prefix=/mingw。 之後再將 i386-mingw32msvc-sdl-config 檔名改 為 sdl-config。

因為 i386-mingw32msvc-sdl-config 的文件中發現 usage(資料來源)是在 sdl-config,所以一定要將 i386-mingw32msvc-sdl-config 檔名改為 sdl-config。否則編譯會出錯。

Step[9] 開啟 Msys 的執行檔,進入 Msys ffmpeg 目錄底下鍵入 ./configure --enable-memalign-hack

Make Make install

Setp[10] 即完成編譯的動作。此時在 ffmpeg 的目錄下會看到 ffmpeg.exe,

ffserver.exe 與及 ffplay.exe 檔。

附錄 二: 在 Suse –linux 作業系統下編譯與及執行 ffserver Step 1:在 Suse-linux 作業系統上,使用 SVN 下載 ffmpeg

(svn checkout svn://svn.mplayerhq.hu/ffmpeg/trunk ffmpeg)

Step 2:在 ffmpeg 目錄下去執行 config 與 make 的動作 ./configure

./make

Step 3:執行 make 動作之會,我們在 ffmpeg 目錄下可看到多出 3 個執行檔 Ffmpeg,ffserver,以及 ffplay,如下紅框內綠色字所示

Step 4:在 ffmpeg 目錄下鍵入./ffserver –f doc/ffserver.conf & 即可看到 ffserver Started ,表示已將 ffserver 伺服器已開啟

Step 5:使用 IE,鍵入http://destination ip:port/stat.html,連接到 ffserver,即可看 Ffserver 預設的網頁圖,如下圖所示

[註:ffserver 的 HTTP 的預設 port 為 8090 ]

Step 6:接下來使用 VLC media player 連接到 ffserver

先進入 doc/ffserver.conf 檔中,將想要播放的檔案與路徑設定好,如下紅 框所示

Step2:使用 VLC 播放器,在檔案->開啟網路串流->選擇 RTSP 在網址中鍵入 rtsp:// destination ip.Port/test1.mpg,即可看到 test1.mpg 播放的影片,

附錄 三:如何在 Windows 下去編譯以及執行 live555

Step 1:先到此網頁 http://www.live555.com/下載 live555 的 Source code

Step 2:在 live555 目錄下有一個 win32config 檔案,將這檔案開啟後,在 Tools32 的路徑,更改為目前 VC++的正確的路徑。

Step 3:打開 VC++ ,在 File ->Open Workspace ->找到存放 live555 的位置,在 live 目錄下會看到很多個目錄,如 BasicUsageEnvironment , testProgs….

如下圖所示

Step 4:在檔案類別的地方,選擇副檔名為 Makefiles(.mak)檔

Step 5:接下來開始 build 檔案。

Step 6:重復 Step 3 ~ Step 5 直到將 live555 目錄中所有的資料都 build 完。

Step 7:接下來使用 cywin 將 live555 伺服器打開,我們看到在 live555 中預設可 播放的影片如下圖 2 所示

2

Step 8:使用 VLC media player 連到 live555 伺服器,即可觀賞 test.mpg 的影片。

附錄四:Trace 程式時所使用的到的程式碼流程

1. 計算 fNextSendTime 的程式碼在 MultiFramedRTPSink.cpp 裡

A. void MultiFramedRTPSink

::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, struct timeval presentationTime,

unsigned durationInMicroseconds) { if (fIsFirstPacket) {

// Record the fact that we're starting to play now:

gettimeofday(&fNextSendTime, NULL);

}

B. afterGettingFrame1()內

//Update the time at which the next packet should be sent, based // on the duration of the frame that we just packed into it.

// However, if this frame has overflow data remaining, then don't // count its duration yet.

if (overflowBytes == 0) {

fNextSendTime.tv_usec += durationInMicroseconds;

fNextSendTime.tv_sec += fNextSendTime.tv_usec/1000000;

fNextSendTime.tv_usec %= 1000000;

}

2. 計算 PTS 的程式碼在-MPEGVideoStreamFramer.cpp 裡

void MPEGVideoStreamFramer

::computePresentationTime(unsigned numAdditionalPictures) // Computes "fPresentationTime" from the most recent GOP's // time_code, along with the "numAdditionalPictures" parameter:

TimeCode& tc = fCurGOPTimeCode;

double pictureTime = fFrameRate == 0.0 ? 0.0

: (tc.pictures + fPicturesAdjustment + numAdditionalPictures)/fFrameRate - fPictureTimeBase;

unsigned pictureSeconds = (unsigned)pictureTime;

double pictureFractionOfSecond = pictureTime - (double)pictureSeconds;

// fTcSecsBase = (((tc.days*24)+tc.hours)*60+tc.minutes)*60+tc.seconds;

unsigned tcSecs

= (((tc.days*24)+tc.hours)*60+tc.minutes)*60+tc.seconds - fTcSecsBase;

fPresentationTime = fPresentationTimeBase;

fPresentationTime.tv_sec += tcSecs + pictureSeconds;

fPresentationTime.tv_usec += (long)(pictureFractionOfSecond*1000000.0);

printf("**EnterComputePresentationTime****\n");

printf("fpresentationTime.tv_usec=%d\n",fPresentationTime.tv_usec);

printf("**End**\n");

if (fPresentationTime.tv_usec >= 1000000) { fPresentationTime.tv_usec -= 1000000;

++fPresentationTime.tv_sec;

}

3. 在建立 RTP 環境時的程式碼在 RTPSink.cpp 裡

A. RTPSink::RTPSink(UsageEnvironment& env,

Groupsock* rtpGS, unsigned char rtpPayloadType, unsigned rtpTimestampFrequency,

char const* rtpPayloadFormatName, unsigned numChannels)

: MediaSink(env), fRTPInterface(this, rtpGS), fRTPPayloadType(rtpPayloadType),

fPacketCount(0), fOctetCount(0), fTotalOctetCount(0), fTimestampFrequency(rtpTimestampFrequency), fNumChannels(numChannels) {

fRTPPayloadFormatName

= strDup(rtpPayloadFormatName == NULL ? "???" : rtpPayloadFormatName);

gettimeofday(&fCreationTime, NULL);

fTotalOctetCountStartTime = fCreationTime;

fSeqNo = (unsigned short)our_random();

fSSRC = (unsigned)our_random();

fTimestampBase = (unsigned)our_random();

fCurrentTimestamp = fTimestampBase;

fTransmissionStatsDB = new RTPTransmissionStatsDB(*this);

}

B. 計算 Timestamp

convertToRTPTimestamp()函數裡:

u_int32_t RTPSink::convertToRTPTimestamp(struct timeval tv, Boolean isFirstTime) {

u_int32_t rtpTimestampIncrement = timevalToTimestamp(tv);

fTimestampBase -= rtpTimestampIncrement;

}

return convertToRTPTimestamp(tv);

}

timevalToTimestamp() 函數:

u_int32_t RTPSink::timevalToTimestamp(struct timeval tv) const { //pts*90k+一個亂數基本值

u_int32_t timestamp = (fTimestampFrequency*tv.tv_sec);

timestamp += (unsigned)((2.0*fTimestampFrequency*tv.tv_usec + 1000000.0)/2000000);

// note: rounding return timestamp;

}

相關文件