很久没写了,随便写写~~
额,这是一个很简单的截屏工具,用的是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);
}
为了向别人、向世界证明自己而努力拼搏,而一旦你真的取得了成绩,才会明白:人无须向别人证明什么,只要你能超越自己。