FFmpeg優化點播延時方案

場景要求
            項目要求點播速度是300到500毫秒之間,如今最長的點播延時是1300毫秒(有的時候甚至沒法播放視頻),生產環境是RTSP傳輸h264裸流數據,研究在接收到I幀的時候,開始出來圖像,簡化FFmpeg的調用邏輯(SPS/PPS已經預先知道,而且分辨率也是固定爲1920*1080)

解決方案
1)指定SPS/PPS參數,方便在調用avcodec_open2函數打開×××的時候,找到正確的視頻參數
https://blog.51cto.com/fengyuzaitu/2058138

2)經過指定視頻碼流格式H264減小探測時間
關鍵函數是:avformat_open_input和avformat_find_stream_info
https://blog.51cto.com/fengyuzaitu/1573766
https://blog.51cto.com/fengyuzaitu/1982996


3)核心是要求發送端發送的第一幀:強制I幀,根據以下的其餘的方案指定碼流的格式

4)用戶新加入流媒體轉發隊列,流媒體推送用戶的第一幀,不必定是I幀(這一幀以前的SPS/PPS不能少),用戶須要等待一段時間才能看到畫面,直到I幀的出現隨着GOP的增大,時間可能更長。爲了解決問題,須要緩存整一個GOP的圖像序列,單純保存I幀,沒有效果,由於每個P幀都會依賴以前的P幀,相似於後面的圖片是前面圖片效果的疊加。新增長的用戶,先發送緩存的GOP序列,而後才發送剩下接收的數據

相關問題點有待研究
1)avformat_open_input取消問題的優化
在代碼中指定以下:        
AVInputFormat* pAVInputFormat = av_find_input_format("h264");
pAVFormatContext->iformat = pAVInputFormat;
//if (avformat_open_input(&pAVFormatContext, "", pAVInputFormat, NULL) < 0)
若是不調用avformat_open_input函數實際上,影響到的是av_read_frame(pVideo->m_pAVFormatContext, packet)
出錯提示:
No start code is found
Error splitting the input into NAL units
實際上av_read_frame關鍵做用是從緩衝中拆分出一個個NAL單元(每個NAL單元都是從00 00 00 01做爲開始碼,開始的),
目前的解決方案是手動本身進行NAL單元的拆分,而後送到av_send_packet進行分幀解碼(從而也取消了
av_read_frame函數的調用),手動拆分出NAL,有點麻煩

正在研究的是avformat_open_input可能會填充pAVFormatContext的URLProtocol協議字段,不過這已是FFmpeg底層函數,
可能不可訪問,正在分析源碼

2)non-existing PPS 0 referenced問題
在調用av_read_frame函數的時候,會提示如上錯誤
non-existing PPS 0 referenced
decode_slice_header error
no frame!

可是實際上,手動添加SPS/PPS的內容到extradata字符串中,
unsigned char sps_pps[] = { 0x00 ,0x00 ,0x01,0x67,0x42,0x00 ,0x2a ,0x96 ,0x35 ,0x40 ,0xf0 ,0x04 ,0x4f ,0xcb ,0x37 ,0x01 ,0x01 ,0x01 ,0x40 ,0x00 ,0x01 ,0xc2 ,0x00 ,0x00 ,0x57 ,0xe4 ,0x01 ,0x00 ,0x00 ,0x00 ,0x01 ,0x68 ,0xce ,0x3c ,0x80, 0x00 };
pAVFormatContext->streams[0]->codecpar->extradata_size = sizeof(sps_pps);
pAVFormatContext->streams[0]->codecpar->extradata = (uint8_t*)av_mallocz(pAVFormatContext->streams[0]->codecpar->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
memset(pAVFormatContext->streams[0]->codecpar->extradata, 0, sizeof(sps_pps) + FF_INPUT_BUFFER_PADDING_SIZE);
memcpy(pAVFormatContext->streams[0]->codecpar->extradata, sps_pps, sizeof(sps_pps));

FFmpeg須要經過分析數據來肯定輸入格式,全部程序啓動時,ffmpeg收到的數據最早應該是SPS與PPS的nalu單元,而後是具體的視頻數據

相關博客
https://blog.51cto.com/fengyuzaitu/2058138
https://blog.51cto.com/fengyuzaitu/2057885

3)若是知道了碼流格式,實際上不須要調用什麼探測碼流格式的函數,直接調用AVCodecContext解碼,就能夠
目前在網上沒有相關的資料


FFmpeg日誌定向輸出到文件
https://blog.51cto.com/fengyuzaitu/2053210
avcodec_send_packet函數錯誤定位
https://blog.51cto.com/fengyuzaitu/2046171

相關資料
1)http://www.yidianzixun.com/news_1eff46dc583b688d33a557b5582745dc
MP4的H264視頻數據保存在名爲mdata的box當中,MediaRecorder經過socket發送出來的MP4數據包含四部分:填充符、ftyp、mdat、slice。
其中slice就是咱們要找的視頻數據,slice是mdata的一部分,slice與mdata之間可能存在填充符,而slice與slice之間是連在一塊兒的。
slice由視頻數據長度(4字節,前兩個字節一般爲0)和視頻數據組成,其中視頻數據是不帶起始碼的H264 Nalu單元,
不難看出其第一個字節爲0x65(關鍵幀)、0x41等。數據長度描述的是 H264 Nalu單元的長度,這樣咱們已經找到一幀完成的H264碼流數據了,
接下來咱們只需將 Nalu單元提取出來前面加上0x00 00 00 01的4字節起始碼咱們就獲得了H264裸數據,這樣的數據在播放器上還不能播放,
需在H264裸數據文件的最前端加上SPS與PPS信息(他們也是有起始碼的哦),至此,播放器可以正常播放文件了前端

相關文章
相關標籤/搜索