音视频

Android实现录屏直播+远程控制(一)

2019-10-08  本文已影响0人  黄宏发

前言

由于公司项目需求,需要做一个录屏推流的东东,我会把项目开发中遇到的一些问题,以及如何解决的写下来
那么接下来我就把Android从录屏直播,再到控制写成一个系列的小文章
由于我实现的版本是基于5.0的,5.0前面的版本就不说了,想要了解的自行Google,先来看下效果图,有图有真相

1、在 Android 5.0,Google 终于开放了视频录制的接口,其实严格来说,是屏幕采集的接口,也就是 MediaProjection 和 MediaProjectionManager
2、接下来我们就看看Android是如何实现录屏的

具体实现步骤

1 申请权限

    <uses-permission android:name="android.permission.INTERNET" />
    <!--允许程序录制音频-->
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <!-- 允许程序修改全局音频设置 -->
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

如果开发的 app targetApi 在 6.0 以上时,还需要动态获取权限

   //发起权限申请
    private void requestPermissons() {
        String[] permissions = new String[]{
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.MODIFY_AUDIO_SETTINGS,
                Manifest.permission.RECORD_AUDIO//音频
        };
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                toast("用户拒绝权限申请");
            } else {
                ActivityCompat.requestPermissions(this, permissions, REQUEST_PERMISSIONS);
            }
        }
    }

权限工作准备完成后就进行编码了

2 获取 MediaProjectionManager 实例对象并且发起一个屏幕采集请求

  
  private MediaProjectionManager mMediaProjectionManage;

    /**
     * 开始录屏
     */
    private void requestRecording() {
        mMediaProjectionManage = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
        Intent captureIntent = null;
        if (mMediaProjectionManage != null) {
            captureIntent = mMediaProjectionManage.createScreenCaptureIntent();
        }
        startActivityForResult(captureIntent, RECORD_REQUEST_CODE);
    }

3 获取 MediaProjection

通过发起一个屏幕捕捉请求,在onActivityResult 返回结果获取 MediaProjection

private VirtualDisplay mVirtualDisplay;
private MediaProjection mMediaProjection;
/**
     * 跳转回调
     *
     * @param requestCode
     * @param resultCode
     * @param data
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == RECORD_REQUEST_CODE) {
            if (resultCode == RESULT_OK) {
                 mMediaProjection= mManager.getMediaProjection(resultCode, data);
            } else {
                toast("requestRecordFail: 用戶拒绝录制屏幕");
            }
        }
    }

4 创建虚拟屏幕

1、通过onActivityResult 回调获取一个MediaProjection对象
2、这样我们就可以去创建一个VirtualDisplay
3、调用mMediaProjection.createVirtualDisplay()就可以返回一个mVirtualDisplay;
4、使用MediaCodec创建一个surface
ps:最终的实现都是通过DisplayManagerGlobal这类,这里就不贴源码了,感兴趣的小伙伴自行去阅读查看

        Surface surface = MediaCodec.createInputSurface();
        //实例化VirtualDisplay,这个类的主要作用是用来获取屏幕信息并保存在里。
        mVirtualDisplay= mMediaProjection.createVirtualDisplay("ScreenRecord",
                width, height, 1, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, surface,
                null, null);

这里说一下VirtualDisplay类,VirtualDisplay类代表一个虚拟显示器,需要调用DisplayManager 类的 createVirtualDisplay()方法,将虚拟显示器的内容渲染在一个Surface控件上,我们录制的屏幕数据其实都是渲染在一个Surface控件上

5 MediaCodec编码,也就是我们获取屏幕数据的关键一员

当然这里面也可以使用MediaRecord去实现录屏获取数据

public static MediaCodec getVideoMediaCodec() {
        MediaFormat format = MediaFormat.createVideoFormat("video/avc", 720, 1280);
        //设置颜色格式
        format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
                MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
        //设置比特率(设置码率,通常码率越高,视频越清晰)
        format.setInteger(MediaFormat.KEY_BIT_RATE, 1000 * 1024);
        //设置帧率
        format.setInteger(MediaFormat.KEY_FRAME_RATE, 10);
        //关键帧间隔时间,通常情况下,你设置成多少问题都不大。
        format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10);
        // 当画面静止时,重复最后一帧,不影响界面显示
        format.setLong(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER, 1000000 / 45);
        format.setInteger(MediaFormat.KEY_BITRATE_MODE, MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR);
        //设置复用模式
        format.setInteger(MediaFormat.KEY_COMPLEXITY, MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR);
        MediaCodec mediaCodec = null;
        try {
//            MediaRecorder mediaRecorder = new MediaRecorder();
            mediaCodec = MediaCodec.createEncoderByType("video/avc");
            mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
        } catch (Exception e) {
            e.printStackTrace();
            if (mediaCodec != null) {
                mediaCodec.reset();
                mediaCodec.stop();
                mediaCodec.release();
                mediaCodec = null;
            }
        }
        return mediaCodec;
    }

Android实现录屏直播+远程控制(二)

结束语

好了,以上就是Android 5.0以上屏幕录制的基本流程操作,有不懂的随时私信。
PS:转载请注明出处
-- The end

上一篇下一篇

猜你喜欢

热点阅读