1. 程式人生 > >2019年終總結&小半年流媒體伺服器開發經驗總結

2019年終總結&小半年流媒體伺服器開發經驗總結

目錄

  • 2019年終總結&小半年流媒體伺服器開發經驗總結
    • 19年開發小結
      • 流媒體服務框架設計
      • 登入服開發
      • ffmpeg音視訊服務開發
      • 音視訊控制
    • 流媒體服務開發小結
      • rtp處理
      • 視訊的合成&音視訊緩衝區
      • 音視訊編碼
    • 回顧19展望20

2019年終總結&小半年流媒體伺服器開發經驗總結


時間轉瞬即逝,轉眼間19年已經過去了,人愈來愈來老,卻不見人心和物質的提升,期望2020年能有一個嶄新的自己。

今年因為發展原因,從嵌入式跳槽做網際網路後端了,幹了一年突然轉行,自己也很糾結這麼做對不對,但歸根結底我只是選擇了做自己想做的事情,從事自己想做的工作罷了。

雖然過來後發現也不併算真正意義上的後端工作,用到的後端技術並不多,主要時間掙扎在了流媒體的開發,音視訊的編解碼,濾波、硬體加速、rtp、音視訊格式(aac、pcm、h264)、另外主管選擇了開源的ffmpeg庫、這些七七八八的東西夠你折磨了。。

19年開發小結

流媒體服務框架設計

基於公司專案需求設計流媒體伺服器,考慮到擴充套件性,採用了主流的多程序模型便於後期做分散式,同時解耦業務層與音視訊處理層,便於更替音視訊處理方案。

登入服開發

基於公共協議棧,管理使用者登入、連線音視訊服務、使用者資料快取、使用者出入音視訊服務動態等、迎合docker特點、單獨使用者資料快取儲存使用者資料。

ffmpeg音視訊服務開發

主要包括音視訊相關內容的開發,也是開發投入時間最長的服務,主要經歷了以下過程。

1)、最初基於ffmpeg的h264軟解實現服務demo.

2)、然後嘗試基於英特爾vaapi硬體加速驅動做h264硬解,對解碼視訊幀做軟體overlay濾波進行音視訊合成,再做vaapi硬編碼。
優點是此流程軟體實現上會更為簡潔快速,也比較穩定。
但是後面發現系統會時不時crash。從系統日誌上沒有找到相關日誌,於是進行了長期的軟體模組排除法檢查問題原因,做了解碼、解碼+濾波、濾波+編碼等單元模組組掛機測試,仍然無法找到系統crash問題原因。
同時也在微軟的github倉庫提交了bug/issue,但是回覆較慢。

3)、起初懷疑是vaapi驅動問題,於是嘗試使用英特爾qsv硬體加速驅動硬解,對解碼視訊幀做硬體overlay_qsv濾波進行音視訊合成,再做qsv硬編碼。
優點是音視訊處理全交付於gpu處理,省下大片cpu時間。缺點是硬體幀上下文關係密切,做視訊自動切換上,需要做更多軟體處理,編碼上略微複雜。
可惜系統crash問題依然存在。

4)、ffmpeg原生工具命令列測試系統crash問題,發現確實有這個問題,而且更換很多個ffmpeg版本都會出現,只是概率可能會有浮動:快的幾分鐘到幾小時crash、慢的一星期可能不會出現,但是不改任何引數再次嘗試依然可能crash.

5)、移植音視訊服務從linux到windows系統下、經過長期測試windows下執行intel加速方案確實沒有系統宕機問題了、同時因為登入服基於muduo庫實現,移植複雜,改將登入服打包進docker容器執行。

6)、完善及優化音視訊服務框架及功能。包括:新增適當rtp快取解決公網環境udp包波動問題、新增音視訊同步機制、增加相應業務功能介面。

7)、移植到微服務框架,進一步增強程式擴充套件性。

音視訊控制

1、建立房間:單機能建立的房間數量是有限的,但是要控制畫質流暢不丟幀,瓶頸在於視訊合成流數量和硬體效能(核心數越多可以適當降低丟幀率,intel驅動效能瓶頸)、
可以堆音視訊服務機器解決這個問題,但是體感價效比並不高。

2、直播房間的增、刪、改、查。

3、多路流輸入下、可指定流合成數量、或者、自動根據流數量合成。

4、 去除音訊迴音、單條流的音訊開關。

5、 配置視訊profile level、 獲取幀率、丟包率等。

6、其他。

流媒體服務開發小結

rtp處理

rtp完全是自己解的,沒有用ffmpeg的avformat庫,這樣我更便於管理網路處理部分。

需要注意的是udp在公網上可能存在網路抖動問題,服務端接收到的udp包不一定能按序到達,也可能存在丟包等問題,你需要開一塊rtp快取,按seq做最小堆。我直接用的golang的heap包實現的。

然後實際上也可以按相對時間戳來heap的compare,這樣也方便你做音視訊同步,記錄第一個到達的rtp包時間戳、後續rtp的時間戳按timestamp的增量做時鐘的換算,換算成一個浮點時間來排序。
例如 h264 90000的時鐘 、 30的幀率 、 : 那麼 3000時間戳增量 代表 3000 / 90000 = 33.33333ms

然後就是rtp時間的同步 : av_rtp_handler所有rtp包都帶了我一個換算出來的相對時間戳的、 我只需要將音視訊的包做一次最小堆插入、每次去取堆頂時間戳最小的rtp包即可、 是音訊包就丟進音訊解碼器、視訊包就丟進視訊解碼器。

視訊的合成&音視訊緩衝區

我想了很久音視訊進行合成結構後發現有一個很重要的東西、那就是音視訊幀的緩衝區、而且這個緩衝區真的很重要、它能做到以下效果:

1、控制幀率

2、解決多路流的音視訊幀抖動問題

1、 通過一個定時器、你能很方便的控制幀率、例如隔33ms往合成器傳送一組音視訊幀進行合成即可。修改幀率你只需要更改定時器的種子值。

2、消抖、每路流到達的時間肯定是不穩定的、可能通道3一下子除了了5包資料、一下子來了10幀資料、而其他路還只有1到2幀或者沒有、但是你要保持實時性肯定不能把所有幀全部儲存下來、所以你必須控制每路的緩衝大小得把擠出來的非I幀刪掉、注意是非I幀不然可能會花屏。

然後就是音視訊合成、音訊用amix、視訊用overlay、

視訊幀合成麻煩在qsv有一個硬體幀上下文、qsvframecontext每次做螢幕的自動切換、或者螢幕位置交換、需要重新生成filter、而你就需要費工夫去更新這個qsvframecontext 極為麻煩、後面想到的方法是設計一張ffmpeg filter輸入的對映

就是在不該ffmpeg濾波器描述符的情況下、而是直接交換filter的輸入位置。

一個草圖將就下: 相當於 就是打亂正當的輸入順序、做一張對映、這樣子不用更改filter的描述符即可做濾波器的切換,要便利極多!

音訊合成沒什麼好說的、就是每路的輸出可能不能包含自己的通道聲音、不然可能存在迴音、你只需要弄個set記錄需要合成的流輸入id的集合、合成的時候把自己的id去掉再合成就行了。

音視訊編碼

編碼好像沒什麼重點東西、打包的時候打上個合適的時間戳即可。

回顧19展望20

今年其實挺累的、第一次一個人從零寫了一整套流媒體服務、以及整個系統框架的搭建、最後也學習了主流後端框架、移植到了微服務框架上。雖然做了很多事但是收穫也多多。希望未來能有更好的發