100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > 两个类实现Android录制屏幕功能

两个类实现Android录制屏幕功能

时间:2021-07-21 14:14:40

相关推荐

两个类实现Android录制屏幕功能

两个类实现Android录制屏幕功能

原理

Android4.4开始支持录制屏幕,但首先需要获取Root权限才可以运行。

Android5.0及之后Android API 开放了视频录制的接口,其实严格来说,是屏幕采集的接口,也就是 MediaProjection 和 MediaProjectionManager。该篇文章是基于该方法进行的录制。

一、申请权限

AndroidManifest配置

<uses-permission android:name="android.permission.RECORD_AUDIO" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

Android6.0后的动态权限

public static void checkPermission(AppCompatActivity activity) {if (Build.VERSION.SDK_INT >= 23) {int checkPermission =ContextCompat.checkSelfPermission(activity, Manifest.permission.RECORD_AUDIO)+ ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_PHONE_STATE)+ ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)+ ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE);if (checkPermission != PackageManager.PERMISSION_GRANTED) {//动态申请ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.RECORD_AUDIO,Manifest.permission.READ_PHONE_STATE,Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE}, 123);}}}

二、申请允许录制屏幕

检查权限初始化MediaProjectionManager申请录制屏幕,会出现提示屏幕录制的系统弹窗在onActivityResult拿到是否允许的结果在结果成功时开启Service进行录制屏幕

该类代码如下

import android.Manifest;import android.app.Activity;import android.content.Intent;import android.content.pm.PackageManager;import android.media.projection.MediaProjectionManager;import android.os.Build;import android.support.v4.app.ActivityCompat;import android.support.v4.content.ContextCompat;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Toast;import com.screen.recorder.demo.service.ScreenRecordService;/*** @author by talon, Date on 19/6/23.* note:*/public class MainActivity extends AppCompatActivity {private static final int REQUEST_CODE = 1;private MediaProjectionManager mMediaProjectionManager;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);checkPermission(this); //检查权限mMediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);}public void StartRecorder(View view) {createScreenCapture();}public void StopRecorder(View view){Intent service = new Intent(this, ScreenRecordService.class);stopService(service);}public static void checkPermission(AppCompatActivity activity) {if (Build.VERSION.SDK_INT >= 23) {int checkPermission =ContextCompat.checkSelfPermission(activity, Manifest.permission.RECORD_AUDIO)+ ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_PHONE_STATE)+ ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)+ ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE);if (checkPermission != PackageManager.PERMISSION_GRANTED) {//动态申请ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.RECORD_AUDIO,Manifest.permission.READ_PHONE_STATE,Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE}, 123);}}}private void createScreenCapture() {Intent captureIntent = mMediaProjectionManager.createScreenCaptureIntent();startActivityForResult(captureIntent, REQUEST_CODE);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK) {try {Toast.makeText(this, "允许录屏", Toast.LENGTH_SHORT).show();Intent service = new Intent(this, ScreenRecordService.class);service.putExtra("resultCode", resultCode);service.putExtra("data", data);startService(service);} catch (Exception e) {e.printStackTrace();}} else {Toast.makeText(this, "拒绝录屏", Toast.LENGTH_SHORT).show();}}}

对应的视图代码如下

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="/apk/res/android"xmlns:app="/apk/res-auto"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="开始录制"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"android:onClick="StartRecorder"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="停止录制"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"android:onClick="StopRecorder"/></LinearLayout>

三、进行录制屏幕

拿到传递由onActivityResult回调产生的resultCodedata获取手机屏幕的宽高与dpi创建MediaProjectionMediaRecorderVirtualDisplaycreateMediaRecorder方法中配置保存视频的信息,文件的路径、文件名、清晰度等

该类代码如下

import android.app.Service;import android.content.Context;import android.content.Intent;import android.hardware.display.DisplayManager;import android.hardware.display.VirtualDisplay;import android.media.MediaRecorder;import android.media.projection.MediaProjection;import android.media.projection.MediaProjectionManager;import android.os.Environment;import android.os.IBinder;import android.util.Log;import com.screen.recorder.demo.utils.ScreenUtils;import java.io.IOException;import java.text.SimpleDateFormat;import java.util.Date;/*** @author by talon, Date on 19/6/23.* note:*/public class ScreenRecordService extends Service {private final String TAG = "ScreenRecordService";/*** 是否为标清视频*/private boolean isVideoSd = false;private int mScreenWidth;private int mScreenHeight;private int mScreenDensity;private int mResultCode;private Intent mResultData;private MediaProjection mMediaProjection;private MediaRecorder mMediaRecorder;private VirtualDisplay mVirtualDisplay;public ScreenRecordService() {}@Overridepublic IBinder onBind(Intent intent) {// TODO: Return the communication channel to the service.return null;}@Overridepublic void onCreate() {super.onCreate();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {mResultCode = intent.getIntExtra("resultCode", 1);mResultData = intent.getParcelableExtra("data");getScreenBaseInfo();mMediaProjection = createMediaProjection();mMediaRecorder = createMediaRecorder();mVirtualDisplay = createVirtualDisplay(); // 必须在mediaRecorder.prepare() 之后调用,否则报错"fail to get surface"mMediaRecorder.start();return Service.START_NOT_STICKY;}@Overridepublic void onDestroy() {super.onDestroy();Log.i(TAG, "onDestroy");if(mVirtualDisplay != null) {mVirtualDisplay.release();mVirtualDisplay = null;}if(mMediaRecorder != null) {mMediaRecorder.setOnErrorListener(null);mMediaProjection.stop();mMediaRecorder.reset();}if(mMediaProjection != null) {mMediaProjection.stop();mMediaProjection = null;}}/*** 获取屏幕相关数据*/private void getScreenBaseInfo() {mScreenWidth = ScreenUtils.getScreenWidth(this);mScreenHeight = ScreenUtils.getScreenHeight(this);mScreenDensity = ScreenUtils.getScreenDensityDpi(this);}private MediaProjection createMediaProjection() {Log.i(TAG, "Create MediaProjection");return ((MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE)).getMediaProjection(mResultCode, mResultData);}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 blocke.printStackTrace();}return mediaRecorder;}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);}}

四、完整Demo下载地址

点我下载,没有积分联系微信公众号“Android唐浮”

五、评论反馈

问题1: java.lang.IllegalStateException: failed to get surface

原因:目前已知在android9、10中没有Environment.DIRECTORY_MOVIES(Movies)文件夹,可以更改为Environment.DIRECTORY_DOWNLOADS(Downloads)文件夹,如果不放心,可以自己创建文件夹。

联系

遇到问题或想持续学习,请关注公众号“Android唐浮”

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。