標籤:tom 一起 text 技術分享 hive tps 興趣 模式 camera2
NDK開發Android端RTMP直播推流程式
經過一番折騰,成功把RTMP直播推流代碼,通過NDK交叉編譯的方式,移植到了Android下,從而實現了Android端採集網路攝影機和麥克縫資料,然後進行h264視頻編碼和aac音頻編碼,並發送到RTMP伺服器,從而實現Android網路攝影機直播。程式名為NdkRtmpEncoder,在這裡把整個過程,和大體架構介紹一下,算是給需要的人引路。
開發思路
首先,為什麼要用NDK來做,因為自己之前就已經實現過RTMP推流、RTMP播放、RTSP轉碼等等各種c++實現的流媒體項目,有很成熟的代碼模組。既然Android有NDK,可以JNI的方式複用之前的成熟代碼,大大拓展和加快項目實現,那為什麼不這樣去做呢。和其他平台一樣,要實現採集網路攝影機推送直播流,需要實現以下幾點
- 擷取Android網路攝影機資料
- 對網路攝影機資料進行h264編碼
- 編碼後資料以RTMP協議封裝資料並推送
下面分開來講開發思路:
- Android端採集網路攝影機未經處理資料,可以在Java層通過Camera2擷取資料,也可以用NativeCamera通過NDK來擷取,不過後者需要的版本高一些,我考慮了一下,還是決定通過Java層擷取資料,然後再交給下層處理。
- h264編碼,可以通過AndroidMediaCodec進行硬體編碼,也可以通過x264進行軟體編碼,這裡因為要複用以前的代碼,決定使用軟體編碼來驗證
- RTMP協議封裝,這部分代碼,直接使用之前的C++代碼即可,本身就是平台無關的,NDK也是linux環境開發,socket網路通訊都是相通的。具體可以參考我之前的文章“C++實現RTMP協議發送H.264編碼及AAC編碼的音視頻”
程式架構
根據我的開發思路,程式架構就顯而易見了:
這裡省略了部分內容,比如在so動態庫之上,有一層封裝模組,供Activity調用
Java層的主要做資料擷取。對網路攝影機,通過Camera2介面,擷取到更新的Surface,並轉交給Opengl.EGL進行繪製,資料被繪製到TextureView的SurfaceTexture上,同時將RGB未經處理資料回調給Activity,由Activity把資料轉交給動態庫。 關於Camera2介面擷取網路攝影機資料,可以參考之前的文章“Android流媒體開發之路一:Camera2採集網路攝影機未經處理資料並手動預覽”,不同的是,那篇文章裡直接使用ImageReader的Surface,這裡使用的是自訂的Surface。
C++層實現對未經處理資料進行編碼,並按照RTMP資料包進行封裝,然後推送到RTMP伺服器。這部分可以參考以前的文章“C++實現RTMP協議發送H.264編碼及AAC編碼的音視頻”。
交叉編譯
這部分也是主要工作之一,c++代碼要想在Android上使用,必須編譯成動態庫,然後讓APP通過JNI來調用。本質上,Android也是linux嘛,所以跟其他嵌入式arm-linux的交叉編譯方式,本質上是差不多的,當然,前提是系統內布置好交叉編譯環境。熟悉NDK的應該都知道,Google提供了完整的編譯工具鏈,也包括SDK,在這裡:“NDK Downloads”。我是在Ubuntu Linux上來做的,所以選擇“Linux 64-bit(x86)”版本,記得Linux環境必須是64位,不然你什麼都編譯不了。
解壓後其實就可以開始了。不過這裡還是有兩種編譯方式:第一種就是類似其他arm-linux環境,配置好交叉編譯工具鏈環境,然後直接按照普通的linux編譯方式進行編譯;第二種是編寫Android.mk檔案,然後用NDK裡提供的ndk-build指令碼進行編譯。
1. 工具鏈方式
對第一種方式來說其實比較簡單,安裝好交叉編譯工具鏈之後,配置一下環境,就可以編譯了。比如如下配置
這樣基本就可以了,當然不同項目可能還需要進一步的修改配置,make之前需要執行configure等,但大致如此。
2. ndk-build方式
對Android.mk來說,跟Makefile差別是很大的,有它自己的文法,它在整個編譯過程中的位置,可能更接近於automake工具裡Makefile.am。關於它的文法,參見我下面的mk檔案,做了一些注釋,可以協助理解,具體的文法可以參考官方網站Android Developer。我在這裡把我rtmp_enc_sdk.so動態庫的Android.mk的主要內容貼出來,大家可作參考。
模式基本是一樣的,按照這個模板,修改成你自己項目裡使用並不困難。
關鍵代碼
不管是Java層還是C++層的代碼其實都不少,不過之前幾篇文章裡已經有關於他們的邏輯結構和實現方法的介紹,有興趣的可以參考,按照文章裡寫的架構去理解,相信都可以實現。我這裡把Java層對網路攝影機捕獲到資料以後的處理邏輯的代碼貼一下。
1 當TextureView有效之後,開始建立工作。首先要產生一個OES SurfaceTexture,後面要把它傳遞給Camera2介面,用於接收網路攝影機畫面,之後開始建立RTMP推流模組調用線程,並建立網路攝影機捕獲模組,和渲染模組
2 當OESTexture畫面有效之後,擷取網路攝影機畫面的實際解析度,以及旋轉矩陣,畫面旋轉資訊等,封裝在一起,交給EGLRender,通知渲染模組進行畫面渲染
3 渲染模組繪製完資料後,讀取RGB未經處理資料並回調,在這裡交給Rtmp發送線程,調用動態庫,完成最後h264編碼,並推送到RTMP伺服器,這下面就是c++層so動態庫做的事情了
運行效果
在手機端RTMP推流畫面:
在PC上用flash播放RTMP直播畫面:
haibindev.cnblogs.com,合作請聯絡QQ。(轉載請註明作者和出處~)
Android流媒體開發之路二:NDK開發Android端RTMP直播推流程式