ffmpeg筆記——UDP組播接收總結


ffmpeg在avformat_open_input里面已經實現了UDP的協議,所以只需要設置好參數,將url傳遞進去就可以了。

       和打開文件的方式基本一樣:

 

01 AVCodecContext *pVideoCodecCtx = NULL;
02 AVCodec *pVideoCodec = NULL;
03 avcodec_register_all();
04 av_register_all();
05 avformat_network_init();
06 if(m_pConfigManager == NULL)
07 {
08      return E_POINTER;
09 }
10  
11 int videoStream = -1;
12  
13 CString url = m_pConfigManager->GetURL();
14 int portNumber = m_pConfigManager->GetPortNumber(channel);
15 url.Format(_T( "%s:%d"), url, portNumber);
16  
17 m_pFormatContext[channel] = avformat_alloc_context();
18 int err = avformat_open_input(&(m_pFormatContext[channel]), url, NULL, NULL);
19 if(err != 0)
20 {
21    fprintf(stderr, "Can't open %s!", url);
22    return E_FAIL;
23 }
24  
25 m_pFormatContext[channel]->flags |= AVFMT_FLAG_GENPTS;
26 m_pFormatContext[channel]->flags |= AVFMT_GENERIC_INDEX;
27 m_pFormatContext[channel]->max_index_size = 99;
28  
29 if(av_find_stream_info(m_pFormatContext[channel]) < 0)
30 {
31    fprintf(stderr,"Can't find stream info \n" );
32                                  
33    return E_FAIL;
34 }
35  
36 av_dump_format(m_pFormatContext[channel], 0, url,false);

       之后就可以通過av_read_frame來獲取通過UPD組播協議發送來的packet,並發送至自己的一個隊列A進行緩存,再由DirectShow等視頻開發框架從該隊列A獲取數據,並進行解碼顯示。

 

       與讀取文件不同,讀取UDP組播協議數據包必須不斷調用av_read_frame。這是因為ffmpeg在讀取UDP時會新建一個數據緩沖區B,數據通過UDP組播協議發送出來后,就被存儲到這個緩沖區B里;如果長時間不調用av_read_frame(例如在讀取文件時,如果自己建立的隊列A已滿,則不再調用av_read_frame,而是使本線程休眠若干毫秒,等待DirectShow等前端框架從隊列A取出數據包進行解碼),那么不斷到來的UDP數據包就會將緩沖區B寫爆,之后再調用av_read_frame就會返回-5,代表IO錯誤。

 

       因為UDP組播一般是與實時源(Live Source)相關聯,因此過時的數據包是沒有用的,因此當隊列A寫滿時,采取從隊列A彈出若干個數據包,之后再進行av_read_frame操作。這樣的代價是在播放過程中會產生丟包(視頻中出現馬賽克、花屏),但是延時會控制在一個合理的范圍內;也可以直接丟棄av_read_frame得到的數據包,這樣視頻中的馬賽克較少,但是這樣會產生無法估計的延時。

 

        另外,在同時讀取多路組播數據包時,也會遇到與緩沖區B相關的問題:av_find_stream_info會在視頻流中尋找並解析PPS、SPS,是非常耗時的。在做好第一路的初始化之后,就應該立即新建一個線程用於調用av_read_frame函數獲取數據(否則,第一路的緩沖區B會被寫爆);與此同時,第二路的初始化工作也將開始;由於此時有一個讀取第一路UDP數據包的線程來爭奪CPU時間,因此第二路的av_find_stream_info將會花費更多的時間,這將導致第二路的緩沖區B被寫爆。

 

        上述問題的解決思路有兩個,第一個是同時初始化兩路UDP連接,但是在我的程序里由於有一些共享資源的限制,線程同步比較麻煩,所以后來放棄了;第二個是盡量減少av_find_stream_info的時間或者加大緩沖區B的大小。看了AVFormatContext的屬性,經過試驗發現,減小probesize和max_analyze_duration可以減少av_find_stream_info的時間,但是沒有找到可以增大緩沖區B的辦法。。。上面兩個屬性也不可以減少的太多,而要依據視頻源的SPS和PPS的特點來確定,否則會找不到stream_info,也就沒有分辨率等信息。

 

        解決了緩沖區的問題后,我發現播放高清視頻(1080i,720p,1080p)時播放時丟包非常嚴重。查了半天,發現播放時隊列A幾乎是時時處於滿狀態,導致程序主動丟棄了很多數據包。再看CPU的狀態,幾乎是滿負荷運轉。輸出解碼和緩存的調試信息后,發現基本上解碼一幀,會緩存五幀……看來是CPU太慢了(四年前的機器,AMD Turion64×2)。換到旁邊同學的i3-2300(盒)上運行就非常流暢了……

 

        看來我該換筆記本了。等28號HKUST出學生機計划,看看價錢靠不靠譜吧~謝謝陽總工提供的消息!

        歡迎轉載,轉載請注明出處:http://guoyb.com/Tech/26.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM