jjzjj

Android VirtualDisplay初识

RichardLM 2023-03-28 原文

VirtualDisplay

一、介绍

代表一个虚拟显示器。 虚拟显示器的内容被渲染到您必须提供给createVirtualDisplay()的Surface 。

二、使用

1、createVirtualDisplay

通常我们使用DisplayManager.createVirtualDisplay()来创建虚拟显示。

一下是创建虚拟显示的具体方法:

createVirtualDisplay(@NonNull String name,
            int width, int height, int densityDpi, @Nullable Surface surface, int flags);
createVirtualDisplay(@NonNull String name,
        int width, int height, int densityDpi, @Nullable Surface surface, int flags,
        @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler)

参数:

name – 虚拟显示器的名称,必须非空。
width – 虚拟显示的宽度(以像素为单位),必须大于 0。
height – 虚拟显示器的高度(以像素为单位),必须大于 0。
densityDpi – 以 dpi 为单位的虚拟显示密度,必须大于 0。
surface – 虚拟显示器的内容应该被渲染到的表面,如果最初没有,则为 null。
flags – 虚拟显示标志的组合: VIRTUAL_DISPLAY_FLAG_PUBLIC 、 VIRTUAL_DISPLAY_FLAG_PRESENTATION 、 VIRTUAL_DISPLAY_FLAG_SECURE 、 VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY或VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR 。
callback - 当VirtualDisplay的状态改变时调用的回调
handler – 应在其上调用侦听器的处理程序,如果应在调用线程的 Looper 上调用侦听器,则为 null。

虚拟显示的内容被渲染到应用程序提供的Surface 。虚拟显示的行为取决于提供给此方法的标志。 默认情况下,虚拟显示被创建为私有的、非展示的和不安全的。 使用某些标志可能需要权限。

2、分析参数flags

1.VIRTUAL_DISPLAY_FLAG_PUBLIC

虚拟显示标志:创建公共显示。公共虚拟显示器
设置此标志时,虚拟显示是公开的。公共虚拟显示器的行为与大多数连接到系统的其他显示器(例如外部或无线显示器)的行为类似。 应用程序可以在显示器上打开窗口,系统可以将其他显示器的内容镜像到它上面。

2.VIRTUAL_DISPLAY_FLAG_PRESENTATION

虚拟显示标志:创建演示显示。演示虚拟显示
当该标志被设置时,虚拟显示器被注册为presentation display category中的presentation display category 。 应用程序可以自动将其内容投影到演示显示以提供更丰富的第二屏幕体验。

3.VIRTUAL_DISPLAY_FLAG_SECURE

虚拟显示标志:创建安全显示。安全的虚拟显示器
设置此标志后,虚拟显示被视为安全。 来电者承诺采取合理措施,例如无线加密,以防止显示内容被截取或记录在持久性介质上。
另外:创建安全的虚拟显示器需要 CAPTURE_SECURE_VIDEO_OUTPUT 权限。 此权限保留供系统组件使用,不适用于第三方应用程序

4.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY

虚拟显示标志:只显示该显示器本身的内容; 不要镜像另一个显示器的内容。
此标志与VIRTUAL_DISPLAY_FLAG_PUBLIC结合使用。 通常,如果公共虚拟显示器没有自己的窗口,它们将自动镜像默认显示器的内容。 当这个标志被指定时,虚拟显示器将只显示它自己的内容,如果它没有窗口,它将被消隐。

5.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR

虚拟显示标志:当没有显示内容时,允许将内容镜像到私人显示器上。此标志仅用于在创建私有显示时覆盖默认行为。

另外:创建自动镜像虚拟显示器需要 CAPTURE_VIDEO_OUTPUT 或 CAPTURE_SECURE_VIDEO_OUTPUT 权限。 这些权限保留供系统组件使用,第三方应用程序无法使用。 或者,可以使用适当的MediaProjection来创建自动镜像虚拟显示。

3、MediaProjection

