Android流媒體開發之路二:NDK C++開發Android端RTMP直播推流程序


NDK C++開發Android端RTMP直播推流程序

經過一番折騰,成功把RTMP直播推流代碼,通過NDK交叉編譯的方式,移植到了Android下,從而實現了Android端采集攝像頭和麥克縫數據,然后進行h264視頻編碼和aac音頻編碼,並發送到RTMP服務器,從而實現Android攝像頭直播。程序名為NdkRtmpEncoder,在這里把整個過程,和大體框架介紹一下,算是給需要的人引路。

開發思路

首先,為什么要用NDK來做,因為自己之前就已經實現過RTMP推流、RTMP播放、RTSP轉碼等等各種c++實現的流媒體項目,有很成熟的代碼模塊。既然Android有NDK,可以JNI的方式復用之前的成熟代碼,大大拓展和加快項目實現,那為什么不這樣去做呢。和其他平台一樣,要實現采集攝像頭推送直播流,需要實現以下幾點

  • 獲取Android攝像頭數據
  • 對攝像頭數據進行h264編碼
  • 編碼后數據以RTMP協議封裝數據並推送

下面分開來講開發思路:

  1. Android端采集攝像頭原始數據,可以在Java層通過Camera2獲取數據,也可以用NativeCamera通過NDK來獲取,不過后者需要的版本高一些,我考慮了一下,還是決定通過Java層獲取數據,然后再交給下層處理。
  2. h264編碼,可以通過AndroidMediaCodec進行硬件編碼,也可以通過x264進行軟件編碼,這里因為要復用以前的代碼,決定使用軟件編碼來驗證
  3. RTMP協議封裝,這部分代碼,直接使用之前的C++代碼即可,本身就是平台無關的,NDK也是linux環境開發,socket網絡通信都是相通的。具體可以參考我之前的文章“C++實現RTMP協議發送H.264編碼及AAC編碼的音視頻

程序框架

根據我的開發思路,程序框架就顯而易見了:

這里省略了部分內容,比如在so動態庫之上,有一層封裝模塊,供Activity調用

  1. Java層的主要做數據采集。對攝像頭,通過Camera2接口,獲取到更新的Surface,並轉交給Opengl.EGL進行繪制,數據被繪制到TextureView的SurfaceTexture上,同時將RGB原始數據回調給Activity,由Activity把數據轉交給動態庫。 關於Camera2接口獲取攝像頭數據,可以參考之前的文章“Android流媒體開發之路一:Camera2采集攝像頭原始數據並手動預覽”,不同的是,那篇文章里直接使用ImageReader的Surface,這里使用的是自定義的Surface。

  2. 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。(轉載請注明作者和出處~)



免責聲明!

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



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