Android屏幕录制源码Demo下载
2015-11-07 17:36
477 查看
Android实现屏幕录制的方式介绍两种,第一种是通过adb shell命令,还一种使用SDK的提供的方法实现.
adb shell 命令
语法: screenrecord [options] <filename>
如果在APP中使用,我们可以通过Process p = Runtime.getRuntime().exec(cmd)来调用shell命令.但是只有system app才能调用,可以在manifest节点中添加android:sharedUserId="android.uid.system"拥有系统级的权限
通过MediaProjection实现
1.动态申请录音和外部存储权限:
2.获取屏幕录制的权限
3.启动屏幕录制服务
屏幕录制服务
代码地址
Android屏幕截图实现方式 & 系统截屏源码分析和三指截屏
adb shell 命令
语法: screenrecord [options] <filename>
Sample: adb shell screenrecord /sdcard/demo.mp4 开始录制(录制手机屏幕; 视频格式为mp4,存放到手机sd卡里,默认录制时间为180s) 参数: --size adb shell screenrecord --size 1280*720 /sdcard/demo.mp4 指定视频分辨率大小 (指定分辨率为1280*720;不指定则默认使用手机的分辨率,为获得最佳效果,请使用设备上的高级视频编码(AVC)支持的大小) 参数: --bit-rate adb shell screenrecord --bit-rate 6000000 /sdcard/demo.mp4 指定视频的比特率 (指定视频的比特率为6Mbps; 如果不指定则默认为4Mbps, 你可以增加比特率以提高视频质量或为了让文件更小而降低比特率) 参数: --time-limit adb shell screenrecord --time-limit 10 /sdcard/demo.mp4 限制录制时间 (限制视频录制时间为10s; 如果不限制,默认180s) 参数: --verbose adb shell screenrecord --time-limit 10 --verbose /sdcard/demo.mp4 在命令行显示录屏Log如下: xxxx:/ # screenrecord --time-limit 10 --verbose /sdcard/demo.mp4 Main display is 1080x2160 @60.00fps (orientation=0) Configuring recorder for 1080x2160 video/avc at 4.00Mbps Content area is 1080x2160 at offset x=0 y=0 Time limit reached Encoder stopping; recorded 34 frames in 10 seconds Stopping encoder and muxer Executing: /system/bin/am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file:///sdcard/demo.mp4 Broadcasting: Intent { act=android.intent.action.MEDIA_SCANNER_SCAN_FILE dat=file:///sdcard/demo.mp4 } Broadcast completed: result=0 参数: --bugreport 添加额外的信息,例如时间戳覆盖,这有助于捕获用于演示错误的视频 参数: --help 查看帮助 导出视频: adb pull /sdcard/demo.mp4
如果在APP中使用,我们可以通过Process p = Runtime.getRuntime().exec(cmd)来调用shell命令.但是只有system app才能调用,可以在manifest节点中添加android:sharedUserId="android.uid.system"拥有系统级的权限
通过MediaProjection实现
1.动态申请录音和外部存储权限:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 10); }
2.获取屏幕录制的权限
MediaProjectionManager manager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE); Intent intent = new Intent(manager.createScreenCaptureIntent()); startActivityForResult(intent, REQUEST_CODE);
3.启动屏幕录制服务
Intent service = new Intent(this, ScreenRecordService.class); service.putExtra("resultCode", resultCode); service.putExtra("data", data); service.putExtra("mWidthPixels", mWidthPixels); service.putExtra("mHeightPixels", mHeightPixels); service.putExtra("mDensityDpi", mDensityDpi); startService(service);
屏幕录制服务
public class ScreenRecordService extends Service { private static final String TAG = "ScreenRecordService"; private WindowManager mWindowManager; private WindowManager.LayoutParams wmParams; private LinearLayout mFloatLayout; private MediaProjection mMediaProjection; private MediaRecorder mMediaRecorder; private VirtualDisplay mVirtualDisplay; private boolean isScreenRecord; private int mScreenDensity, mWidthPixels, mHeightPixels; @Override public IBinder onBind(Intent intent) { // return new MyBinder(); return null; } @Override public void onCreate() { super.onCreate(); initView(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { int resultCode = intent.getIntExtra("resultCode", -1); Intent data = intent.getParcelableExtra("data"); mWidthPixels = intent.getIntExtra("mWidthPixels", 720); mHeightPixels = intent.getIntExtra("mHeightPixels", 1080); mScreenDensity = intent.getIntExtra("mDensityDpi", 1); Log.d(TAG, "initData --> mScreenDensity: " + mScreenDensity + " mWidthPixels: " + mWidthPixels + " mHeightPixels: " + mHeightPixels); mMediaProjection = ((MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE)) .getMediaProjection(resultCode, data); return super.onStartCommand(intent, flags, startId); } private void startRecorder() { Log.d(TAG, "startRecord"); isScreenRecord = true; createMediaRecorder(); createVirtualDisplay(); // 在mediaRecorder.prepare() 之后调用,否则报错 failed to get surface mMediaRecorder.start(); } private void createVirtualDisplay() { mVirtualDisplay = mMediaProjection.createVirtualDisplay(TAG, mWidthPixels, mHeightPixels, mScreenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mMediaRecorder.getSurface(), null, null); } private void createMediaRecorder() { // 生成文件名 SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); String curTime = formatter.format(new Date(System.currentTimeMillis())); mMediaRecorder = new MediaRecorder(); //设置视频源: DEFAULT,Surface,Camera mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); //设置视频输出格式: amr_nb,amr_wb,default,mpeg_4,raw_amr,three_gpp mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); //设置视频编码格式: default, H263, H264, MPEG_4_SP mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); // //设置音频源 // mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT); // // //设置音频编码格式: default,AAC,AMR_NB,AMR_WB // mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); //设置视频尺寸大小 mMediaRecorder.setVideoSize(mWidthPixels, mHeightPixels); //设置视频编码的码率 mMediaRecorder.setVideoEncodingBitRate(5 * mWidthPixels * mHeightPixels); // mWidthPixels * mHeightPixels //设置视频编码的帧率 mMediaRecorder.setVideoFrameRate(60); // 30 //设置视频输出路径 mMediaRecorder.setOutputFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES) + "/Ansen_" + curTime + ".mp4"); try { mMediaRecorder.prepare(); } catch (IOException e) { e.printStackTrace(); Log.e(TAG, e.getMessage()); } Log.d(TAG, "VideoSize: " + mWidthPixels + " X " + mHeightPixels + " VideoEncodingBitRate: " + (5 * mWidthPixels * mHeightPixels) + " +VideoFrameRate: " + "60"); } private void initView() { mWindowManager = (WindowManager) getApplication().getSystemService(getApplication().WINDOW_SERVICE); wmParams = new WindowManager.LayoutParams(); wmParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;// 设置window type为TYPE_SYSTEM_ALERT wmParams.format = PixelFormat.RGBA_8888;// 设置图片格式,效果为背景透明 wmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;// 设置浮动窗口不可聚焦(实现操作除浮动窗口外的其他可见窗口的操作) wmParams.gravity = Gravity.LEFT | Gravity.TOP;// 默认位置:右下角 wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT; wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT; wmParams.x = (ScreenUtils.getScreenWidth(getApplicationContext()) - wmParams.width) / 2;// 设置x、y初始值,相对于gravity wmParams.y = 10; // 浮动窗口布局 mFloatLayout = (LinearLayout) LayoutInflater.from(getApplication()).inflate(R.layout.screen_recorder, null); mWindowManager.addView(mFloatLayout, wmParams); final LinearLayout screenrecord = (LinearLayout) mFloatLayout.findViewById(R.id.screenrecord); final TextView title = (TextView) mFloatLayout.findViewById(R.id.screenrecord_title); final TextView close = (TextView) mFloatLayout.findViewById(R.id.screenrecord_close); final ImageView image = (ImageView) mFloatLayout.findViewById(R.id.play_stop); mFloatLayout.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); // 设置监听浮动窗口的触摸移动 View.OnTouchListener mOnTouchListener = new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // getRawX是触摸位置相对于屏幕的坐标,getX是相对于按钮的坐标 wmParams.x = (int) event.getRawX() - mFloatLayout.getMeasuredWidth() / 2; Log.i(TAG, "RawX" + event.getRawX() + " X" + event.getX()); wmParams.y = (int) event.getRawY() - mFloatLayout.getMeasuredHeight() / 2 - 25;// 减25为状态栏的高度 Log.i(TAG, "RawY" + event.getRawY() + " Y" + event.getY()); mWindowManager.updateViewLayout(mFloatLayout, wmParams);// 刷新 return false; } }; mFloatLayout.setOnTouchListener(mOnTouchListener); screenrecord.setOnTouchListener(mOnTouchListener); screenrecord.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (isScreenRecord) { image.setImageResource(R.mipmap.screen_record_play); title.setText("开始"); stopRecord(); } else { image.setImageResource(R.mipmap.screen_record_stop); title.setText("停止"); startRecorder(); } } }); close.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Log.d(TAG, "stopSelf"); ScreenRecordService.this.stopSelf(); } }); } private void stopRecord() { Log.d(TAG, "stopRecord"); isScreenRecord = false; mMediaRecorder.stop(); mMediaRecorder.reset(); } @Override public void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy"); if (isScreenRecord) { stopRecord(); } mVirtualDisplay.release(); mMediaProjection.stop(); mWindowManager.removeView(mFloatLayout); } }
代码地址
Android屏幕截图实现方式 & 系统截屏源码分析和三指截屏
相关文章推荐
- Android开发笔记 - 示例代码
- Android Spinner
- Android项目中如何用好构建神器Gradle?
- android 创建数据库
- Android 显示或者隐藏软键盘
- Android学习之volley
- Android下修改hosts文件
- Android开发文摘集合1
- Android监听自身卸载,弹出用户反馈调查
- Android监听自身卸载,弹出用户反馈调查
- Android监听自身卸载,弹出用户反馈调查
- AndroidL 开机展示Keyguard锁屏机制初探
- 初学Android,字符串,数字,尺寸,数组资源(十二)
- Android Weak Handler:可以避免内存泄漏的Handler库
- Android之登录那点事
- Android TextView中\n不能正常换行的问题
- Android的init过程(二):初始化语言(init.rc)解析
- Android的init过程详解(一)
- android ContentProvider简单介绍及使用
- Android Bundle类