Android Lollipop (5.0) 螢幕錄製實現

w39發表於2021-09-09
引言

網上很多關於 Android 錄屏的解決方案是透過讀取 /dev/graphics/fb0 裡面的 frame buffer,然後再透過各種開源編碼器轉為影片,但必須要 root 才行,而且有些手機即便你 root 還是不能成功,獲取到的 framebuffer 全是 0, 所以不是一個很好的解決方案。從 Android 4.4 Google 引入了透過 adb 命令錄屏的功能,需要透過 USB 除錯連線到 PC,執行 adb shell screenrecord /sdcard/xxxx.mp4開始錄屏,並且錄屏限制時長最長 3 分鐘。Android 5.0 引入 MediaProject,可以不需要 adb,也不用 root 就可以錄屏,但需要彈許可權獲取視窗,需要使用者允許才行,這裡主要介紹 Android 5.0+ 利用 MediaProject 在非 root 情況下實現螢幕錄製。

基本原理

在 Android 5.0,Google 終於開放了影片錄製的介面,其實嚴格來說,是螢幕採集的介面,也就是 MediaProjectionMediaProjectionManager

具體實現步驟

1 申請許可權

在 AndroidManifest 中新增許可權

Android 6.0 加入的動態許可權申請,如果應用的 targetSdkVersion 是 23,申請敏感許可權還需要動態申請

if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
    != PackageManager.PERMISSION_GRANTED) {  
  ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, STORAGE_REQUEST_CODE);
}
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.RECORD_AUDIO)
    != PackageManager.PERMISSION_GRANTED) {  
  ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.RECORD_AUDIO}, AUDIO_REQUEST_CODE);
}

2 獲取 MediaProjectionManager 例項

MediaProjectionManager 也是系統服務的一種,透過 getSystemService 來獲取例項

MediaProjectionManager projectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);

3 發起螢幕捕捉請求

Intent captureIntent= projectionManager.createScreenCaptureIntent(); 
startActivityForResult(captureIntent, REQUEST_CODE);

4 獲取 MediaProjection

透過 onActivityResult 返回結果獲取 MediaProjection

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  if (requestCode == RECORD_REQUEST_CODE && resultCode == RESULT_OK) {
    mediaProjection = projectionManager.getMediaProjection(resultCode, data);
  }
}

5 建立虛擬螢幕

這一步就是透過 MediaProject 錄製螢幕的關鍵所在,VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR 引數是指建立螢幕映象,所以我們實際錄製內容的是螢幕映象,但內容和實際螢幕是一樣的,並且這裡我們把 VirtualDisplay 的渲染目標 Surface 設定為 MediaRecordergetSurface,後面我就可以透過 MediaRecorder 將螢幕內容錄製下來,並且存成 video 檔案

private void createVirtualDisplay() {
  virtualDisplay = mediaProjection.createVirtualDisplay(
        "MainScreen",
        width,
        height,
        dpi,
        DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
        mediaRecorder.getSurface(),
        null, null);
}

6 錄製螢幕資料

這裡利用 MediaRecord 將螢幕內容儲存下來,當然也可以利用其它方式儲存螢幕內容,例如:ImageReader

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();
  }
}

public boolean startRecord() {
  if (mediaProjection == null || running) {
    return false;
  }
  initRecorder();
  createVirtualDisplay();
  mediaRecorder.start();
  running = true;
  return true;
}
原始碼地址

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/854/viewspace-2804120/,如需轉載,請註明出處,否則將追究法律責任。

相關文章