授予应用程序捕获屏幕内容和/或录制系统音频的能力的令牌。 授予的确切功能取决于 MediaProjection 的类型。
屏幕捕获会话可以通过MediaProjectionManager.createScreenCaptureIntent启动。 这允许捕获屏幕内容,但不能捕获系统音频。

示例:

MediaProjectionManager mProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
if (mProjectionManager != null) {
    startActivityForResult(mProjectionManager.createScreenCaptureIntent(), 1);   
        }

在onActivityResult回调中处理

@Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        String path=GetRealPath.getPath(this,uri);
        if(requestCode==1){
            if(resultCode==RESULT_OK){
                MediaProjection mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
                VirtualDisplay virtualDisplay =mMediaProjection.createVirtualDisplay("screen_shut", mWidth, mHeight, mDensity,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,mSurface,null,null);
            }
        }
    }

createVirtualDisplay参数:

name: 是生成的VirtualDisplay实例的名称;
width, height: 分别是生成实例的宽高;
dpi: 生成实例的像素密度,必须大于0,一般都取1;
surface: 这个比较重要,是你生成的VirtualDisplay的载体,我的理解是,VirtualDisplay的内容是一帧帧的屏幕截图(所以你看到是有宽高,像素密度等设置),所以MediaProjection获取到的其实是一帧帧的图,然后通过surface来顺序播放这些图片,形成视频。

MediaProjection最好在前台服务中创建并在清单文件中设置Service为foregroundServiceType="mediaProjection",以上仅仅为示例

三、使用ImageReader获取虚拟显示器中的图像

1、ImageReader

ImageReader 类允许应用程序直接访问渲染到Surface图像数据;图像数据封装在Image对象中,可以同时访问多个这样的对象,最多可达maxImages构造函数参数指定的数量。 通过其Surface发送到 ImageReader 的新图像将排队,直到通过acquireLatestImage或acquireNextImage调用访问。 由于内存限制,如果 ImageReader 没有以等于生产速率的速率获取和释放图像,则图像源最终将在尝试渲染到 Surface 时停止或丢弃图像。

2、实例化newInstance

静态方法直接调用

ImageReader.newInstance(
        @IntRange(from = 1) int width,
        @IntRange(from = 1) int height,
        @Format             int format,
        @IntRange(from = 1) int maxImages);

width – 此阅读器将生成的图像的默认宽度(以像素为单位)。
height – 此阅读器将生成的图像的默认高度(以像素为单位)。
格式 - 此阅读器将生成的图像格式。 这必须是ImageFormat或android.graphics.PixelFormat常量之一。 请注意,并非所有格式都受支持,例如 ImageFormat.NV21。
maxImages – 用户希望同时访问的最大图像数。 这应该尽可能小以限制内存使用。 一旦用户获得了 maxImages 图像,必须先释放其中一个图像,然后才能通过。

3、获取VirtualDisplay中的图像

创建virtualdisplay时传入imageReader.getSurface()

virtualDisplay=mDisplayManager.createVirtualDisplay("getImage", mWidth, mHeight, mDensity, mImageReader.getSurface(),
        DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION);

imageReader.getSurface():获取可用于为此ImageReader生成Images的Surface 。

注册一个侦听器,以便在 ImageReader 中有新图像可用时调用。

注意这里的新图像,也就是说如果你的虚拟显示中始终没有新的操作或者说界面没有变化,ImageReader是监听不到新的图像的,log可能不会打印,但不意味着虚拟显示中的图像消失了。

//一般而言,如果你的Handler是要来刷新操作UI的,那么就需要在主线程下跑。
Handler mHandler=new Handler(Looper.getMainLooper());
mImageReader.setOnImageAvailableListener(new ImageAvailableListener(),mHandler);
private class ImageAvailableListener implements ImageReader.OnImageAvailableListener {

        @Override
        public void onImageAvailable(ImageReader reader) {
                if (reader != mImageReader) {
                    return;
                }
                //SystemClock.sleep(2000);
                Image image = reader.acquireNextImage();
                if (image != 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.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);
                    bitmap.copyPixelsFromBuffer(buffer);
                    //保存图片到本地
                    ImageSaveUtil.saveBitmap2file(bitmap,activity,String.valueOf(System.currentTimeMillis()));
                    Log.d(TAG, "New image available from virtual display." + i);
                    image.close();
                    i++;
                }
            }
        }

