简单屏幕录制截屏工具

很久没写了,随便写写~~

额,这是一个很简单的截屏工具,用的是Android系统的MediaProjectionManager实现截屏录制功能

使用到的主要类:

说明
MediaProjectionManager MediaProjection管理
MediaProjection 授予捕获屏幕或记录系统音频的功能
VirtualDisplay 个人理解类似虚拟屏幕?捕获屏幕后将数据输出到虚拟屏幕 然后可以获取视频的信息,指定输出的位置等
ImageReader 这个类被允许直接从Surface接收渲染的图像数据
MediaRecorder 用于将音视频编码输出

流程:

  • 1.申请录屏screenCaptureIntent
  • 2.调用activity的 startActivityForResult(screenCaptureIntent,code);需要用户允许
  • 3.在onActivityResult获取屏幕录制的操作对象mMediaProjection = mediaProjectionManager.getMediaProjection(resultCode, resultData);
  • 4.MediaProjection + VirtualDisplay + Surface(根据情况使用提供者) 实现录屏截屏功能

使用:

1.在Activity的onCreate下创建

screenshotRecordUtil = new ScreenshotRecordUtil();
screenshotRecordUtil.screenCaptureIntent(this, new ScreenshotRecordUtil.ScreenshotRecordCallback() {
            @Override
            public void onScreenshotSuccess(String path, Bitmap bitmap) {
                //path目前没写(没有保存文件,有需求自行在ScreenshotRecordUtil里startCapture方法实现),
                //这里是直接获取的bitmap显示

                //在主线程更新UI
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        //Glide.with(Live2Activity.this).load(bitmap).into(image);
                    }
                });
            }

            @Override
            public void onScreenshotFailure() {
                //截图失败
            }

            @Override
            public void onRecordStart() {
                //录屏开始
                //LogUtils.d("录屏开始:");
            }

            @Override
            public void onRecordStop(String path) {
                //录屏结束
                //LogUtils.d("录屏结束:"+path);
            }
        });

2.实现onActivityResult方法

 @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == ScreenshotRecordUtil.REQUEST_SHOT_CODE && resultCode == RESULT_OK) {
            // 获取申请截屏结果
            screenshotRecordUtil.setUpImageProjection(Live2Activity.this, resultCode, data);
        } else if (requestCode == ScreenshotRecordUtil.REQUEST_RECORD_CODE && resultCode == RESULT_OK) {
            // 获取申请录屏结果

            //录屏文件存储目录地址
            String root = Environment.getExternalStorageDirectory() + AppConstants.PATH_VIDEO);

            File appDir = new File(root);
            if (!appDir.exists()) {
                appDir.mkdirs();
            }

            //创建文件
            File file = new File(appDir, System.currentTimeMillis() + ".mp4");

            screenshotRecordUtil.setUpVideoProjection(Live2Activity.this, resultCode, data, file);
        }
    }

3.点击按钮,截屏

   /**
     * 截取屏幕
     * REQUEST_SHOT_CODE 是请求码,和你的重复了可以自己更改
     */
    @OnClick(R.id.btn_screenshot)
    void screenshot() {
         screenshotRecordUtil.screenCapture(ScreenshotRecordUtil.REQUEST_SHOT_CODE);
    }

4.点击按钮,录屏

   /**
     * 录屏
     */
    @OnClick(R.id.btn_recording)
    void onClickRecording() {
        if (screenshotRecordUtil.isRecording()) {
            screenshotRecordUtil.mediaRecorderStop();
        } else {
            screenshotRecordUtil.screenCapture(ScreenshotRecordUtil.REQUEST_RECORD_CODE);
        }
    }

ScreenshotRecordUtil 类:


import static android.content.Context.WINDOW_SERVICE;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaRecorder;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.WindowManager;

import com.blankj.utilcode.util.StringUtils;
import com.blankj.utilcode.util.ThreadUtils;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;

/**
 * 截屏录屏工具
 * <p>
 * 1.申请录屏Intent
 * <p>
 * 2.然后调用activity的 startActivityForResult(screenCaptureIntent,code);
 * <p>
 * 3.onActivityResult获取屏幕录制的操作对象
 * mMediaProjection = mediaProjectionManager.getMediaProjection(resultCode, resultData);
 * <p>
 * 4.MediaProjection + VirtualDisplay + Surface(根据情况使用提供者) 实现录屏截屏功能
 */
