Android截屏和录屏Demo
2018-01-10 22:51
239 查看
最近两天研究了一下安卓截屏和录屏功能的实现,基本的思路如下:
截屏:通过View绘制缓冲获得Bitmap,然后写到文件中,完成截屏的功能;
录屏:通过MediaRecorder进行video record,基本过程如下:
要是想实现录屏功能,首先需要向系统申请权限,然后得到系统的反馈,分别创建录屏服务、MediaProjectionManager、MediaRecorder以及创建VirtualDisplay,最后开始录屏。录屏结束后对相关资源进行释放。
下面上代码:
首先是配置权限:
然而在实际开发中发生了如下一幕,Permission Deny.这个时候可能是相关的权限没有自动打开,需要手动去应用权限管理中将相关的权限打开,如下:
然后就是写界面XML(界面很简单):
效果如下:
接下来是MainActivity.java(相关说明写在注释中了,直接参考的API,准确一些,现在访问API可方便多了,哈哈哈)
录屏ScreenRecordService.java
OK,完成,相关的解释直接写在代码中了。
非淡泊无以明志,非宁静无以致远。共勉。
Demo下载地址:http://download.csdn.net/download/dzjin1234/10199546
截屏:通过View绘制缓冲获得Bitmap,然后写到文件中,完成截屏的功能;
录屏:通过MediaRecorder进行video record,基本过程如下:
MediaRecorder recorder = new MediaRecorder(); recorder.setAudioSource(MediaRecorder.AudioSource.MIC); recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); recorder.setOutputFile(PATH_NAME); recorder.prepare(); recorder.start(); // Recording is now started ... recorder.stop(); recorder.reset(); // You can reuse the object by going back to setAudioSource() step recorder.release(); // Now the object cannot be reused
要是想实现录屏功能,首先需要向系统申请权限,然后得到系统的反馈,分别创建录屏服务、MediaProjectionManager、MediaRecorder以及创建VirtualDisplay,最后开始录屏。录屏结束后对相关资源进行释放。
下面上代码:
首先是配置权限:
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.CAMERA"/>
然而在实际开发中发生了如下一幕,Permission Deny.这个时候可能是相关的权限没有自动打开,需要手动去应用权限管理中将相关的权限打开,如下:
然后就是写界面XML(界面很简单):
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/linearLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> <Button android:id="@+id/buttonCapture" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginEnd="20dp" android:layout_marginStart="20dp" android:text="截屏" android:textSize="24sp" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> <Button android:id="@+id/buttonRecord" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginEnd="20dp" android:layout_marginStart="20dp" android:text="录屏" android:textSize="24sp" /> </LinearLayout> </LinearLayout>
效果如下:
接下来是MainActivity.java(相关说明写在注释中了,直接参考的API,准确一些,现在访问API可方便多了,哈哈哈)
package com.dzjin.screen.screenshotandrecorddemo; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.media.projection.MediaProjectionManager; import android.os.Environment; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.DisplayMetrics; import android.view.KeyEvent; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.Toast; import java.io.FileOutputStream; import java.text.SimpleDateFormat; import java.util.Date; public class MainActivity extends AppCompatActivity { private LinearLayout linearLayout=null; private Button buttonRecord=null; private Button buttonCapture=null; private boolean isRecord=false; private int mScreenWidth; private int mScreenHeight; private int mScreenDensity; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); getScreenBaseInfo(); linearLayout=(LinearLayout)findViewById(R.id.linearLayout); buttonRecord=(Button)findViewById(R.id.buttonRecord); buttonCapture=(Button)findViewById(R.id.buttonCapture); buttonRecord.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if(isRecord){ stopScreenRecord(); }else{ startScreenRecord(); } } }); buttonCapture.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { capture(linearLayout); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(requestCode == 1000){ if(resultCode == RESULT_OK){ //获得录屏权限,启动Service进行录制 Intent intent=new Intent(MainActivity.this,ScreenRecordService.class); intent.putExtra("resultCode",resultCode); intent.putExtra("resultData",data); intent.putExtra("mScreenWidth",mScreenWidth); intent.putExtra("mScreenHeight",mScreenHeight); intent.putExtra("mScreenDensity",mScreenDensity); startService(intent); Toast.makeText(this,"录屏开始",Toast.LENGTH_SHORT).show(); }else{ Toast.makeText(this,"录屏失败",Toast.LENGTH_SHORT).show(); } } } //start screen record private void startScreenRecord(){ //Manages the retrieval of certain types of MediaProjection tokens. MediaProjectionManager mediaProjectionManager= (MediaProjectionManager)getSystemService(Context.MEDIA_PROJECTION_SERVICE); //Returns an Intent that must passed to startActivityForResult() in order to start screen capture. Intent permissionIntent=mediaProjectionManager.createScreenCaptureIntent(); startActivityForResult(permissionIntent,1000); isRecord=true; buttonRecord.setText(new String("停止录屏")); } //stop screen record. private void stopScreenRecord(){ Intent service = new Intent(this, ScreenRecordService.class); stopService(service); isRecord=false; buttonRecord.setText(new String("开始录屏")); Toast.makeText(this,"录屏成功",Toast.LENGTH_SHORT).show(); } public void capture(View v){ //格式化时间作为截屏文件名 SimpleDateFormat simpleDateFormat=new SimpleDateFormat("YY-MM-DD-HH-MM-SS"); //在获取外部存储的时候,一定注意添加权限,如果添加权限还不能成功,则手动在应用中开启权限。 String filePathName= Environment.getExternalStorageDirectory()+"/"+simpleDateFormat.format(new Date())+".png"; //Find the topmost view in the current view hierarcht. View view=v.getRootView(); // Enable or disable drawing cache. view.setDrawingCacheEnabled(true); // Calling this method is equivalent to calling buildDrawingCache(false); // In order to force drawing cache to be buuild. view.buildDrawingCache(); //Calling this method is equivalent to calling getDrawingCache(false); //Return the Bitmap in which this view drawing is cached. Bitmap bitmap=view.getDrawingCache(); try{ System.out.println(filePathName); FileOutputStream fileOutputStream=new FileOutputStream(filePathName); //Write a compressed version of bitmap to specified outputStream. bitmap.compress(Bitmap.CompressFormat.PNG,100,fileOutputStream); Toast.makeText(this,"Cpature Succeed",Toast.LENGTH_SHORT).show(); }catch (Exception e){ e.printStackTrace(); Toast.makeText(this,"Cpature Failed",Toast.LENGTH_SHORT).show(); } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { // 在这里将BACK键模拟了HOME键的返回桌面功能(并无必要) if (keyCode == KeyEvent.KEYCODE_BACK) { simulateHome(); return true; } return super.onKeyDown(keyCode, event); } /** * 获取屏幕基本信息 */ private void getScreenBaseInfo() { //A structure describing general information about a display, such as its size, density, and font scaling. DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); mScreenWidth = metrics.widthPixels; mScreenHeight = metrics.heightPixels; mScreenDensity = metrics.densityDpi; } /** * 模拟HOME键返回桌面的功能 */ private void simulateHome() { //Intent.ACTION_MAIN,Activity Action: Start as a main entry point, does not expect to receive data. Intent intent = new Intent(Intent.ACTION_MAIN); //If set, this activity will become the start of a new task on this history stack. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //This is the home activity, that is the first activity that is displayed when the device boots. intent.addCategory(Intent.CATEGORY_HOME); this.startActivity(intent); } }
录屏ScreenRecordService.java
package com.dzjin.screen.screenshotandrecorddemo; 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.support.annotation.Nullable; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by dzjin on 2018/1/9. */ public class ScreenRecordService extends Service { private int resultCode; private Intent resultData=null; private MediaProjection mediaProjection=null; private MediaRecorder mediaRecorder=null; private VirtualDisplay virtualDisplay=null; private int mScreenWidth; private int mScreenHeight; private int mScreenDensity; private Context context=null; @Override public void onCreate() { super.onCreate(); } /** * Called by the system every time a client explicitly starts the service by calling startService(Intent), * providing the arguments it supplied and a unique integer token representing the start request. * Do not call this method directly. * @param intent * @param flags * @param startId * @return */ @Override public int onStartCommand(Intent intent, int flags, int startId) { try{ resultCode=intent.getIntExtra("resultCode",-1); resultData=intent.getParcelableExtra("resultData"); mScreenWidth=intent.getIntExtra("mScreenWidth",0); mScreenHeight=intent.getIntExtra("mScreenHeight",0); mScreenDensity=intent.getIntExtra("mScreenDensity",0); mediaProjection=createMediaProjection(); mediaRecorder=createMediaRecorder(); virtualDisplay=createVirtualDisplay(); mediaRecorder.start(); }catch (Exception e) { e.printStackTrace(); } /** * START_NOT_STICKY: * Constant to return from onStartCommand(Intent, int, int): if this service's process is * killed while it is started (after returning from onStartCommand(Intent, int, int)), * and there are no new start intents to deliver to it, then take the service out of the * started state and don't recreate until a future explicit call to Context.startService(Intent). * The service will not receive a onStartCommand(Intent, int, int) call with a null Intent * because it will not be re-started if there are no pending Intents to deliver. */ return Service.START_NOT_STICKY; } //createMediaProjection public MediaProjection createMediaProjection(){ /** * Use with getSystemService(Class) to retrieve a MediaProjectionManager instance for * managing media projection sessions. */ return ((MediaProjectionManager)getSystemService(Context.MEDIA_PROJECTION_SERVICE)) .getMediaProjection(resultCode,resultData); /** * Retrieve the MediaProjection obtained from a succesful screen capture request. * Will be null if the result from the startActivityForResult() is anything other than RESULT_OK. */ } private MediaRecorder createMediaRecorder(){ SimpleDateFormat simpleDateFormat=new SimpleDateFormat("YY-MM-DD-HH-MM-SS"); String filePathName= Environment.getExternalStorageDirectory()+"/video"+simpleDateFormat.format(new Date())+".mp4"; //Used to record audio and video. The recording control is based on a simple state machine. MediaRecorder mediaRecorder=new MediaRecorder(); //Set the video source to be used for recording. mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); //Set the format of the output produced during recording. //3GPP media file format mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); //Sets the video encoding bit rate for recording. //param:the video encoding bit rate in bits per second. mediaRecorder.setVideoEncodingBitRate(5*mScreenWidth*mScreenHeight); //Sets the video encoder to be used for recording. mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); //Sets the width and height of the video to be captured. mediaRecorder.setVideoSize(mScreenWidth,mScreenHeight); //Sets the frame rate of the video to be captured. mediaRecorder.setVideoFrameRate(60); try{ //Pass in the file object to be written. mediaRecorder.setOutputFile(filePathName); //Prepares the recorder to begin capturing and encoding data. mediaRecorder.prepare(); }catch (Exception e){ e.printStackTrace(); } return mediaRecorder; } private VirtualDisplay createVirtualDisplay(){ /** * name String: The name of the virtual display, must be non-empty.This value must never be null. width int: The width of the virtual display in pixels. Must be greater than 0. height int: The height of the virtual display in pixels. Must be greater than 0. dpi int: The density of the virtual display in dpi. Must be greater than 0. flags int: A combination of virtual display flags. See DisplayManager for the full list of flags. surface Surface: The surface to which the content of the virtual display should be rendered, or null if there is none initially. callback VirtualDisplay.Callback: Callback to call when the virtual display's state changes, or null if none. handler Handler: The Handler on which the callback should be invoked, or null if the callback should be invoked on the calling thread's main Looper. */ /** * DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR * Virtual display flag: Allows content to be mirrored on private displays when no content is being shown. */ return mediaProjection.createVirtualDisplay("mediaProjection",mScreenWidth,mScreenHeight,mScreenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,mediaRecorder.getSurface(),null,null); } @Override public void onDestroy() { super.onDestroy(); if(virtualDisplay!=null){ virtualDisplay.release(); virtualDisplay=null; } if(mediaRecorder!=null){ mediaRecorder.stop(); mediaRecorder=null; } if(mediaProjection!=null){ mediaProjection.stop(); mediaProjection=null; } } @Nullable @Override public IBinder onBind(Intent intent) { return null; } }
OK,完成,相关的解释直接写在代码中了。
非淡泊无以明志,非宁静无以致远。共勉。
Demo下载地址:http://download.csdn.net/download/dzjin1234/10199546
相关文章推荐
- android视频截屏&手机录屏实现
- Android系统 截屏监听 的 原理与实现
- Android 中自动同步的机制的简单的demo,例如订单同步,商品同步,会员同步,操作同步
- 【Android】如何快速构建Android Demo
- Android---观察者模式的简单实现demo
- Android实现矩形区域截屏的方法
- Android 高仿 频道管理----网易、今日头条、腾讯视频 (可以拖动的GridView)附源码DEMO
- android登录超时显示demo
- Android 使用腾讯微博SSO授权基于腾讯demo的修改
- Android蓝牙串口通信模板及demo,trick
- [Android官方Demo系列](API 15)AccelerometerPlay
- Android音视频学习——Camera2官方demo解析(1)
- Android 通知栏Notification的整合 全面学习 (一个DEMO让你完全了解它)
- Android录屏通过udp共享到其它手机
- Android 截屏方法
- Android实现录屏直播(三)MediaProjection + VirtualDisplay + librtmp + MediaCodec实现视频编码并推流到rtmp服务器
- Android Service(服务)绑定远程服务一个小demo
- android开源项目之OTTO事件总线(二)官方demo解说
- Android 的第三方报表组件,AChartEngine 案列demo