Android实现录屏直播+远程控制(一)
前言
由于公司项目需求,需要做一个录屏推流的东东,我会把项目开发中遇到的一些问题,以及如何解决的写下来
那么接下来我就把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 5.0以上屏幕录制的基本流程操作,有不懂的随时私信。
PS:转载请注明出处
-- The end