public class ScreenshotRecordUtil {
    private static final String TAG = ScreenshotRecordUtil.class.getSimpleName();
    public static final int REQUEST_SHOT_CODE = 10011;//截屏请求回调code
    public static final int REQUEST_RECORD_CODE = 10012;//录屏请求回调code
    private MediaRecorder mMediaRecorder;                                                           //MediaRecorder屏幕录制 需求场景是把屏幕录制成文件,录屏直播则使用MediaCodec或者大名鼎鼎的FFmpeg
    private ImageReader mImageReader;                                                               //获取屏幕渲染得到Image

    private MediaProjectionManager mediaProjectionManager;                                          //系统提供的一个录屏服务
    private MediaProjection mMediaProjection;                                                       //屏幕录制的操作对象
    private VirtualDisplay mVirtualDisplay;                                                         //虚拟屏幕——VirtualDisplay

    private String mVideoPath;                                                                      //录像输入地址

    private Activity activity;
    private Intent screenCaptureIntent;
    private ScreenshotRecordCallback screenshotRecordCallback;

    /**
     * 申请录屏Intent
     */
    public void screenCaptureIntent(Activity activity, ScreenshotRecordCallback screenshotRecordCallback) {
        this.activity = activity;
        this.screenshotRecordCallback = screenshotRecordCallback;

        this.mediaProjectionManager = (MediaProjectionManager) activity.getSystemService(Context.MEDIA_PROJECTION_SERVICE);
        this.screenCaptureIntent = mediaProjectionManager.createScreenCaptureIntent();
    }


    /**
     * 调用activity的 startActivityForResult
     */
    public void screenCapture(int code) {
        this.activity.startActivityForResult(screenCaptureIntent, code);
    }


    /**
     * 获取屏幕截图
     *
     * @param activity   activity
     * @param resultCode onActivityResult返回的 resultCode
     * @param resultData onActivityResult返回的 resultData
     */
    public void setUpImageProjection(Activity activity, int resultCode, Intent resultData) {
        //创建mImageReader,用于获取VirtualDisplay的image
        DisplayMetrics displayMetrics = new DisplayMetrics();
        WindowManager windowManager = (WindowManager) activity.getSystemService(WINDOW_SERVICE);
        windowManager.getDefaultDisplay().getMetrics(displayMetrics);
        int width = displayMetrics.widthPixels;
        int height = displayMetrics.heightPixels;
        Log.e(TAG, "displayMetrics width=" + width + ", height=" + height);
        this.mImageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 2);

        //获取屏幕录制的操作对象
        this.mMediaProjection = mediaProjectionManager.getMediaProjection(resultCode, resultData);

        //创建虚拟屏幕,使用ImageReader提供的Surface
        //VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR:当没有内容显示时,允许将内容镜像到专用显示器上。
        //VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY:仅显示此屏幕的内容,不镜像显示其他屏幕的内容。
        //VIRTUAL_DISPLAY_FLAG_PRESENTATION:创建演示文稿的屏幕。
        //VIRTUAL_DISPLAY_FLAG_PUBLIC:创建公开的屏幕。
        //VIRTUAL_DISPLAY_FLAG_SECURE:创建一个安全的屏幕

        this.mVirtualDisplay = mMediaProjection.createVirtualDisplay("ScreenCapture",
                width, height,
                displayMetrics.densityDpi,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                mImageReader.getSurface(), null, null);

