Android 录屏服务使用(源码)

Android 录屏服务使用(源码)

从Android 5.0开始,可以对手机进行录屏,使用场景:如错误场景的视频上传,简单屏幕获取等,下面贴出使用用例和对使用的类一个简单的介绍
- MediaProjection
- MediaRecorder
- VirtualDisplay
- 使用
- 总结


MediaProjection

MediaProjection是一个5.0之后给开发者提供的新的截屏或者录屏的新手段。MediaProjection可以用来捕捉屏幕
这里我们主要用到的一个方法是

public VirtualDisplay createVirtualDisplay(String name, int width, int height, int dpi, int flags, Surface surface, android.hardware.display.VirtualDisplay.Callback callback, Handler handler) {
        throw new RuntimeException("Stub!");
    }

参数1:实际的流媒体显示实体名字,不能为null;

参数2:实际的流媒体显示实体的宽度,单位为像素,必须大于0;

参数3:实际的流媒体显示实体的高度,单位为像素,必须大于0;

参数4:实际的流媒体显示实体的像素密度,单位为dp,必须大于0;

参数5:实际的流媒体显示实体标志的结合,更多请查看 DisplayManager里头的标志,取值是{VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY,VIRTUAL_DISPLAY_FLAG_PRESENTATION,
VIRTUAL_DISPLAY_FLAG_PUBLIC,
VIRTUAL_DISPLAY_FLAG_SECURE}中的一个

参数6:播放流媒体的surface实例,可为null,如果木有;

参数7:实际的流媒体显示实体状态改变时的回调方法,可能为null;

参数8:调用参数7回调方法的handler;

返回VirtualDisplay实例,具体请查看VirtualDisplay类;

MediaRecorder

增加对录制音视频的支持,Android系统提供了这个类。该类的使用也非常简单

以下是对MediaRecorder的配置

setAudioSource(MediaRecorder.AudioSource.);
设置声音来源,一般传入 MediaRecorder. AudioSource.MIC参数指定录制来自麦克风的声音。(这里如果只录屏可以不设置)
setVideoSource(MediaRecorder.VideoSource.SURFACE);
设置用于录制的视频来源。如屏幕等
setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
设置所录制的音视频文件的格式。
setOutputFile(getsaveDirectory() + temp + “.mp4”);
设置录制的音频文件的保存位置。
setVideoSize(width, height);最高只能设置640x480
设置要拍摄的宽度和视频的高度。
setVideoEncoder(MediaRecorder.VideoEncoder.H264);
设置视频的编码格式
setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
设置音频编码格式
setVideoEncodingBitRate(1024 * 1024);
设置所录制视频的编码位率。
setVideoFrameRate(18);
设置录制视频的捕获帧速率。
setOrientationHint(90);
设置输出的视频播放的方向提示。
setMaxDuration(30*1000);
设置录制会话的最长持续时间(以ms为单位)。
prepare();
准备录制

VirtualDisplay

VirtualDisplay类代表一个虚拟显示器,需要调用DisplayManager 类的 createVirtualDisplay()方法,将虚拟显示器的内容渲染在一个Surface控件上,当进程终止时虚拟显示器会被自动的释放,并且所有的Window都会被强制移除。当不再使用他时,你应该调用release() 方法来释放资源。
这个类中主要有6个主要方法,主要是用来操作显示器,例如获取显示器,设置/得到surface,

注意,有些app例如游戏的每一次操作的录制,如果频繁的创建这个VirtualDisplay,会让手机内存持续消耗,让手机变卡,所以创建的操作放在服务中,系统会自动提用当前创建的VirtualDisplay不会频繁创建和不释放

简单的方法
Surface getSurface ()
获取虚拟显示器的surface。
release ()
释放显示器,并且销毁其所依据的surface
resize (int width, int height, int densityDpi)
运行应用程序使用虚拟现实器去适应改变的条件状态,而不用销毁再重建一个实例。
setSurface (Surface surface)
设置虚拟显示器依靠的surface。移除虚拟显示器所依靠的surface相当于关闭屏幕的操作。调用者///需要手动的销毁surface。

使用

创建一个服务 RecordUtil 在录屏之前启动这个服务,可以在AppApplication 中开启这个服务,具体的录屏界面去绑定这个服务,注意在AndroidManifest.xml中注册这个服务

服务

public class RecordUtil extends Service {
//    private static RecordUtil recordUtil = null;
    private MediaProjection mediaProjection;



    private MediaRecorder mediaRecorder;
    private  VirtualDisplay virtualDisplay;
    private boolean running;
    private int width = 320;
    private int height = 420;
    private int dpi;
    private Context context;

    public static int current = 0;

    public RecordUtil(){

    }

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

    @Override
    public void onCreate() {
        super.onCreate();
        HandlerThread serviceThread = new HandlerThread("service_thread",
                android.os.Process.THREAD_PRIORITY_BACKGROUND);
        serviceThread.start();
        running = false;
        mediaRecorder = new MediaRecorder();
    }

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

