热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

android视频截屏&手机录屏实现代码

本文介绍了android视频截屏&手机录屏实现代码,分享给大家,希望对大家有帮助 问题 在android中有时候我们需要对屏幕进行截

本文介绍了android视频截屏&手机录屏实现代码,分享给大家,希望对大家有帮助

问题

在android中有时候我们需要对屏幕进行截屏操作,单一的截屏操作好解决可以通过activity的顶层view DecorView获取一个bitmap,得到就是当前activity上面的全部视图。

 View view = activity.getWindow().getDecorView();
    view.setDrawingCacheEnabled(true);
    view.buildDrawingCache();
    Bitmap bmp = view.getDrawingCache();
    DisplayMetrics dm = new DisplayMetrics();
    activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
    Bitmap ret = Bitmap.createBitmap(bmp, 0, 0, dm.widthPixels, dm.heightPixels);
    view.destroyDrawingCache();

如果activity中包含一些视频播放器比如SurfaceView GLSurfaceView TextureView,在调用截屏代码会发现播放视频的部分是黑屏的,原因是这几种视频渲染的view通过以上代码拿到的是缓冲区不是真正的图像。

解决办法

android5.0以上系统提供了一个 MediaProjectionManager类来对手机进行录屏操作,也支持获取手机的Image图像的操作,知道了这些我们就可以通过提供的api来进行截屏操作了。

这里通过Service来操作截屏和录屏的api

1.绑定截屏的Service

 Intent intent = new Intent(this, ScreenService.class);
 bindService(intent, mServiceConnection, BIND_AUTO_CREATE);

 public void onServiceConnected(ComponentName className, IBinder service) {
       DisplayMetrics metrics = new DisplayMetrics();
       getWindowManager().getDefaultDisplay().getMetrics(metrics);
       ScreenService.RecordBinder binder = (ScreenService.RecordBinder) service;
       recordService = binder.getRecordService();
       recordService.setConfig(metrics.widthPixels, metrics.heightPixels, metrics.densityDpi);
       mButton.setEnabled(true);
       mButton.setText(recordService.isRunning() ? "结束" : "开始");
 }

2.请求权限 onActivityResult 方法中回调。

 Intent captureIntent = projectionManager.createScreenCaptureIntent();
 startActivityForResult(captureIntent, RECORD_REQUEST_CODE);

成功后

 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
     if (requestCode == RECORD_REQUEST_CODE && resultCode == RESULT_OK) {

       //######## 截屏逻辑 ########
       mediaProjection = projectionManager.getMediaProjection(resultCode, data);
       recordService.setMediaProject(mediaProjection);
       recordService.initImageReader();

     }
 }

3. 获取截屏

 @Override
 public void onClick(View view) {

  //######## 截屏逻辑 ########
   Bitmap bitmap = recordService.getBitmap();
   mImageView.setImageBitmap(bitmap);
 }

录屏

录屏需要初始化一些录屏参数,输入麦克风类型视频类型,保存路径等

 private void initRecorder() {
     mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
     mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
     mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
     mediaRecorder.setOutputFile(
         getSavePath() + System.currentTimeMillis() + ".mp4");
     mediaRecorder.setVideoSize(width, height);
     mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
     mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
     mediaRecorder.setVideoEncodingBitRate(5 * 1024 * 1024);
     mediaRecorder.setVideoFrameRate(30);
     try {
       mediaRecorder.prepare();
     } catch (IOException e) {
       e.printStackTrace();
     }
 }

开始录屏

mediaRecorder.start();

保存路径

完整Service代码

public class ScreenService extends Service {
private MediaRecorder mediaRecorder;
private VirtualDisplay virtualDisplay;
private boolean running;
private int width = 720;
private int height = 1080;
private int dpi;
private ImageReader mImageReader;
private MediaProjection mediaProjection;

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


 @Override
 public void onCreate() {
   super.onCreate();
   running = false;
   mediaRecorder = new MediaRecorder();
 }


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


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


 /**
 * 开始录屏
 *
 * @return true
 */
 public boolean startRecord() {
   if (mediaProjection == null || running) {
     return false;
   }
   initRecorder();
   createVirtualDisplay();
   mediaRecorder.start();
   running = true;
   return true;
 }


 /**
 * 结束录屏
 *
 * @return true
 */
 public boolean stopRecord() {
   if (!running) {
     return false;
   }
   running = false;
   mediaRecorder.stop();
   mediaRecorder.reset();
   virtualDisplay.release();
   mediaProjection.stop();

   return true;
 }


 public void setMediaProjection(MediaProjection mediaProjection) {
   this.mediaProjection = mediaProjection;
 }