        //这里稍稍作了个延时,立马取的话 mImageReader.acquireLatestImage()可能为空
        ThreadUtils.executeByCachedWithDelay(new ThreadUtils.SimpleTask<Object>() {
            @Override
            public Object doInBackground() throws Throwable {
                startCapture();
                return null;
            }

            @Override
            public void onSuccess(Object result) {

            }
        }, 100, TimeUnit.MILLISECONDS);
    }


    /**
     * 屏幕录制
     *
     * @param activity   activity
     * @param resultCode onActivityResult返回的 resultCode
     * @param resultData onActivityResult返回的 resultData
     * @param file       录制输出文件
     */
    public void setUpVideoProjection(Activity activity, int resultCode, Intent resultData, File file) {
        //创建mImageReader,用于获取VirtualDisplay的image
        DisplayMetrics displayMetrics = new DisplayMetrics();
        WindowManager windowManager = (WindowManager) activity.getSystemService(WINDOW_SERVICE);
        windowManager.getDefaultDisplay().getMetrics(displayMetrics);
        int width = displayMetrics.widthPixels;
        int height = displayMetrics.heightPixels;
        Log.e(TAG, "displayMetrics width=" + width + ", height=" + height);

        initMediaRecorder(file, width, height);

        //获取屏幕录制的操作对象
        this.mMediaProjection = mediaProjectionManager.getMediaProjection(resultCode, resultData);

        //创建虚拟屏幕 需要在mMediaRecorder.prepare();后,否则mMediaRecorder.getSurface()拿不到Surface对象
        this.mVirtualDisplay = mMediaProjection.createVirtualDisplay("ScreenRecorder",
                width, height,
                displayMetrics.densityDpi,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                mMediaRecorder.getSurface(), null, null);


        mediaRecorderStars();
    }

    /**
     * 截图
     */
    public void startCapture() {
        String mImageName = System.currentTimeMillis() + ".png";
        Log.i(TAG, "image name is : " + mImageName);
        Image image = mImageReader.acquireLatestImage();
        if (image == null) {
            Log.e(TAG, "image is null.");
            if (screenshotRecordCallback != null) {
                screenshotRecordCallback.onScreenshotFailure();
            }
            return;
        }
        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 mBitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);
        mBitmap.copyPixelsFromBuffer(buffer);
        mBitmap = Bitmap.createBitmap(mBitmap, 0, 0, width, height);
        image.close();

        if (mBitmap != null) {
            // 保存或者显示...

            if (screenshotRecordCallback != null) {
                screenshotRecordCallback.onScreenshotSuccess(null, mBitmap);
            }
        }
    }


    /**
     * 录屏
     */
    private void initMediaRecorder(File file, int width, int height) {
        this.mMediaRecorder = new MediaRecorder();
        // 设置音频来源 需要动态申请 android.permission.RECORD_AUDIO 权限
        this.mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        // 设置视频来源
        this.mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
        // 设置输出格式
        this.mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        // 设置输出文件
        this.mVideoPath = file.getAbsolutePath();
        this.mMediaRecorder.setOutputFile(mVideoPath);
        // 设置视频宽高
        this.mMediaRecorder.setVideoSize(width, height);
        // 设置视频帧率
        this.mMediaRecorder.setVideoFrameRate(30);
        // 设置视频编码比特率
        this.mMediaRecorder.setVideoEncodingBitRate(5 * 1024 * 1024);
        // 设置音频编码
        this.mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
        // 设置视频编码
        this.mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);

        try {
            this.mMediaRecorder.prepare();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //通过mVideoPath地址确定是否在录屏
    public boolean isRecording() {

        Log.e(TAG, "mVideoPath is " + mVideoPath + ",b:" + StringUtils.isEmpty(mVideoPath));

        return !StringUtils.isEmpty(mVideoPath);
    }

    //开始录制
    public void mediaRecorderStars() {
        if (StringUtils.isEmpty(mVideoPath)) {
            Log.e(TAG, "mVideoPath is null");
            return;
        }

        if (mMediaRecorder == null) {
            Log.e(TAG, "mMediaRecorder is null");
            return;
        }

        mMediaRecorder.start();

        if (screenshotRecordCallback != null) {
            screenshotRecordCallback.onRecordStart();
        }
    }

    //结束录制
    public void mediaRecorderStop() {
        if (mMediaRecorder != null) {
            mMediaRecorder.stop();

            if (screenshotRecordCallback != null) {
                screenshotRecordCallback.onRecordStop(mVideoPath);
            }

            mVideoPath = null;
            mMediaRecorder.reset();
        } else {
            Log.e(TAG, "mMediaRecorder is null");
        }
    }


  /**
     * 释放相关资源
     */
    public void release() {
        if (mImageReader != null) {
            mImageReader.close();
        }

        if (mMediaRecorder != null) {
            mMediaRecorder.setOnErrorListener(null);
            mMediaProjection.stop();
            mMediaRecorder.reset();
            mMediaRecorder.release();
        }

        if (mVirtualDisplay != null) {
            mVirtualDisplay.release();
            mVirtualDisplay = null;
        }

        if (mMediaProjection != null) {
            mMediaProjection.stop();
            mMediaProjection = null;
        }
    }


    public interface ScreenshotRecordCallback {
        void onScreenshotSuccess(String path, Bitmap bitmap);

        void onScreenshotFailure();

        void onRecordStart();

        void onRecordStop(String path);

    }


为了向别人、向世界证明自己而努力拼搏,而一旦你真的取得了成绩,才会明白:人无须向别人证明什么,只要你能超越自己。

Guess you like

Origin blog.csdn.net/github_37847975/article/details/122477106