预备知识

Android MediaProjection学习(一)之实现屏幕截图 通过预备知识我们应该知道MediaProjection的相关方法和知识。在屏幕截图里我们用了ImageReader来获取截图,而在这一节中我们通过另外一个工具MediaRecorder来获取屏幕的视频。

MediaRecorder

Google官方文档:官方文档

Used to record audio and video. The recording control is based on a simple state machine (see below).

Android mediaplayer error 处理_MediaProjection


A common case of using MediaRecorder to record audio works as follows:

MediaRecorder recorder = new MediaRecorder();
 recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
 recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
 recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
 recorder.setOutputFile(PATH_NAME);
 recorder.prepare();
 recorder.start();   // Recording is now started
 ...
 recorder.stop();
 recorder.reset();   // You can reuse the object by going back to setAudioSource() step
 recorder.release(); // Now the object cannot be reused

引用结束

其实我们结合流程图来看就可以明白了,首先我们要初始化Recorder,调用相关方法。然后顺着流程图走,然后就是数据源的配置,方法如图。配置完这些后我们就调用prepare()方法来让Recorder处于预备状态,最后调用start()就开始录制了。

屏幕录制

了解了上述知识以后我们就可以开始屏幕录制了,现在只剩一个问题,那就是MediaRecorder的视频源从哪来?我们先看看几个常见的视频源。
Constants

类型

名称

解释

int

CAMERA

Camera video source,Using the Camera API as video source.

int

DEFAULT

int

SURFACE

Surface video source,Using a Surface as video source.

第一个CAMERA视频源来自系统相机的API,第三个SURFACE则是通过surface来获取视频。是不是有头绪了,没错我们的截屏就是通过ImageReader的getSurface方法获取了surface然后转换后就可以了。录屏也是一样,通过MediaRecorder的getSurface方法来获取一个surface来录屏就可以了。

这里需要注意的一点就是,我们需要把我们的录屏放在服务里运行,就可以录制我们程序以外的屏幕内容了。

代码

首先我们需要获取一个MediaProjection方法如下:

private MediaProjection createMediaProjection() {
        Log.i(TAG, "Create MediaProjection");
        return ((MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE)).getMediaProjection(mResultCode, mResultData);
    }

然后初始化MediaRecorder:

private MediaRecorder createMediaRecorder() {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
        Date curDate = new Date(System.currentTimeMillis());
        String curTime = formatter.format(curDate).replace(" ", "");
        String videoQuality = "HD";
        if(isVideoSd) videoQuality = "SD";

        Log.i(TAG, "Create MediaRecorder");
        MediaRecorder mediaRecorder = new MediaRecorder();
        if(isAudio) mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        mediaRecorder.setOutputFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES) + "/" + videoQuality + curTime + ".mp4");
        mediaRecorder.setVideoSize(mScreenWidth, mScreenHeight);  //after setVideoSource(), setOutFormat()
        mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);  //after setOutputFormat()
        if(isAudio) mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);  //after setOutputFormat()
        int bitRate;
        if(isVideoSd) {
            mediaRecorder.setVideoEncodingBitRate(mScreenWidth * mScreenHeight);
            mediaRecorder.setVideoFrameRate(30);
            bitRate = mScreenWidth * mScreenHeight / 1000;
        } else {
            mediaRecorder.setVideoEncodingBitRate(5 * mScreenWidth * mScreenHeight);
            mediaRecorder.setVideoFrameRate(60); //after setVideoSource(), setOutFormat()
            bitRate = 5 * mScreenWidth * mScreenHeight / 1000;
        }
        try {
            mediaRecorder.prepare();
        } catch (IllegalStateException | IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        Log.i(TAG, "Audio: " + isAudio + ", SD video: " + isVideoSd + ", BitRate: " + bitRate + "kbps");
        return mediaRecorder;
    }

这段代码包含了录制高清和普清视频,帧率设置,视频源,文件输出路径等。
最后我们调用MediaProjection的createVirtualDisplay方法:

private VirtualDisplay createVirtualDisplay() {
        Log.i(TAG, "Create VirtualDisplay");
        return mMediaProjection.createVirtualDisplay(TAG, mScreenWidth, mScreenHeight, mScreenDensity,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mMediaRecorder.getSurface(), null, null);
    }

这里通过mMediaRecorder.getSurface()将屏幕内容给我们初始化的MediaRecorder,最后调用MediaRecorder的start()就可以将录制的视频输出到我们指定的目录下了。

Summary总结

我们捋一下录屏的步骤。
Ⅰ 获取MediaProjectionManager和MediaProjection
Ⅱ 初始化MediaRecorder
Ⅲ 调用MediaProjection的createVirtualDisplay方法传入MediaRecorder的getSurface方法返回的surface
Ⅳ 调用MediaRecorder的start()方法
然后就可以实现录屏功能了,开心๑乛◡乛๑。