    @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;
    }

    public boolean startRecord(String temp) {
        if(mediaRecorder != null) {
            if (mediaProjection == null || running) {
                return false;
            }
            try {
                initRecorder(temp);
                createVirtualDisplay();
                mediaRecorder.start();
                running = true;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return true;
    }

    public boolean stopRecord() {
        if(mediaRecorder != null) {
            if (!running) {
                return false;
            }
            try {
                running = false;
                mediaRecorder.stop();
            mediaRecorder.reset();
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                    virtualDisplay.release();
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                        mediaProjection.stop();
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        return true;
    }

    public boolean release(){
        if(mediaRecorder != null && hasLollipop()) {
            if (!running) {
                return false;
            }
            try {
                running = false;
                mediaRecorder.stop();
                mediaRecorder.reset();
                virtualDisplay.release();
                mediaProjection.stop();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return true;
    }

    public static boolean hasLollipop(){
        return Build.VERSION.SDK_INT >= 21;
    }

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

    }

    private void initRecorder(String temp) {
        if(mediaRecorder != null) {
            try {
                // mediaRecorder.setAudioSource(MediaRecorder.AudioSource.);
                mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
                mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                mediaRecorder.setOutputFile(getsaveDirectory() + temp + ".mp4");
                //mediaRecorder.setVideoSize(width, height);
                mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
                // mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
                mediaRecorder.setVideoEncodingBitRate(1024 * 1024);
                mediaRecorder.setVideoFrameRate(18);
                //设置要捕获的视频的宽度和高度
                //mSurfaceHolder.setFixedSize(320, 240);//最高只能设置640x480
                mediaRecorder.setVideoSize(width, height);//最高只能设置640x480
                //mediaRecorder.setOrientationHint(90);
                //mediaRecorder.setMaxDuration(30*1000);
                mediaRecorder.prepare();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static String getsaveDirectory() {
        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;
                }
            }

            //Toast.makeText(context, rootDir, Toast.LENGTH_SHORT).show();

            return rootDir;
        } else {
            return null;
        }
    }


    /**
     * 递归删除文件
     * @param file
     */
    public static void recursionDeleteFile(File file){
        try {
            if(file.isFile()){
                file.delete();
                return;
            }
            if(file.isDirectory()){
                File[] childFile = file.listFiles();
                if(childFile == null || childFile.length == 0){
                    file.delete();
                    return;
                }
                for(File f : childFile){
                    recursionDeleteFile(f);
                }
                file.delete();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public class RecordBinder extends Binder {
        public RecordUtil getRecordService() {
            return RecordUtil.this;
        }
    }
}

AppApplication

 startService(new Intent(this, RecordUtil.class));

Activity


 public MediaProjectionManager projectionManager;
 public MediaProjection mediaProjection;
 public RecordUtil recordService;

 绑定服务
 public void bind(){
   Intent intent = new Intent(this, RecordUtil.class);
   bindService(intent, connection, BIND_AUTO_CREATE);
}

并在Activity重写
 @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        try {
            Logger.i("----activity-->" + requestCode + "---result--->" + resultCode);

            Logger.i("----activity-->" + requestCode + "---result--->" + resultCode);
            UMShareAPI.get(this).onActivityResult(requestCode, resultCode, data);

            if(DeviceUtils.hasLollipop()) {
                if (requestCode == 101 && resultCode == RESULT_OK) {
//                   RecordUtil recordUtil=new RecordUtil();
                    if (RecordUtil.hasLollipop()) {
                        Logger.e("________________________onActivityResult");
                        mediaProjection = projectionManager.getMediaProjection(resultCode, data);
                        recordService.setMediaProject(mediaProjection);
                        /*if (RecordUtil.current > 3) {
                            RecordUtil.current = 0;
                        }*/
                        RecordUtil.current++;
                        //RecordUtil.getInstance().setOutFile("temp"+RecordUtil.current);
                        recordService.startRecord("temp" + RecordUtil.current);
                    }
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
 private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {
            DisplayMetrics metrics = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(metrics);
            RecordUtil.RecordBinder binder = (RecordUtil.RecordBinder) service;
            recordService = binder.getRecordService();
            recordService.setConfig(320, 420, metrics.densityDpi);
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {}
    };
 @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(connection);

    }

启动录屏

if(RecordUtil.hasLollipop()) {
                                if(mediaProjection != null){
                                    if(ecordService.isRunning()){
                                        recordService.stopRecord();
                                    }
                                }
                                Logger.e("_________________________录制视频开始");
                                RecordUtil.current++;
                                Intent captureIntent =projectionManager.createScreenCaptureIntent();
         startActivityForResult(captureIntent, RECORD_REQUEST_CODE);
                                if (ContextCompat.checkSelfPermission(mActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                                        != PackageManager.PERMISSION_GRANTED) {
                                    ActivityCompat.requestPermissions(mActivity,
                                            new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, STORAGE_REQUEST_CODE);
                                }

                                if (ContextCompat.checkSelfPermission(mActivity, Manifest.permission.RECORD_AUDIO)
                                        != PackageManager.PERMISSION_GRANTED) {
                                    ActivityCompat.requestPermissions(mActivity,
                                            new String[] {Manifest.permission.RECORD_AUDIO}, AUDIO_REQUEST_CODE);
                                }


                            }

获得录屏文件路径

  if (recordService.isRunning()) {
                       recordService.stopRecord();
      }
    try {
                            File file = new File(RecordUtil.getsaveDirectory() + "temp" + RecordUtil.current + ".mp4");
                            Logger.i("----file exit--->" + file.exists() + "-----file url--->" + file.getAbsolutePath());
                            if (file.exists()) {
                                //上传
                                Logger.e("_________________________存在");
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }

路还很长,慢慢走

猜你喜欢

转载自blog.csdn.net/qq_28535319/article/details/80047934