直播帶貨系統是如何實現直播錄屏的
一、概述
在視訊會議、線上課堂、遊戲直播,直播帶貨系統等場景下,螢幕共享是一個最常被用到的功能。要實現對螢幕畫面的實時共享,端到端主要有幾個步驟:錄屏採集、影片編碼、實時傳輸、影片解碼、影片渲染。
一般來說,實時螢幕共享時,共享發起端以固定取樣頻率(一般 8 - 15幀)抓取到螢幕中指定源的畫面(包括指定螢幕、指定區域、指定程式等),直播帶貨系統經過影片編碼壓縮(選擇保持文字/圖形邊緣資訊不失真的方案)後,在實時網路上以相應的幀率分發。
下面我們將介紹基於不同端,實現錄屏採集的方法。
二、原理
在分享如何實現直播帶貨系統Android系統錄屏採集前,我們先來看看其背後的原理。
Android 在 4.4 版本前要實現螢幕錄製必須獲取到 root 許可權,但目前大部分裝置的系統版本都高於4.4,因此這種情況在此就不作贅述。
在 5.0及以上版本,我們可以利用系統提供的 MediaProjection 和 MediaProjectionManager 進行螢幕錄製,可以不需要獲取 root 許可權,但會彈窗獲取許可權,需要使用者同意才行。
那麼在Android5.0及以上版本,我們使用 MedaProjection 是如何把螢幕的資料錄製下來呢?
這裡我們就要說到兩個“助攻的小夥伴”了——Surface 和 VirtualDisplay。
1、Surface
> Handle onto a raw buffer that is being managed by the screen
> compositor.A Surface is generally created by or from a consumer of
> image buffers (such as a SurfaceTexture ,MediaRecorder , or Allocation
> ), and is handed to some kind of producer (such as OpenGL ,MediaPlayer
> , or CameraDevice ) to draw into.
Google 官網對 Surface 的定義是:Surface 就是螢幕資料消費者(如 SurfaceTexture,MediaRecorder,Allocation)提供給螢幕資料的生產者(如 OpenGL,MediaPlayer,CameraDevice)的一塊資料緩衝區,生產者們可以在 Surface 上進行影像內容的生產,消費者們會把生產出來的資料消費到螢幕上面(繪製出來)或者是轉換成消費者所希望的資料。
2、VirtualDisplay
顧名思義,這個便是系統提供的一個虛擬螢幕,我們採用 MediaProjection 進行錄製,就需要建立這樣一個 VirturalDisplay 。那麼,這個 VirturalDisplay 和 Surface 有什麼關聯呢?屬於生產者還是消費者呢?
答案非常明顯,VirturalDisplay 屬於生產者,因為 VirturalDisplay 是系統的一個虛擬螢幕,其內容可以理解為手機物理螢幕的複製,只是僅存在於記憶體中,而沒有繪製出來,所以我們無法看到這個螢幕而已,那麼既然是手機螢幕的映象,相對於螢幕錄製的整個架構來說,自然就是生產者了。
OK,現在清楚了這兩個助攻的小夥伴的特點,我們還要思考一個問題,現在緩衝區有了,生產者有了,那消費者呢??螢幕資料應該給誰消費呢?
這就涉及到了場景問題。Android 允許我們把螢幕資料透過 MediaRecorder 錄製下來然後儲存,也允許我們把螢幕資料錄製下來透過 MediaCodec 進行編碼,然後傳輸出去。
因此根據上面的原理,我們可以畫出以下螢幕採集的整體架構圖:
三、實現
上面我們已經清楚了整個直播帶貨系統螢幕錄製的原理,那麼在程式碼層面,我們應當如何實現呢?主要分為以下幾步:
第一步,申請許可權。在 AndroidManifest 加上申請許可權的程式碼,因為我們需要用到音訊錄製。
```
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
```
第二步,獲取直播帶貨系統服務。透過 MediaProjectionManager 獲取一個系統服務,這個系統服務需要獲取使用者授權:
```
mMediaProjectionManager = (MediaProjectionManager)
getSystemService(MEDIA_PROJECTION_SERVICE);
```
MediaProjectionManager 是系統提供的一個錄屏服務,在使用上和其他的系統服務沒有太大的區別,都是透過 getSystemService 獲取對應的服務。
第三步,建立 Intent 跳轉服務。MediaProjectManager 已經封裝了獲取 Intent 的方法 createScreenCaptureIntent, 拿到 Intent 之後,當呼叫 startActivityForResult 方法時,會觸發一個請求授權的彈窗,當使用者同意授權或者拒絕授權,都會透過 onActivityResult 返回。
```
Intent captureIntent= mMediaProjectionManager.createScreenCaptureIntent();
startActivityForResult(captureIntent, REQUEST_CODE);
```
第四步,監聽 onActivityResult 根據使用者授權返回的結果獲取
```
MediaProjection
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
mMediaProjection = mMediaProjectionManager.getMediaProjection(resultCode,
data);
}
}
```
在這裡我們才是獲取到了真正的螢幕錄製操作物件—— MediaProjection,接下來我們就需要透過這個物件去開啟螢幕錄製。
第五步,建立虛擬螢幕。我們已經獲取到了 MediaProjection,接下來就是要建立一個虛擬螢幕——VirtualDisplay,這一步是螢幕錄製的關鍵所在,我們先來看看 MediaProject 官網的 API 是如何建立一個 VirtualDIsplay的,重點看看引數的定義。
```
public VirtualDisplay createVirtualDisplay(@NonNull String name,
int width, int height, int dpi, int flags, @Nullable Surface surface,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler)
```
對於建立虛擬螢幕的 API ,其他引數可以先忽略,但其中有兩個引數我們需要注意,一個是 Surface surface ,一個是 int Flag 。
首先是 int Flag ,從這個引數的命名上來看,我們知道這是一個標誌位,從 Android 的習慣來看,這個標誌位可以傳遞什麼引數呢?我們看看註釋。
```
* @param flags A combination of virtual display flags. See {@link DisplayManager}
for the full
* list of flags.
```
根據註釋,我們可以看到 DisplayManager 提供了以下相關的 Flag:
那麼,提供的這幾個 Flag 有什麼區別呢?
VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR:當沒有內容顯示時,允許將內容映象到專用顯示器上。
VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY:僅顯示此螢幕的內容,不映象顯示其他螢幕的內容。
VIRTUAL_DISPLAY_FLAG_PRESENTATION:建立簡報的螢幕。
VIRTUAL_DISPLAY_FLAG_PUBLIC:建立公開的螢幕。
VIRTUAL_DISPLAY_FLAG_SECURE:建立一個安全的螢幕
一般如果沒有特殊的需求,我們將這個 Flag 設定為 VIRTUAL_DISPLAY_FLAG_PUBLIC 就可以了,這樣就可以獲取到螢幕的資料了。
然後是Surface ,這不就是我們前面說的助攻小夥伴嘛。我們前面說過了,這個 Surface 是由消費者去建立的。因此,這時候就要想想我們的消費者是什麼?我們的場景是什麼?是要錄製成檔案還是編碼成資料傳輸出去實現錄屏直播呢?
當然…… 這個終極問題最後可能是要產品經理來決定……o(╯□╰)o
1、螢幕錄製儲存(MediaRecoder)
好了,假設現在產品經理已經明確表示,需求場景是直播帶貨系統把螢幕錄製成檔案儲存下來,就像現在很多市面上的螢幕錄製 APP 一樣。那我們應該怎麼做呢?
其實很簡單,我們只需要想一下,有沒有什麼 API 是可以將影像資料錄製儲存成檔案的呢?
Android 官方就已經有提供了一個工具供我們使用,那就是 MediaRecoder ,重點是 MediaRecoder 可以透過 getSurface 對外提供一個 Surface,而這個 Surface 剛好是 VirtualDisplay 所需要的,所以整個呼叫鏈和 API 我們可以理清楚了,如下圖。而資料的流向則是相反的,從 VirturalDisplay -> Surface -> MediaRecoder(綠色箭頭表示資料的流向)。
那麼 MediaRecoder 要怎麼使用呢?MediaRecoder 不僅可以錄製影片畫面,還可以錄製音訊。下面提供瞭如何設定 MediaRecoder 的程式碼。最後,只要呼叫一下 mediaRecorder.start() 就會啟動錄製,並將錄製好的影片畫面和 MIC 採集到的聲音儲存到我們定義的檔案中。
```
private void initRecorder() {
File file = new File(Environment.getExternalStorageDirectory(),
System.currentTimeMillis() + ".mp4");
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mediaRecorder.setOutputFile(file.getAbsolutePath());
mediaRecorder.setVideoSize(width, height);
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mediaRecorder.setVideoEncodingBitRate(5 * 1024 * 1024);
mediaRecorder.setVideoFrameRate(30);
try {
mediaRecorder.prepare();
} catch (IOException e) {
e.printStackTrace();
}
}
```
2、錄屏直播
如果此時產品經理突然要改需求,想把直播帶貨系統錄製成檔案改成錄屏直播(那也是沒辦法的事o(╯□╰)o)。那我們就要改變方案了,把資料的消費者 MediaRecorder 換成其他可以編碼的工具,比如 Android 自帶的硬體編碼 MediaCodec或者大名鼎鼎的FFmpeg。但是資料的生產者不會變,依然是VirtualDisplay,資料緩衝依舊是Surface。
以 MediaCodec 為例,關於 MediaRecoder 的流程圖則變為:
MediaCodec 作為 Android 系統提供的硬編/硬解能力,本身便可作為一次專題進行分享,因此,這裡不會太深入的分享關於 MediaCodec 的功能和使用方式,只是作為一個消費者的角度和我們的螢幕錄製直播方案進行分享。
```
mEncoder = MediaCodec.createEncoderByType(MIME_TYPE);
mEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
mInputSurface = mEncoder.createInputSurface(); //這⾥輸出的 Surface 可以輸⼊給
VirtualDisplay
//直接開啟編碼器
mEncoder.start();
```
四、延伸
透過以上內容我們知道,MediaRecoder 支援錄製 MIC 採集的音訊資料和MediaProjection 提供的螢幕畫面資料。然而 MediaProjection 不能提供音訊資料,如果我們想透過 MediaRecoder 錄製 MediaProjection 提供的螢幕畫面資料加上非 MediaRecoder 指定的音訊源呢?比如我們錄製一個遊戲影片,但是想加入對應的音訊,類似於王者榮耀的精彩片段加上特定音效,要如何實現嗯?
其實只要我們在一開始錄製的時候,不設定 MediaRecoder 的音訊源,然後再利用其他工具,把音訊源剪輯進去就可以了。比如大名鼎鼎的FFmpeg就是音影片剪輯的好手,但是呢,FFmpeg對於上手是有一定的門檻和難度的,想要自己編譯一個穩定可靠好用的FFmpeg庫可不是那麼簡單的,並且為了加上一個錄製音訊的功能,大大增加我們 APK 的體積,也是因小失大的。
那麼,還有其他的辦法可以實現嗎?答案是肯定的。
Android 系統提供了原生的 MediaExtractor 類,給音影片混合提供了相對比較簡單易操作的方法,那麼,使用 MediaExtractor 應該注意什麼呢?
MediaExtractor 可以把音訊和影片源剪輯到一起,我們可以理解為兩條不同的軌道——音訊軌和影片軌,把他們混在一起,其中最重要的自然是混合在一起的時間戳。因此,在剪輯的時候,除非可以明確的確定音訊的開始時間在影片的某個詳細時間點,否則,建議將音訊和影片全部置回開始的時候,然後再開始混合。
五、總結
最後我們來總結一下本篇的主要內容。
首先我們介紹了原理,說明了MediaProjectionManager和MediaProjection兩個安卓系統用來提供錄屏能力的系統服務,以及兩個助攻的小夥伴——資料緩衝區Surface 和虛擬螢幕 VirtualDisplay;
其次介紹了直播帶貨系統如何實現錄屏採集的兩個使用場景:錄製並儲存(螢幕錄製)和錄製並編碼(螢幕直播);
最後延伸瞭如何在螢幕錄製並儲存的同時,混入非環境背景音的音訊。
最後的最後,記得在不使用的時候,釋放使用到的 API 哦!!
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70002045/viewspace-2785496/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 帶貨直播系統,透過ffmpeg推流實現首屏秒開
- 直播帶貨系統的開發打破原有的直播模式模式
- 直播賣貨系統的火爆源於帶貨直播原始碼的特色原始碼
- 直播商城系統APP帶貨系統短視訊帶貨系統APP
- 呼叫支付介面,實現直播帶貨系統原始碼的線上支付原始碼
- 帶貨直播系統,實現簡單的換頭像並儲存
- 直播帶貨系統原始碼,實現MYSQL資料庫的主從同步原始碼MySql資料庫主從同步
- 直播市場的爆發延伸出直播帶貨系統的市場
- 帶貨直播系統原始碼中,商品詳情頁是如何搭建起來的原始碼
- 帶貨直播系統,透過主從同步實現讀寫分離主從同步
- 帶貨直播系統原始碼的發展史原始碼
- Android實現錄屏直播(一)ScreenRecorder的簡單分析Android
- 全民直播時代,直播賣貨系統的合作模式如何收益?模式
- 帶貨直播原始碼,淺談直播實現過程和技術原始碼
- Windows 11實現錄屏直播,搭建Nginx的rtmp服務WindowsNginx
- 直播賣貨系統,如何實現mysql資料庫的讀寫分離MySql資料庫
- 商城APP直播帶貨,原生開發系統功能APP
- 實現直播帶貨系統推流,你進行推流監控了嗎?
- 直播帶貨平臺開發流量體現是重中之重!
- 直播帶貨系統為商家帶來了怎樣的機遇?
- 從直播商城系統的KOL效應分析,直播帶貨井噴的必然性
- 直播間如何帶貨?商家通過直播如何留住使用者?
- Windows11實現錄屏直播,H5頁面直播 HLS ,不依賴FlashWindowsH5
- 直播商城系統:帶貨APP+短視訊+直播+商城+多商戶appAPP
- 直播商城系統原始碼獨立運營版直播帶貨仿抖音帶貨模式App原生開發原始碼模式APP
- 直播賣貨系統開發,解決HLS實現直播過程中的延遲問題
- 直播平臺開發的小店功能強大,如何解決直播帶貨的貨源
- 直播帶貨必須提供回看功能,直播帶貨的“規矩”來了!
- 網路視訊直播系統開發,視訊解碼是如何實現的?
- 直播帶貨系統開發:如何才能達到高標準的市場水平
- 12┃音視訊直播系統之 WebRTC 實現1對1直播系統實戰Web
- 直播帶貨原始碼,Android Studio購買售賣系統原始碼Android
- 直播帶貨系統開發如何在眾多同行中嶄露頭角
- 瞭解直播帶貨系統使用的MySQL資料庫基礎MySql資料庫
- 直播帶貨軟體開發過程中,如何實現圖片上傳
- 為什麼各個平臺都加入直播功能?直播帶貨系統原始碼的魔力在哪?原始碼
- 開發直播帶貨系統,需要從哪幾個方面入手?
- 直播系統搭建,vue之computed帶引數如何接收Vue