轉自:http://topic.csdn.net/u/20100104/16/0fd992e8-b0a6-4c2b-85a4-d9513d3b1491.html
?
相信有不少人和我一樣,希望實現H264格式視頻的流媒體播放。但是對于一個新手來說,往往不知道從何入手。利用百度,GOOGLE等搜索資料真是沙里淘金。在琢磨了N周之后,才弄出來了點成果,其中費了很多無用的功夫,光看英文協議就費了一周,后來才知道有中文版,并且我所達到的目的很簡單,只要讓VLC實時播放就行,不需要了解整個協議。我也很希望能直接搜出來一套代碼,都一直沒找到,還是得自己動手。現在我把自己的代碼貼出來,希望對做類似工程的朋友有所幫助。
一、本示例代碼在我的電腦上實現了對標準H264碼流的RTP打包發送到本機的1234端口,用VLC播放器從1234端口能接收到該碼流并實時播放。代碼附有詳細的注釋,應該很容易理解(前提是大家稍微對RFC3550 RFC3984協議有了解)。
二、本示例代碼是按照RFC3984協議僅完成了RTP打包,并沒有完成發送RTCP。原因就引用這位達人的話:“1.RTCP里頭有很多關于RTCP發送簡隔的時間計算,RTP信息的統計,這種操作不是難,而是煩,我不想去寫。2.RTCP和RTP一開始出來的時候并不是因為視頻的點播等應用的,而是視頻會議。RTCP有管理與會者的層面含義,這一功能在很多場合并不會用到。3.我想簡單,沒有寫多個流間的同步,如一個影片的視頻和音頻流。這些其實是RTCP來完成的。我懶得去寫,因為這些工作RTP的各個庫類(例如JRTPLIB庫)都做得很好。我覺得用庫的最大優點就在這吧”。
三、和代碼相關的原理性的東西,大家應該去看看RFC3550,RFC3984.這兩份協議都有熱心網友翻譯好的中文版。我把他們放在壓縮包里,大家就不用再累個半死去搜索注冊下載了。如果為了更省事,我覺得看看這位網友總結的RFC3984的內容就夠了。網址是http://www.cppblog.com/czanyou/archive/2009/12/25/67940.html。如果打不開網頁,就到壓縮包里資料文件夾下找吧。我已經把網頁保存下來了。
四、代碼并非是我完全原創的,而是我在搜索到得網友的代碼的基礎上修改的。這里要特別感謝以下幾位網友:1.貓頭上的鷹(他的博客地址http://blog.csdn.net/Tinnal/archive/2008/09/03/2871734.aspx)在他的博客里我第一次找到了有價值的東西,并且他無償提供的MPEG的RTP打包源碼只要拷貝下來建個工程就能實現MPEG的流媒體,對我啟發很大。2.liming,他提供的代碼已經實現了H264的碼流分析,將其中的每個NALU單元分離開來,并分析出了NALU的類型,長度等信息。為我實現RTP打包提供了很大的方便,事實上,這份示例代碼就是在他的代碼上添加了RTP打包部分,我連工程名字都沒有改。他的源代碼在這里http://www.pudn.com/detail.asp?id=510807。3****,他提供的SDP文件在關鍵時候幫了我大忙,我發送的RTP數據包通過Wireshark抓包工具分析一直沒錯,可VLC播放器就是沒任何反應。直到下載了他的SDP文件文件后終于出畫面了。某位網友說VLC對H264只能通過TS封包或SDP文件打開RTP碼流,在此我也這么懷疑。4.jessiepan和他的帖子,http://topic.csdn.net/u/20090725/11/5FBC75B0-1091-4DD4-9154-3E3D59F9B6D1.html,這里提供了很多有用的信息。
?
使用方法:直接在VC6上打開工程,編譯。(需要注意的是大家要把IP地址和端口改為自己的。在h264.h的#define DEST_IP "192.168.0.30"和#define DEST_PORT 1234這兩行修改就行了。同時w.sdp文件里也要改成一致的IP和端口號,不然VLC是接受不到數據的。在c=IN IP4 192.168.0.30 和m=video 1234 RTP/AVP 96這兩行。中間的1234是我設置的端口號。)在執行程序之前,先用VLC打開w.sdp文件,然后執行程序,就可以看到畫面了:)。同樣需要注意的是VLC1.0以后的版本不支持直接打開h.264視頻文件,但是0.97版本就支持。兩個版本的VLC播放器大家去著哩下載這里我測試用1.03和0.97兩份版本的VLC都可以接受并播放h.264RTP碼流。
目前還有幾個問題我沒有弄明白,希望有高手在看完這個帖子后能幫我解答:
1.關于時間戳的設置。RFC3984里沒有提到時間戳具體如何計算,我也是按照各方面的小道消息這樣設置。unsigned int timestamp_increse=0;timestamp_increse=(unsigned int)(90000.0 / framerate); 即初始值設為0,時間戳增量設為90000.0 / framerate,framerate我設為25,即每秒25幀。每發送一個NALU單元,時間戳增加。若是該NALU大于1400字節,需要分片時,則多個分片擁有相同的時間戳。這樣設置是否正確。請牛人給個權威解答。
2.按照我的理解,SDP文件僅實現了告訴VLC在哪個IP和端口接受264RTP包,同樣的信息我也通過在VLC的媒體-》打開網絡串流,協議選RTP,然后填寫IP和端口號中設置好了,為什么用打開SDP文件的方法能接收,但用后者VLC卻沒有一點反應。
3.當我將幀率設為25時(即代碼里的float framerate=25;)vlc能接受碼流,但會比較卡,常緩沖,提示錯誤為main error: ES_OUT_SET_(GROUP_)PCR is called too late, increasing pts_delay to 339 ms。我懷疑是我的電腦發送UDP包速度不夠每秒播放25幀的所需要的UDP包數量,因此在SDP文件我添加了a=framerate:15來限制播放器每秒播放15幀,同時在代碼里的相應行float framerate=15;也將幀率改為15這樣雖然解決了卡的問題,但是視頻播放很慢。請問要是我想達到每秒播放25幀,難道只能換臺好電腦了?
5.下一步我想用jrtplib來打包RTP,因為聽說用這個庫實現RTCP很方便,是不是這個庫會根據網絡狀況自動發送RTCP信息。如果哪位高手有這方面的代碼或者是實現了RTSP的代碼,希望能拿出來交流,哪怕是部分代碼或者是實現部分功能也好。
? 源碼下載地址:http://download.csdn.net/source/1961862大家下載后有什么問題可以直接和我聯系,不留郵箱了,直接留QQ號吧:1002666420.另外我這里還有一個老外寫的用LIVE555庫實現H264 STREAMING的教程及代碼,有需要的可以聯系我。