Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android5.0錄屏方案

Android5.0錄屏方案

編輯:關於Android編程

導語 本文主要是圍繞android直播助手的功能做了一些研究,因為之前對Android多媒體相關的內容知之甚少,只有概念,於是查閱了相關資料並做以總結。

由於我對音視頻相關知識零基礎所以補充了一些相關知識

采集音頻原始數據---->壓縮編碼---->封裝

采集視頻原始數據---->壓縮編碼---->封裝

音視頻編碼

壓縮編碼就是對數據進行壓縮以節省空間便於存儲和傳輸。

視頻壓縮編碼就是將視頻幀的像素數據RGB或YUV等壓縮成視頻碼流,編碼一般對YUV格式進行,視頻編碼方案H.264,MPEG2,MPEG4等。

音頻壓縮編碼就是將采樣的音頻采樣數據PCM等壓縮成音頻碼流。音頻編碼方案:AAC,WMA,MP3等。

編碼是音視頻技術中最重要的技術之一,也是難點,所幸的是,Android提供了MediaCodec用來方便開發者進行視音頻的編解碼,並且對於某種編碼器還可以指定幀格式,盡管如此,我們也不能指定任意格式,因為這需要硬件的支持,可以通過API查詢支持的幀格式。

通過createEncoderByType方法只需要傳入mime即可創建對應的解碼器,mime可以時下面的形式。

\

MediaCodec類的使用邏輯大致如下圖所示,簡單來說,一個編碼器用於處理輸入數據並對其進行編碼處理後輸出,它內部有一系列的輸入和輸出緩沖區,使用時,從編碼器申請空的輸入緩沖區,然後填充數據後發送給編碼器處理,編碼完成後編碼器會將編碼後的數據放入輸出緩沖區,只需要從輸出緩沖區取出編碼後的數據後用於處理,最後將空間返還給編碼器。

\

使用MediaCodec可以有三種方式

1.使用Buffer數組的同步方式(API20以後deprecated)

2.使用Buffer同步方式

3.異步方式

前兩種方式基本類似,只是使用Buffer的同步方式性能更好。以第一種方式為例:

\

當要中指編碼時只需要在最後一個有效數據Buffer中或者額外發送一個空的Buffer指定其Flag標志位為BUFFER_FLAG_END_OF_STREAM,然後調用queueInputBuffer發送給編碼器即可。

除了直接使用ByteBuffer作為MediaCodec的輸入輸出還可以通過Surface作為數據的載體,具體的有兩種:使用InputSurface和使用OutputSurface。

以使用InputSurface為例,使用createInputSurface()方法創建一個InputSurface。

RequestsaSurfacetouseastheinputtoanencoder,inplaceofinputbuffers.表明使用這個Surface來代替Buffer作為編碼器的輸入。

編碼器將會自動的從InputSurface讀取幀數據送往編碼器。此時訪問不到輸入Buffer緩沖區,使用getInputBuffers等方法拋出異常。編碼流結束時調用signalEndOfInputStream函數,該函數調用後,Surface就會停止向編碼器提供數據流。

顯然,這種方式在不需要獲取音視頻流的原始數據時是非常方便的。

音視頻混合

封裝一般指的是將進行過壓縮編碼的音頻流和視頻流進行合並,封裝格式種類很多,例如MP4,MKV等等,它的作用就是將壓縮編碼的視頻和音頻按照一定的格式封裝在一起。例如,將H.264編碼的視頻碼流和AAC編碼的音頻碼流合並成MP4格式的數據,

Android也提供了MediaMuxer支持將編碼後的音視頻碼流合並成MP4格式的文件。

\

使用MediaMuxer的關鍵代碼如下

\

Android5.0錄制視頻的方案

通過MediaProjectionManager進行錄制屏幕。關鍵代碼如下

\

在onActivityResult中判斷是否獲得錄屏權限。然後執行下面操作。

\

createVirtualDisplay:CreatesaVirtualDisplaytocapturethecontentsofthescreen

這個參數表示了錄制的手機屏幕的內容要顯示到哪個SurfaceView上,實際上表示了屏幕幀數據的走向,這個參數非常關鍵。

相關的幾個類

ImageReader:TheImageReaderclassallowsdirectapplicationaccesstoimagedatarenderedintoaSurface

ImageReader類允許應用直接訪問渲染到Surface上的image數據。使用MediaProjectionManager錄制的屏幕內容可以直接渲染到一個Surface上,這個參數在createVirtualDisplay時傳入,但是我們無法訪問到渲染的內容。所以ImageReader類主要是用於使用Surface時訪問不到原始視頻數據流的情形。要想訪問到每一幀的內容可以使用ImageReader類。

該類有一個函數getSurface獲取一個Surface,通過這個函數獲取一個Surface用來為ImageReader產生Images即視頻流幀數據。

\

將這個Surface指定到錄制屏幕時的Surface參數,就可以通過ImageReader讀取到Surface上面渲染的每一幀的數據,通過acquireLatestImage()等方法可以獲取一個Image對象。

Image:AsinglecompleteimagebuffertousewithamediasourcesuchasaMediaCodecoraCameraDevice.

也就是說Image類表示一個圖片緩沖區,用來和MediaCodec一起使用。通過Image對象可以得到這一幀畫面的像素數據,應該是RGB數據,轉化為YUV格式的數據house,然後通過MediaCodec對其進行編碼。

本地錄屏方案

有了上面的准備知識,再來看直播助手的兩個主要功能本地錄屏和推流功能的實現邏輯容易多了。

本地錄屏的邏輯:本地錄屏不需要操作視頻原始數據,因此使用InputSurface作為編碼器的輸入。

視頻:MediaProjection通過createVirtualDisplay創建的VirtualDisplay傳入的Surface是通過MediaCodec的createInputSurface方法返回的,表明編碼器的輸入其實來自於錄制到的屏幕數據,於是只需要在MediaCodec的輸出緩沖區中拿到編碼後的ByteBuffer即可。

音頻:錄制程序獲得音頻原始數據PCM,傳給MediaCodec編碼,然後從MediaCodec的輸出緩沖區拿到編碼後的ByteBuffer即可。

最終通過合並模塊將音視頻混合。

推流的邏輯:推流SDK提供了一個編碼器TVLiveSdk_LiveEncoder,它接受YUV420的視頻數據格式和PCM編碼的原始音頻流。因此要獲得視頻的原始幀數據才行,可以通過ImageReader實現該功能。

視頻:MediaProjection通過createVirtualDisplay創建的VirtualDisplay傳入的Surface是通過ImageReader的getSurface方法返回的,表明錄制的屏幕幀數據傳遞到ImageReader,於是通過ImageReader的相關API可以讀取到錄制的屏幕每一幀的數據,但這個數據時RGB格式的,轉化為YUV格式後傳到推流SDK即可。

音頻:由於推流SDK需要的就是原始PCM編碼的音頻數據,因此錄制到音頻數據後直接調用推流SDK即可。

簡單說就是重定向了屏幕錄制的數據的方向,這個Surface提供的是什麼,錄制的視頻數據就傳到哪裡。Surface提供的是本地某個SurfaceView控件,那麼就會將屏幕內容顯示到這個控件上,提供MediaCodec就是作為編碼器的輸入源最終獲得編碼後的數據,提供ImageReader就會作為ImageReader的數據源,最終獲得了視頻的原始數據流。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved