--- 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); ``` 執行後就會產生提示畫面,如下圖: ![](https://i.imgur.com/LE2bbKQ.png) 使用者同意與否則就可以透過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