天天看點

Android 音視訊開發——錄屏直播

觀看手遊直播時,我們觀衆端看到的是選手的螢幕上的内容,這是如何實作的呢?這篇部落格将手寫一個錄屏直播 Demo,實作類似手遊直播的效果

擷取螢幕資料很簡單,Android 系統有提供對應的服務,難點在于傳輸資料到直播伺服器,我們使用 RtmpDump 來傳輸 Rtmp 資料,由于 RtmpDump 使用 C 語言實作,我們還需要用到 NDK 開發,單單用 Java 無法實作哈,當然如果不怕麻煩的話,還可以自己編譯 Ffmpeg 實作 Rtmp 推流,B 站開源的 ijkplayer 播放器也是基于 Ffmpeg 來開發的

最終我們推流到 B 站直播間,在直播間能夠實時看到我們手機螢幕上的畫面

Android 音視訊開發——錄屏直播

擷取錄屏資料

對資料進行 h264 編碼

Rtmp 資料包

上傳到直播伺服器推流位址

通過 Intent 擷取到 MediaProjectionService,繼而擷取到 Mediaprojection 的 VirtualCanvas,我們錄屏的原始資料就是從中得來的

通過 MediaProjection 擷取到的 YUV 裸資料,我們先需要對其進行 h264 編碼,此時我們使用原生 MediaCodec 進行硬體編碼

經過上面兩步,我們獲得了編碼好的 h264 資料,接下來封裝 Rtmp 就比較頭疼了(Ndk 的知識都忘得差不多了)

首先我們在項目的 cpp 檔案中,把 Rtmpdump 的源代碼導入,我們使用 rtmpdump 連接配接伺服器,以及傳輸 Rtmp 資料,要知道目前手裡的資料還是 h264 碼流,是無法直接傳輸,需要封裝成 Rtmp 資料包

使用第三方庫 Rtmpdump 來實作推流到直播伺服器,由于 Rtmpdump 的代碼量不是很多,我們直接拷貝源代碼到 Android 的 cpp 檔案,如果需要用到 Ffmpeg 不能才用該種調用方式了,需要提前編譯好 so 庫檔案

對 Rtmp 暫時不需要做太深刻的了解,因為很容易給自己繞進去,用 Rtmp 傳輸 h264 資料,那麼 sps,pps ,以及關鍵幀怎麼擺放,Rtmp 都已經規定好了,我們就需要使用 NDK 的方式,實作 rtmp 資料的填充

Android 音視訊開發——錄屏直播

連接配接伺服器

RTMP_Init(RTMP *r) 初始化

RTMP_EnableWrite(RTMP *r) 配置開啟資料寫入

RTMP_Connect(RTMP *r, RTMPPacket *cp)

RTMP_ConnectStream(RTMP *r, int seekTime)

發送資料

RTMPPacket_Alloc(RTMPPacket *p, int nSize)

RTMP_SendPacket(RTMP *r, RTMPPacket *packet, int queue)

RTMPPacket_Free(RTMPPacket *p)

這一步中,需要預先準備直播推流位址,然後實作 native 方法

Android 音視訊開發——錄屏直播

有意思的是,Rtmp 協定中不需要傳遞分隔符(h264 分隔符為 0 0 0 1),并且推流的第一個 Rtmp 包的内容為 sps、pps 等

malloc 隻管配置設定記憶體,并不能對所得的記憶體進行初始化,是以得到的一片新記憶體中,其值将是随機的,申請的記憶體是連續的

傳回類型是 void* 類型,void* 表示未确定類型的指針。C/C++ 規定,void* 類型可以強制轉換為任何其它類型的指針,malloc 函數傳回的是 void * 類型,C++:p = malloc (sizeof(int)); 則程式無法通過編譯,報錯:“不能将 void* 指派給 int * 類型變量”。是以必須通過 (int *) 來将強制轉換

首先我們通過系統服務拿到手機螢幕的畫面,此時取到的原始資料還無法進行網絡傳輸,在對其進行 h264 編碼後,封裝 Rtmp 包,然後按照 Rtmp 協定規定的方式進行傳輸

​​音視訊技術之——抖音視訊編碼實戰​​

​​Android 音視訊——實戰之從零實作視訊流推流到哔哩哔哩​​

​​H265為何比H264壓縮比更高,品質更清晰,從編碼原理了解真相​​

​​Android 音視訊進階實戰​​