1. 程式人生 > >android視訊截圖&手機錄屏實現

android視訊截圖&手機錄屏實現

問題

在android中有時候我們需要對螢幕進行截圖操作,單一的截圖操作好解決可以通過activity的頂層view DecorView獲取一個bitmap,得到就是當前activity上面的全部檢視。

 View view = activity.getWindow().getDecorView();
        view.setDrawingCacheEnabled(true);
        view.buildDrawingCache();
        Bitmap bmp = view.getDrawingCache();
        DisplayMetrics dm = new DisplayMetrics();
        activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
        Bitmap ret = Bitmap.createBitmap(bmp, 0, 0, dm.widthPixels, dm.heightPixels);
        view.destroyDrawingCache();

如果activity中包含一些視訊播放器比如SurfaceView GLSurfaceView
TextureView,在呼叫截圖程式碼會發現播放視訊的部分是黑屏的,原因是這幾種視訊渲染的view通過以上程式碼拿到的是緩衝區不是真正的影象。

解決辦法

android5.0以上系統提供了一個 MediaProjectionManager
類來對手機進行錄屏操作,也支援獲取手機的Image影象的操作,知道了這些我們就可以通過提供的api來進行截圖操作了。

這裡通過Service來操作截圖和錄屏的api

1.繫結截圖的Service

 Intent intent = new Intent(this, ScreenService.class);
 bindService(intent, mServiceConnection, BIND_AUTO_CREATE);

 public void onServiceConnected(ComponentName className, IBinder service) {
             DisplayMetrics metrics = new DisplayMetrics();
             getWindowManager().getDefaultDisplay().getMetrics(metrics);
             ScreenService.RecordBinder binder = (ScreenService.RecordBinder) service;
             recordService = binder.getRecordService();
             recordService.setConfig(metrics.widthPixels, metrics.heightPixels, metrics.densityDpi);
             mButton.setEnabled(true);
             mButton.setText(recordService.isRunning() ? "結束" : "開始");
  }

2.請求許可權 onActivityResult 方法中回撥。

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

  成功後
  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         if (requestCode == RECORD_REQUEST_CODE && resultCode == RESULT_OK) {

             //######## 截圖邏輯 ########
             mediaProjection = projectionManager.getMediaProjection(resultCode, data);
             recordService.setMediaProject(mediaProjection);
             recordService.initImageReader();

         }
  }

3. 獲取截圖

  @Override
  public void onClick(View view) {

    //########  截圖邏輯 ########
     Bitmap bitmap = recordService.getBitmap();
     mImageView.setImageBitmap(bitmap);
  }

錄屏

錄屏需要初始化一些錄屏引數,輸入麥克風型別視訊型別,儲存路徑等

 private void initRecorder() {
         mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
         mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
         mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
         mediaRecorder.setOutputFile(
                 getSavePath() + System.currentTimeMillis() + ".mp4");
         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();
         }
 }

開始錄屏

  mediaRecorder.start();

儲存路徑


完整Service程式碼

public class ScreenService extends Service {
private MediaRecorder mediaRecorder;
private VirtualDisplay virtualDisplay;
private boolean running;
private int width = 720;
private int height = 1080;
private int dpi;
private ImageReader mImageReader;
private MediaProjection mediaProjection;

 @Override
 public IBinder onBind(Intent intent) {
     return new RecordBinder();
 }


 @Override
 public void onCreate() {
     super.onCreate();
     running = false;
     mediaRecorder = new MediaRecorder();
 }


 @Override
 public int onStartCommand(Intent intent, int flags, int startId) {
     return super.onStartCommand(intent, flags, startId);
 }


 @Override
 public void onDestroy() {
     super.onDestroy();
 }


 public void setMediaProject(MediaProjection project) {
     mediaProjection = project;
 }


 public boolean isRunning() {
     return running;
 }


 public void setConfig(int width, int height, int dpi) {
     this.width = width;
     this.height = height;
     this.dpi = dpi;
 }


 /**
  * 開始錄屏
  *
  * @return true
  */
 public boolean startRecord() {
     if (mediaProjection == null || running) {
         return false;
     }
     initRecorder();
     createVirtualDisplay();
     mediaRecorder.start();
     running = true;
     return true;
 }


 /**
  * 結束錄屏
  *
  * @return true
  */
 public boolean stopRecord() {
     if (!running) {
         return false;
     }
     running = false;
     mediaRecorder.stop();
     mediaRecorder.reset();
     virtualDisplay.release();
     mediaProjection.stop();

     return true;
 }


