tft每日頭條

 > 科技

 > 錄屏軟件用什麼開發

錄屏軟件用什麼開發

科技 更新时间:2025-02-01 12:08:54

概述

在視頻會議、線上課堂、遊戲直播等場景下,屏幕共享是一個最常被用到的功能。要實現對屏幕畫面的實時共享,端到端主要有這幾個步驟:錄屏采集、視頻編碼、實時傳輸、視頻解碼、視頻渲染。

一般來說,實時屏幕共享時,共享發起端以固定采樣頻率(一般 8 - 15幀)抓取到屏幕中指定源的畫面(包括指定屏幕、指定區域、指定程序等),經過視頻編碼壓縮(選擇保持文本/圖形邊緣信息不失真的方案)後,在實時網絡上以相應的幀率分發。

因此,錄屏采集是實現實時屏幕共享的基礎。即構作為專業的音視頻雲服務商,對于實時屏幕共享有一套完整的流程體系和 API 封裝,讓開發者可以更加方便快捷地擁有錄屏直播的能力。

下面我們将介紹基于不同端,實現錄屏采集的方法。這是第一篇,Android端錄屏采集實現教程。

原理

在分享如何實現Android系統錄屏采集前,我們先來看看其背後的原理。

Android 在 4.4 版本前要實現屏幕錄制必須獲取到 root 權限,但目前大部分設備的系統版本都高于4.4,因此這種情況在此就不作贅述。

在5.0及以上版本,我們可以利用系統提供的MediaProjection 和 MediaProjectionManager 進行屏幕錄制,可以不需要獲取 root 權限,但會彈窗獲取權限,需要用戶同意才行。

那麼在Android5.0及以上版本,我們使用 MedaProjection 是如何把屏幕的數據錄制下來呢?

這裡我們就要說到兩個“助攻的小夥伴”了——Surface 和 VirtualDisplay。

1、SurfaceHandle 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 進行編碼,然後傳輸出去。

因此根據上面的原理,我們可以畫出以下屏幕采集的整體架構圖:

錄屏軟件用什麼開發(安創成長營一期團隊即構科技)1

實現

上面我們已經清楚了整個屏幕錄制的原理,那麼在代碼層面,我們應當如何實現呢?主要分為以下幾步:

第一步,申請權限。在 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:

錄屏軟件用什麼開發(安創成長營一期團隊即構科技)2

那麼,提供的這幾個 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 是由消費者去創建的。因此,這時候就要想想我們的消費者是什麼?我們的場景是什麼?是要錄制成文件還是編碼成數據傳輸出去實現錄屏直播呢?

當然…… 這個終極問題最後可能是要産品經理來決定……

1、屏幕錄制保存(MediaRecoder)

好了,假設現在産品經理已經明确表示,需求場景是把屏幕錄制成文件保存下來,就像現在很多市面上的屏幕錄制 APP 一樣。那我們應該怎麼做呢?

其實很簡單,我們隻需要想一下,有沒有什麼 API 是可以将圖像數據錄制保存成文件的呢?

Android 官方就已經有提供了一個工具供我們使用,那就是 MediaRecoder ,重點是 MediaRecoder 可以通過 getSurface 對外提供一個 Surface,而這個 Surface 剛好是 VirtualDisplay 所需要的,所以整個調用鍊和 API 我們可以理清楚了,如下圖。而數據的流向則是相反的,從 VirturalDisplay -> Surface -> MediaRecoder(綠色箭頭表示數據的流向)。

錄屏軟件用什麼開發(安創成長營一期團隊即構科技)3

那麼 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、錄屏直播

如果此時産品經理突然要改需求,想把錄制成文件改成錄屏直播。

那我們就要改變方案了,把數據的消費者 MediaRecorder 換成其他可以編碼的工具,比如 Android 自帶的硬件編碼 MediaCodec或者大名鼎鼎的FFmpeg。但是數據的生産者不會變,依然是VirtualDisplay,數據緩沖依舊是Surface。

以 MediaCodec 為例,關于 MediaRecoder 的流程圖則變為:

錄屏軟件用什麼開發(安創成長營一期團隊即構科技)4

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 可以把音頻和視頻源剪輯到一起,我們可以理解為兩條不同的軌道——音頻軌和視頻軌,把他們混在一起,其中最重要的自然是混合在一起的時間戳。因此,在剪輯的時候,除非可以明确的确定音頻的開始時間在視頻的某個詳細時間點,否則,建議将音頻和視頻全部置回開始的時候,然後再開始混合。

總結

最後,我們來總結一下Android端錄屏采集實現的主要内容。

首先,從原理上要了解

MediaProjectionManager和MediaProjection這兩個安卓系統用來提供錄屏能力的系統服務,以及兩個助攻的小夥伴——數據緩沖區Surface 和虛拟屏幕 VirtualDisplay;

其次,介紹了如何實現錄屏采集的兩個使用場景:錄制并保存(屏幕錄制)和錄制并編碼(屏幕直播);

最後,延伸了如何在屏幕錄制并保存的同時,混入非環境背景音的音頻。

最後的最後,記得在不使用的時候,釋放使用到的 API 哦!!

(文章來源:即構科技)

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关科技资讯推荐

热门科技资讯推荐

网友关注

Copyright 2023-2025 - www.tftnews.com All Rights Reserved