HEXA娛樂開發日志技術點004——一步到位的推流

HEXA開發日志目錄
上一篇 HEXA娛樂開發日志技術點003——下位機成功推流


顛覆

本篇的成果是,實現了基于raw data的推流。
前一篇是基于flv文件的推流,flv文件的內容是對raw data進行壓縮編碼的產物,而我們從mind SDK獲得的是raw data,是不能用RTMPDUMP直接推流的,所以才有了本篇內容,并對前一篇的內容進行了顛覆,這個顛覆要從下圖說起。

技術需求與技術點

這張圖相對于之前的版本有些變化,左邊技術需求多了個壓縮編碼,右邊技術點中的RTMPDUMPffmpeg取代了,右邊這個變化就是本篇所指的顛覆了。

需求的變化

當初對RTMPDUMP不了解,不清楚它要的是壓縮編碼后的數據,所以沒考慮到壓縮編碼這個必要的數據轉換步驟。

技術點的顛覆

前一篇的部分成果被顛覆的原因是,我只知道ffmpeg可以壓縮編碼,但不知道它還可以直接推流,當我看到雷前輩的例子時,我驚呆了,因為里面沒有一點RTMPDUMP的影子,卻說它可以推流。
在驗證了雷前輩的例子之后,我當時認為,大概是ffmpeg使用了RTMPDUMP的庫吧,因為它們的git地址都出現了ffmpeg.org,既然它們是整整齊齊的一家人,那至少應該是相互有關聯的一群人做出來的吧。對于rtmp推流的功能不會單獨做出兩份相同功能的東西吧。因為我的系統里裝了RTMPDUMP的庫,所以還僥幸地認為多半ffmpegRTMPDUMP之間有依賴關系,直到我把skill中的RTMPDUMP庫刪除,并確認機器人身體里確實沒有了這個庫,還依舊能正常推流之后,我才放棄了僥幸。
這徹底宣告了,我對RTMPDUMP的相關研究,對于目標來說是無用功。

這就是積極前進的人生的常態吧,在對昨天的自己的嘲笑中前進,明知道今天的自己也會被明天的自己嘲笑,但若不做今天的無用功,也無法獲得明天嘲笑今天的資格。

干貨

回顧了昨天的無用功,再來看看今天又搞出了什么幺蛾子。
首先明確一下本篇目標,就是把從raw data到推流這條路打通,這里的raw data還不是從mind SDK獲得的,只是用官方的算法制造的。步驟還是經典三板斧,即研究、上位機demo、移植到下位機

研究ffmpeg

其實算不上什么研究,主要是搞清楚上位機demo的步驟,在考慮如何入手之前,先列一下已知條件:

  • ffmpeg有官方例子可以參考
  • 我在之前的工作中研究并改造過一個官方例子
  • 雷前輩有例子可以參考

下面對已知逐一分析:

  1. 首先,先看一下我研究過的那個例子,這個例子只能編碼視頻,沒有音頻,我并不能拿來用。只是在這個例子的研究中,我知道了如何用新ffmpeg接口替換掉過時的接口。
  2. 然后,我確定了我需要參考的官方例子,這個例子把raw data壓成了flv文件,而前一篇正好是以flv文件作為輸入的,我當時想,一定可以在這兩者之間建立數據連接,而不必生成flv文件,這樣輸入是raw data,輸出是推流,本篇的目標就達到了。這時的產出是61dd400e0323bd242e5242ec01608c594373cde0。在這個修改中,我把這個例子的過時接口都換成了新的,并且編譯OK了,然后待用。
  3. 最后,我看到了雷前輩的例子,從這個例子可以看出,我根本不用考慮如何與RTMPDUMP建立數據連接,只要對例子改一下輸出方式,就可以直接推流啦。

至此,第一板斧砍完。

上位機demo

這個階段就三步,先驗證例子的有效性,再驗證改造的例子的推流功能的有效性,最后用GO語言調用測試。
第一步很順利,沒有單獨提交。
第二步,即C語言部分的提交是f51f070eeb2b3a0a7827519d58d6a3c27bb7ce23,可以看到修改很簡單,如果真去嫁接RTMPDUMP,工作量得比這個大得多得多得多。。。
第三步,加入GO語言部分的提交是cf0d3e304a5a824c6912a8e3b2b13975c990e8c8,其中的demo_ffmpeg.c是基于test.c修改的,主要是把生產raw data的函數改成了call back,這樣就可以在GO語言里實現raw data的生成,至少從C部分來看,整個流程就和最后實際的使用方式完全一樣了。而對于GO語言部分,后面再把生產raw data的方法改成從攝像頭和話筒獲取就行了,當然這是后話了。