 public void setMediaProjection(MediaProjection mediaProjection) {
     this.mediaProjection = mediaProjection;
 }


 /**
  * 初始化ImageRead引數
  */
 public void initImageReader() {
     if (mImageReader == null) {
         int maxImages = 2;
         mImageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, maxImages);
         createImageVirtualDisplay();
     }
 }


 /**
  * 建立一個錄屏 Virtual
  */

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


 /**
  * 建立一個ImageReader Virtual
  */
 private void createImageVirtualDisplay() {
     virtualDisplay = mediaProjection
             .createVirtualDisplay("mediaprojection", width, height, dpi,
                     DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mImageReader
                     .getSurface(), null, null);
 }


 /**
  * 初始化儲存螢幕錄影的引數
  */
 private void initRecorder() {
     mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
     mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
     mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
     mediaRecorder.setOutputFile(
             getSavePath() + System.currentTimeMillis() + ".mp4");
     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();
     }
 }


 /**
  * 獲取一個儲存螢幕錄影的路徑
  *
  * @return path
  */
 public String getSavePath() {
     if (Environment.getExternalStorageState()
                    .equals(Environment.MEDIA_MOUNTED)) {
         String rootDir = Environment.getExternalStorageDirectory()
                                     .getAbsolutePath() + "/" +
                 "ScreenRecord" + "/";

         File file = new File(rootDir);
         if (!file.exists()) {
             if (!file.mkdirs()) {
                 return null;
             }
         }
         return rootDir;
     } else {
         return null;
     }
 }


 /**
  * 請求完許可權後馬上獲取有可能為null,可以通過判斷is null來重複獲取。
  */
 public Bitmap getBitmap() {
     Bitmap bitmap = cutoutFrame();
     if (bitmap == null) {
         getBitmap();
     }
     return bitmap;
 }


 /**
  * 通過底層來獲取下一幀的影象
  *
  * @return bitmap
  */
 public Bitmap cutoutFrame() {
     Image image = mImageReader.acquireLatestImage();
     if (image == null) {
         return null;
     }
     int width = image.getWidth();
     int height = image.getHeight();
     final Image.Plane[] planes = image.getPlanes();
     final ByteBuffer buffer = planes[0].getBuffer();
     int pixelStride = planes[0].getPixelStride();
     int rowStride = planes[0].getRowStride();
     int rowPadding = rowStride - pixelStride * width;
     Bitmap bitmap = Bitmap.createBitmap(width +
             rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);
     bitmap.copyPixelsFromBuffer(buffer);
     return Bitmap.createBitmap(bitmap, 0, 0, width, height);
 }


 public class RecordBinder extends Binder {
     public ScreenService getRecordService() {
         return ScreenService.this;
     }
 }

demo下載

相關推薦

android視訊&手機實現

問題 在android中有時候我們需要對螢幕進行截圖操作,單一的截圖操作好解決可以通過activity的頂層view DecorView獲取一個bitmap,得到就是當前activity上面的全部檢視。 View view = activity.getWindow().getDecorView();

android手機

1. 手動截圖,通過其他第三方軟體傳送截圖,或者從手機取出截圖 2. 使用命令截圖,將截圖儲存到手機,再拉取到電腦 #!/bin/sh #執行 sh screenshot name picName=$1 filePath='caps' if [ ! $picName ];then picName=

Android實現全域性以及

廢話不多說 直接上程式碼(使用kotlin編寫大致與java差不多) 程式碼註釋也挺詳細的 利用mediaProjection 實現截圖與錄屏 mediaProjection 是android 5.

FastStone Capture 輕便而強大的軟體

這款軟體具有:截圖、螢幕錄製、取色、螢幕放大器、螢幕焦點、螢幕十字線等功能,並且在截圖後還可以編輯圖片! 檔案小巧,功能卻十分齊全,可謂是麻雀雖小五臟俱全!強烈推薦。 1、下載 百度網盤(已破解+已漢化+無需安裝直接執行):https://pan.字baidu.去com/掉s/1JWqgVNEmYdAs

gnome中操作

截圖與錄屏 你可以抓取當前螢幕圖片(截圖)或者錄製一個當前螢幕中操作的視訊(錄屏)。當你想要給某人演示怎樣在電腦上進行某些操作時,你可以通過截圖和錄屏來獲取圖片及視訊檔案,然後通過 email 向別人傳送這些檔案或將這些檔案共享到網路上。 截圖          

Ubuntu

Ubuntu 截圖 Ubuntu17.04自帶有截圖軟體和截圖快捷鍵,可以滿足正常截圖試用。在dash裡面直接輸入jie,第一個即是截圖軟體,開啟如下圖,執行比較穩定。 截全屏通用快捷鍵PrintScreen,按下後如下圖所示 以上截圖預設儲存到 /使用者/圖片/目錄下。

Android 拍照 事件監聽實現

需求是獲得使用者截圖,或者拍照的主動存圖行為。 但是 android 官方沒有提供回撥廣播之類的實現監聽,所以需要用另一種方式達到需求,這裡實現的就是通過監聽media資料夾實現目的。 所需許可權:  <uses-permission android:name="an

adb命令

錄屏 adb shell screenrecord /sdcard/test01.mp4 adb pull /sdcard/test01.mp4 截圖 adb shell screencap -p /sdcard/screen.png adb pull /sdc

Cypress系列(60)- 執行時的

如果想從頭學起Cypress,可以看下面的系列文章哦 https://www.cnblogs.com/poloyy/category/1768839.html   背景 在測試執行時截圖和錄屏能夠在測試錯誤時快速定位到問題所在 Cypress 截圖和錄屏功能強大   無須配置,自動截圖

Android Multimedia實戰(四)MediaProjection實現,與MediaMuxer實現為MP4,Gif格式

MediaProjection可以用來捕捉螢幕,具體來說可以擷取當前螢幕和錄製螢幕視訊 (5.0以上) 先總結下系統是如何實現組合鍵截圖的: 都應該知道Android原始碼中對按鍵的捕獲位於檔案PhoneWindowManager.java中 當滿足按鍵

Ruby+appium實現、滑、長按、日誌輸出到本地文件夾

username 實例 方法 pytho 日誌 用戶名 read 清除 文件夾 require ‘rubygems‘ require ‘appium_lib‘require ‘date‘require ‘logger‘require ‘pathname‘require ‘t

js+html手機視訊

在執行這段程式碼的時候引用的視訊一定要儲存在本地,否則會報canvas.toDataURL()錯 <html> <meta http-equiv="X-UA-Compatible" content="chrome=1"> <head>

C++實現螢幕(全

最近維護的專案,在某些情況下,光有日誌還不行,於是添加了截圖功能,特定情況下,會自動截圖,輔助分析,從而改程序序。以下是截圖實現程式碼。 void CDemoDlg::ScreenShot(void) { CWnd *pDesktop = GetDesktopWi

Android手機並製作Gif

做效果展示時經常需要一些Gif圖來顯示動態效果,我目前使用的方法是手機錄屏生成視訊檔案,再通過第三方軟體用視訊檔案生成動圖。剛才製作了一個動圖效果圖如下: 這裡我使用的是adb的screenrecord命令,它是API Level 19以上才支援的,官方文

canvas與html5實現視訊功能

這段時間一直在研究canvas,突發奇想想做一個可以截圖視訊的功能,然後把圖片拉去做表情包,哈哈哈哈哈哈~~ 製作方法: 1.在頁面中載入視訊 在使用canvas製作這個截圖功能時,首先必須保證頁面上已經載入完成了這個視訊,這樣才能夠方便的對其操作。如果使用下面直接

android後臺實現(2)--screencap原始碼修改

         首先找到screencap類在Android原始碼中的位置,/442/frameworks/base/cmds/screencap/screencap.cpp。 原始碼如下: /* * Copyright (C) 2010 The Android Op

html5視訊實現

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content

Android系統實現(附程式碼)

1.背景           寫部落格快兩年了,寫了100+的文章,最火的文章也是大家最關注的就是如何實現android系統截圖。其實我們google android_screen_shot就會找到很對

通過Python連線手機,並手機螢幕儲存到電腦(android

首先下載adb可以到百度網盤連結下載:https://pan.baidu.com/s/1htbYtq0或者自己去搜索引擎搜尋,網上一大堆將下載的壓縮包解壓,如圖:然後再系統中新增環境變數:右鍵我的電腦- 屬性-高階系統設定-高階-環境變數將Path中新增adb.exe的路徑:

Ruby+appium實現、滑、長按、日誌輸出到本地資料夾

require 'rubygems' require 'appium_lib' require 'date' require 'logger' require 'pathname' require 'thread' require"fileutils" capa