 /**
 * 初始化ImageRead参数
 */
 public void initImageReader() {
   if (mImageReader == null) {
     int maxImages = 2;
     mImageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, maxImages);
     createImageVirtualDisplay();
   }
 }


 /**
 * 创建一个录屏 Virtual
 */

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


 /**
 * 创建一个ImageReader Virtual
 */
 private void createImageVirtualDisplay() {
   virtualDisplay = mediaProjection
       .createVirtualDisplay("mediaprojection", width, height, dpi,
           DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mImageReader
           .getSurface(), null, null);
 }


 /**
 * 初始化保存屏幕录像的参数
 */
 private void initRecorder() {
   mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
   mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
   mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
   mediaRecorder.setOutputFile(
       getSavePath() + System.currentTimeMillis() + ".mp4");
   mediaRecorder.setVideoSize(width, height);
   mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
   mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
   mediaRecorder.setVideoEncodingBitRate(5 * 1024 * 1024);
   mediaRecorder.setVideoFrameRate(30);
   try {
     mediaRecorder.prepare();
   } catch (IOException e) {
     e.printStackTrace();
   }
 }


 /**
 * 获取一个保存屏幕录像的路径
 *
 * @return path
 */
 public String getSavePath() {
   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;
       }
     }
     return rootDir;
   } else {
     return null;
   }
 }


 /**
 * 请求完权限后马上获取有可能为null,可以通过判断is null来重复获取。
 */
 public Bitmap getBitmap() {
   Bitmap bitmap = cutoutFrame();
   if (bitmap == null) {
     getBitmap();
   }
   return bitmap;
 }


 /**
 * 通过底层来获取下一帧的图像
 *
 * @return bitmap
 */
 public Bitmap cutoutFrame() {
   Image image = mImageReader.acquireLatestImage();
   if (image == null) {
     return null;
   }
   int width = image.getWidth();
   int height = image.getHeight();
   final Image.Plane[] planes = image.getPlanes();
   final ByteBuffer buffer = planes[0].getBuffer();
   int pixelStride = planes[0].getPixelStride();
   int rowStride = planes[0].getRowStride();
   int rowPadding = rowStride - pixelStride * width;
   Bitmap bitmap = Bitmap.createBitmap(width +
       rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);
   bitmap.copyPixelsFromBuffer(buffer);
   return Bitmap.createBitmap(bitmap, 0, 0, width, height);
 }


 public class RecordBinder extends Binder {
   public ScreenService getRecordService() {
     return ScreenService.this;
   }
 }

demo下载

github

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 深入理解 Oracle 存储函数:计算员工年收入
    本文介绍如何使用 Oracle 存储函数查询特定员工的年收入。我们将详细解释存储函数的创建过程,并提供完整的代码示例。 ... [详细]
  • 本文总结了2018年的关键成就,包括职业变动、购车、考取驾照等重要事件,并分享了读书、工作、家庭和朋友方面的感悟。同时,展望2019年,制定了健康、软实力提升和技术学习的具体目标。 ... [详细]
  • CSS 布局:液态三栏混合宽度布局
    本文介绍了如何使用 CSS 实现液态的三栏布局,其中各栏具有不同的宽度设置。通过调整容器和内容区域的属性,可以实现灵活且响应式的网页设计。 ... [详细]
  • Linux 系统启动故障排除指南:MBR 和 GRUB 问题
    本文详细介绍了 Linux 系统启动过程中常见的 MBR 扇区和 GRUB 引导程序故障及其解决方案,涵盖从备份、模拟故障到恢复的具体步骤。 ... [详细]
  • 本文介绍了如何使用jQuery根据元素的类型(如复选框)和标签名(如段落)来获取DOM对象。这有助于更高效地操作网页中的特定元素。 ... [详细]
  • 本文将详细介绍如何使用剪映应用中的镜像功能,帮助用户轻松实现视频的镜像效果。通过简单的步骤,您可以快速掌握这一实用技巧。 ... [详细]
  • 本文介绍如何在 Xcode 中使用快捷键和菜单命令对多行代码进行缩进,包括右缩进和左缩进的具体操作方法。 ... [详细]
  • 在Linux系统中配置并启动ActiveMQ
    本文详细介绍了如何在Linux环境中安装和配置ActiveMQ,包括端口开放及防火墙设置。通过本文,您可以掌握完整的ActiveMQ部署流程,确保其在网络环境中正常运行。 ... [详细]
  • 本文介绍如何通过Windows批处理脚本定期检查并重启Java应用程序,确保其持续稳定运行。脚本每30分钟检查一次,并在需要时重启Java程序。同时,它会将任务结果发送到Redis。 ... [详细]
  • Android LED 数字字体的应用与实现
    本文介绍了一种适用于 Android 应用的 LED 数字字体(digital font),并详细描述了其在 UI 设计中的应用场景及其实现方法。这种字体常用于视频、广告倒计时等场景,能够增强视觉效果。 ... [详细]
  • 本章将深入探讨移动 UI 设计的核心原则,帮助开发者构建简洁、高效且用户友好的界面。通过学习设计规则和用户体验优化技巧,您将能够创建出既美观又实用的移动应用。 ... [详细]
  • 本文介绍如何通过SQL查询从JDE(JD Edwards)系统中提取所有字典数据,涵盖关键表的关联和字段选择。具体包括F0004和F0005系列表的数据提取方法。 ... [详细]
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
  • 本文详细介绍了如何通过命令行启动MySQL服务,包括打开命令提示符窗口、进入MySQL的bin目录、输入正确的连接命令以及注意事项。文中还提供了更多相关命令的资源链接。 ... [详细]
  • 扫描线三巨头 hdu1928hdu 1255  hdu 1542 [POJ 1151]
    学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ... [详细]
author-avatar
jrs2078148
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有