至此,第二板斧砍完。

移植到下位機

移植也是之前的套路,先編譯C依賴庫,然后GO程序與mind SDK對接。

ffmpeg的交叉編譯

這里先感謝某位哥們兒的幫助,把他以一般Ubuntu為目標平臺的編譯方法提供給我做參考。
可惜的是,后面還是有東西要探索,最關鍵的就是交叉編譯所帶來的麻煩,最后的configure命令長這樣:

./configure --prefix="/go/src/skill/FFmpeg" \
--extra-cflags="-I/go/src/skill/FFmpeg/include" \
--extra-ldflags="-L/go/src/skill/FFmpeg/lib" \
--bindir="/go/src/skill/FFmpeg/bin" \
--enable-cross-compile \
--cross-prefix=arm-linux-gnueabihf- \
--cc=arm-linux-gnueabihf-gcc \
--disable-x86asm --arch=armv4 --target-os=linux \
--disable-static --enable-shared \
--disable-ffmpeg --disable-ffplay --disable-ffprobe
make
make install
  • 帶有cross字樣的都與交叉編譯有關,還有cc指定了交叉編譯器
  • 要生成動態庫,--enable-shared是要加的,我不需要靜態庫就加了--disable-static
  • -disable-ffmpeg -disable-ffprobe -disable-ffplay是說不需要生成這些可執行程序,因為我只需要依賴庫

相對于對接mind SDK,編譯ffmpeg還是麻煩一點,以為它的編譯選項比較復雜,有些選項好不好用、該不該用,都變成了很隨緣的事情,這些選項也是我慢慢摸索出來的。

GO程序對接mind SDK

關于對接mind SDK,修改是ca44359aebc9d2729cd9213f6c126a9be1722c34,雖然文件多,但是并不復雜。

  • 增加ffmpeg的頭文件(DanmuDriveMe/robot/deps/include下面多個文件)
  • 增加ffmpeg的庫文件(DanmuDriveMe/robot/deps/lib下面多個文件)
  • 刪除RTMPDUMP相關的文件,包括頭文件、庫文件和GO文件
  • ffmpeg demo對接mind SDK,這些是核心修改,只有5個文件

邏輯和上位機demo大同小異,關于對接mind SDK不做詳細解釋了,只說一個GO與C混合編程的小坑,一個坑了我若干小時的小坑,具體看下面注釋吧。

func stream_start(url string) {
    //這個cc是C語言部分的buffer
    cc := C.CString(url)
    //defer是說在即將退出這個函數時執行后面語句,即在退出stream_start函數之前會把cc free掉
    defer C.free(unsafe.Pointer(cc))
    if stream_control(true) {
        log.Debug.Println("url:["+url+"]")
        //setup是C函數,里面會使用cc
        go C.setup(cc)
        //go語句是非阻塞的,如果沒有這個sleep,stream_start函數就會很快返回,這意味著cc很快會free
        // avoid to free cc too early
        time.Sleep(time.Second)
    }
}

要注意上面代碼中的2件事的順序,即cc的釋放和使用的順序,我被坑的原因就是,cc先被釋放了,然后才被使用,并且我還不知道怎么才能看到C部分的log,對C部分的debug手段很笨拙,所以花很長時間才懷疑到這。
cc被釋放的原因是stream_start函數很快返回了,那么基于defer語句的機制,cc就很快被釋放了,而go語句是非阻塞的,從cc傳入setup到被使用,需要一段時間,所以函數最后要加一個sleep,保證在這段時間內,函數不會返回,cc也就不會在使用前被釋放。
當然,還應該有其他解決方法,比如不在GO這邊釋放cc,在C部分釋放也許也能行。

至此,第三板斧砍完。

總結

  • ffmpeg替代了RTMPDUMP,一步到位地完成了壓縮編碼和推流
  • 下位機推流還有點問題,可以在播放端看到,似乎是推流的速度不夠,出現了視頻網站那種放一會兒就要緩沖一下的現象,具體原因有待分析
  • 下面計劃是對機器人采集的音視頻raw data進行推流,以及用OpenCV處理圖像
  • 這些事情的草還沒發芽,包括彈幕命令集、機器人命名等

下一篇 HEXA娛樂開發日志技術點005——死而復生之Gstreamer推流

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容