有关Android VirtualDisplay初识的更多相关文章

  1. 玩以太坊链上项目的必备技能(初识智能合约语言-Solidity之旅一) - 2

    前面一篇关于智能合约翻译文讲到了,是一种计算机程序,既然是程序,那就可以使用程序语言去编写智能合约了。而若想玩区块链上的项目,大部分区块链项目都是开源的,能看得懂智能合约代码,或找出其中的漏洞,那么,学习Solidity这门高级的智能合约语言是有必要的,当然,这都得在公链``````以太坊上,毕竟国内的联盟链有些是不兼容Solidity。Solidity是一种面向对象的高级语言,用于实现智能合约。智能合约是管理以太坊状态下的账户行为的程序。Solidity是运行在以太坊(Ethereum)虚拟机(EVM)上,其语法受到了c++、python、javascript影响。Solidity是静态类型

  2. 【Linux】初识Linux --指令Ⅰ - 2

    Halo,这里是Ppeua。平时主要更新C语言,C++,数据结构算法,Linux…感兴趣就关注我吧!你定不会失望。目录1.ls显示当前目录下的文件内内容2.pwd-显示用户当前所在的目录3.cd-改变工作目录。将当前工作目录改变到指定的目录下1.cd-回到上一次待的工作空间2.cd..返回上一层目录1.相对路径:cd../aurora2.绝对路径:cd/home/aurora/lesson1/aurora3.cd~进入用户家目录4.cd/进入root目录4.mkdir-新建目录5.rmdir/rm-删除1.rmdir删除空文件夹2.rm删除1.rm-f2.rm-i3.rm-r1.ls显示当前目

  3. gtest初识 - googletest(一) - 2

    gtest是Google开发的一个开源单元测试框架,代码提供丰富的注释和实例,参考实际用例可以很快上手基本单元测试,丰富的代码注释能够让有兴趣的开发者深入了解gtest的代码结构并做部分针对性的二次开发。gtest主要针对c/c++提供了针对函数接口和类方法丰富测试方法,针对单元测试特有的数据或者代码反复编写的这种特性做了集成和优化,满足当前绝大部分对于单元测试的需求。其有如下特点:自动收集测试用例,无需开发者再次组织提供强大的断言集,支持包括布尔、整型、浮点型、字符串等。提供断言方法自定义扩展提供死亡测试功能使用参数化自动生成多个相似的测试用例可以将公共的用例初始化和清理工作放入测试夹具中,

  4. 鸿蒙HarmonyOS开发环境初识及搭建 - 2

    一鸿蒙简介HarmonyOS是一款面向万物互联时代的、全新的分布式操作系统。在传统的单设备系统能力基础上,HarmonyOS提出了基于同一套系统能力、适配多种终端形态的分布式理念,能够支持手机、平板、智能穿戴、智慧屏、车机等多种终端设备,提供全场景(移动办公、运动健康、社交通信、媒体娱乐等)业务能力。HarmonyOS提供了支持多种开发语言的API,供开发者进行应用开发。支持的开发语言包括Java、XML(ExtensibleMarkupLanguage)、C/C++、JS(JavaScript)、CSS(CascadingStyleSheets)和HML(HarmonyOSMarkupLan

  5. 初识测开/测试- 第一篇 - 测开/测试方向 - 2

    前言在进入软件测试的正式讲解之前,我们需要对这个行业有一个整体的了解。当我们从软件开发转向软件测试的时候,多数公司是欢迎的,而且难度也小。反之,当我们从软件测试转向软件开发的时候,难度将会变得很大。关于互联网的工作大概有以下三种:1、软件开发:进行软件系统的开发,功能实现的工作2、软件测试验证软件功能性的正确性。具体的验证方式分为以下几种:1、手工验证2、自动化验证3、软件测试与开发开发测试工具,开发测试脚本,其目的就是为了提高测试效率。看到开发这两个字,说明是会涉及到编程的。但是难度会比软件开发低一些,没有数据结构中的编程那么难。测试开发这里的编程,都是有着指定规则来编写代码。换句话来说,它

  6. BACnet协议详解——初识BACnet架构 - 2

    文章目录BACnet协议架构BACnet简化的架构简化的四层BACnet体系结构选取BACnet网络的拓扑结构安全最后声明BACnet协议架构国际标准化组织在制定计算机网络通讯协议标准时定义了一个模型,称为开放系统互联参考模型(OSI(ISO7498)。模型的目的是解决计算机与计算机之间普遍的通信问题。下图给出了这七层的体系架构图。对于这种发生在两个应用程序之间的通信,看起来两个程序似乎是通过各自的应用接口直接相连。而真正的通信只发生在物理层。实现OSI模型协议所需的费用较高,在绝大部分楼宇自动控制系统中,并不需要实现OSI模型的所有内容。如果只选择OSI模型中需要的层次,形成一个简化的模型,

  7. webpack--》webpack底层深入讲解,从初识到精通,真正实现从0到1的过程 - 2

    目录webpackwebpack的基本使用安装配置修改自定义打包的入口与出口优化js或图片的存放路径配置webpack中@符号的使用webpack中相关插件安装webpack-dev-serverhtml-webpack-pluginclean-webpack-pluginwebpack中的loader打包处理css文件打包处理less文件打包处理样式表中与url路径相关的文件打包处理js文件中的高级语法webpack的打包与发布配置build命令SourceMapwebpackwebpack是前端项目工程化的具体解决方案。其主要功能为:它提供了友好的前端模块化开发支持,以及代码压缩混淆,处理

  8. 【微信小程序】初识微信小程序 - 2

    作者简介:一名C站萌新,前来进行小程序的前进之路博主主页:大熊李子的主页🐻1.1什么是微信小程序微信小程序是一种可以通过扫码或搜索即可进入使用的应用,减少了下载安装的环节,实现用户对于应用“触手可及、用完即走”的理想需求。在微信公众平台,小程序是与服务号、订阅号、企业微信并行的体系点开微信“发现-小程序”栏,你就能看到近期使用过的小程序;或者下拉微信聊天页面,你也能看到自己用过的小程序。如果你没有用过任何小程序,那么可以扫码进入小程序页面,或者点击好友分享的小程序卡片进入小程序。1.2小程序与普通网页开发的区别1.运行环境不同网页运行在浏览器环境中小程序运行在微信环境中2.API不同由于运行环

  9. 头歌MySQL数据库 - 初识MySQL 答案 - 2

    第1关:创建数据库在右侧命令行中连接MySQL,并创建一个名为MyDb的数据库。连接数据库的用户名为:root,密码为:123123。mysql-uroot-p123123-h127.0.0.1createdatabaseMyDb第2关:创建表在右侧命令行中操作,创建数据库TestDb,在TestDb下创建表t_emp,表结构如下:字段名称数据类型备注idINT员工编号nameVARCHAR(32)员工名称deptIdINT所在部门标号salaryFLOAT工资mysql-uroot-p123123-h127.0.0.1useTestDbcreatetablet_emp(  idint,  n

  10. 初识MINIO及springboot整合minio - 2

    一、minio简介minio是一款高性能、分布式的对象存储系统。minio一开始就是针对性能要求更高的私有云标准进行软件架构设计的,所以它采用了更易用的方式进行设计,它实现对象存储所需要的全部功能,在性能上也更加强劲,更易用、高效。二、特性1.高性能MinIO是全球领先的对象存储先锋,目前在全世界有数百万的用户.在标准硬件上,读/写速度上高达183GB/秒和171GB/秒。对象存储可以充当主存储层,以处理Spark、Presto、TensorFlow、H2O.ai等各种复杂工作负载以及成为HadoopHDFS的替代品。MinIO用作云原生应用程序的主要存储,与传统对象存储相比,云原生应用程序需

随机推荐