---
tags: Android
---
# Android 螢幕畫面錄影
## 權限需求
根據下面的範例,我們需要以下兩個權限,分別是錄影跟寫入檔案的權限:
``` =xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
```
## 簡介
一開始我先介紹一下主要會用到的三個物件,這些物件可以幫助你完成畫面錄影的動作:MediaProjectManager、MediaProject、MediaRecorder.
我自己簡單的整理出來了這三個物件的使用關係:
1. MediaProjectManager是用來產生詢問使用者可否進行畫面錄影的Intent,同意後則可以取得MediaProject.
2. MediaProject我的理解是可以產生一個可擷取並顯示於Surface的虛擬內容,並也可以註冊一個call back,當MediaProjection呼叫stop時觸發該call back.
3. MediaRecorder則是可對錄影進行參數的設定並且提供介面可控制錄影的動作,例如prepare、start以及stop等等.
## 提示並取得同意
因為在畫面擷取前,需要提示並且取得使用者的同意,所以在一開始MediaProjectManager可以幫助你產生詢問的Intent.
``` =java
private MediaProjectionManager mMediaProjectionManager;
...
mMediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
startActivityForResult(mMediaProjectionManager.createScreenCaptureIntent(),REQUEST_MEDIA_PROJECTION);
```
執行後就會產生提示畫面,如下圖:

使用者同意與否則就可以透過onActivityResult來取得,請參考下面的程式碼:
``` =java
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_MEDIA_PROJECTION && resultCode == RESULT_OK){
//使用者已同意,可以開始進行錄影的準備工作.
}
}
```
## 錄影前準備
前面已經提到MediaProjectManager除了可以產生提示使用者的Intent,在同意後則可以透過它取得MediaProject,如下面的程式碼所示:
``` =java
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_MEDIA_PROJECTION && resultCode == RESULT_OK){
mMediaProjection = mMediaProjectionManager.getMediaProjection(resultCode, data);
mMediaProjection.registerCallback(mMyMediaProjectionCallBack,null);
}
}
```
可以看到我有註冊一個call back,上面有提到註冊這個call back的用意,如果你也需要註冊一個call back,可以如下所示建立一個:
``` =java
class MyMediaProjectionCallBack extends MediaProjection.Callback{
@Override
public void onStop(){
//MediaProjection.stop() 呼叫後觸發callback
unregisterMediaProjectionCallback();
}
}
```
接著準備進行錄影的相關參數設定,例如輸出的影片格式、檔案路徑等等.首先,先建立一個MediaRecorder並開始進行相關的設定,如下所示:
``` =java
private MediaRecorder mMediaRecorder;
...
mMediaRecorder = new MediaRecorder();
try {
//特別注MediaRecorder的設定順序,請依照以下順序進行設定。
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mMediaRecorder.setVideoSize(mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels);
mMediaRecorder.setVideoFrameRate(30);
mMediaRecorder.setOutputFile(SAVE_PATH);
mMediaRecorder.setVideoEncodingBitRate(1024 * 1024);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.prepare();
} catch (IOException e) {
e.printStackTrace();
}
```
上面要注意的是參數設定的順序,如果順序不對的話就會拋出IllegalStateException,所以這裡的順序要留意,如果不了解也可以點進source code裡面查看,function上面的註解也會說明呼叫的順序.最後在所有的參數設定完成後,呼叫prepare(),代表準備進行錄影.
在開始錄影的最後,我們還必須要產生一個VirtualDisplay用來擷取手機畫面的顯示內容.
``` =java
private VirtualDisplay mVirtualDisplay;
private DisplayMetrics displayMetrics;
...
mVirtualDisplay = createVirtualDisplay(mMediaProjection);
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
...
private VirtualDisplay createVirtualDisplay(MediaProjection projection) {
Surface surface = mMediaRecorder.getSurface();
return projection.createVirtualDisplay(
"record screen",
displayMetrics.widthPixels,
displayMetrics.heightPixels,
displayMetrics.densityDpi,
DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY | DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
surface, null, null);
}
```
完成以上步驟後準備工作大致完成,可以開始進行錄影.
## 開始錄影
幫你一切都準備好了,開始進行錄影就很簡單:
``` =java
mMediaRecorder.start();
```
停止錄影時我會執行下面的程式碼:
``` =java
mMediaRecorder.stop();
mMediaRecorder.reset();
```
上面要注意的是reset(),當執行後MediaRecorder的參數設定要重新進行設定.
當完成錄影後,也要留意資源的釋放.
``` =java
mVirtualDisplay.release();
mMediaRecorder.release();
mMediaRecorder = null;
```
以上簡單介紹了如何進行手機畫面錄影的實作方式,詳細的程式碼可以參考我的[GitLab](https://gitlab.com/poppophi/screenrecorderdemo)
## 參考資料
https://developer.android.com/guide/topics/media/mediarecorder
https://developer.android.com/reference/android/media/projection/MediaProjection