当前位置: 首页 > article >正文

Android Graphics 显示系统 - VirtualDisplay的初印象 - 简单示例

开始准备这篇文章时巴黎奥运会赛场上激战正酣,写完时奥运已落下帷幕,期间也看了许多精彩的赛事直播,拼搏与汗水书写的传奇无不激励着平凡岗位上的我们。每一枚奖牌的背后,都凝聚着运动员数不尽的汗水付出与坚持不懈,学习Android Graphics显示系统的知识,也需要我们长久的坚持、不断地探索实践。一点一滴地积累,一万小时天才定律,相信你终将赢得属于自己的金牌。

前言

在许多场景中都会用到Android 虚拟屏幕VirtualDisplay,比如常见的屏幕录制、WifiDisplay(Miracast)。当然,本系列的目的还是希望给大家讲解底层Graphics系统中虚拟屏幕的一些儿运作逻辑,至于上层框架的WindowManagerService/DisplayManagerService等无非就是在框架层增加了更丰富的控制接口逻辑,但其本质还是在SurfaceFlinger、HWC等较低层面完成虚拟屏幕的核心功能。

还是老样子,抛开WMS等复杂逻辑,我们从简单的demo开始,来了解VirtualDisplay的使用及运作逻辑。

Android VirtualDisplay示例

基于Android 14平台开发了一个极简的创建虚拟屏幕的示例,代码至文末下载获取

使用方法

  • 下载代码放到android源码目录下;

  • 执行mm编译获得可执行档 VirtualDisplayDemo;

  • push到测试环境中;

    adb push VirtualDisplayDemo /system/bin/

  • 运行程序;

    adb shell VirtualDisplayDemo 
    

效果展示

dumpsys SurfaceFlinger看看虚拟屏幕的信息

Display 11529215050109536902 (virtual, "Super-VirtualDisplay")
   Composition Display State:
   isEnabled=true isSecure=false usesDeviceComposition=false 
   usesClientComposition=true flipClientTarget=false reusedClientComposition=false 
   layerFilter={layerStack=99 toInternalDisplay=false }
   transform (ROT_0) (SCALE )
    0.5000  0.0000  0.0000
    0.0000  0.5000  0.0000
    0.0000  0.0000  1.0000
   layerStackSpace=ProjectionSpace{bounds=Rect(0, 0, 1920, 1080), content=Rect(0, 0, 1920, 1080), orientation=ROTATION_0} 
   framebufferSpace=ProjectionSpace{bounds=Rect(0, 0, 960, 540), content=Rect(0, 0, 960, 540), orientation=ROTATION_0} 
   orientedDisplaySpace=ProjectionSpace{bounds=Rect(0, 0, 960, 540), content=Rect(0, 0, 960, 540), orientation=ROTATION_0} 
   displaySpace=ProjectionSpace{bounds=Rect(0, 0, 960, 540), content=Rect(0, 0, 960, 540), orientation=ROTATION_0} 
   needsFiltering=true 
   colorMode=NATIVE (0) renderIntent=COLORIMETRIC (0) dataspace=UNKNOWN (0) targetDataspace=UNKNOWN (0) 
   colorTransformMatrix=[[1.000,0.000,0.000,0.000][0.000,1.000,0.000,0.000][0.000,0.000,1.000,0.000][0.000,0.000,0.000,1.000]] 
   displayBrightnessNits=-1.000000 sdrWhitePointNits=-1.000000 clientTargetBrightness=1.000000 displayBrightness=nullopt 
   compositionStrategyPredictionState=DISABLED 

   treat170mAsSrgb=false 


   Composition Display Color State:
   HWC Support: wideColorGamut=false hdr10plus=false hdr10=false hlg=false dv=false metadata=0 

   Composition RenderSurface State:
   size=[960 540] ANativeWindow=0x71ab9e8b4010 (format 1) 

   0 Layers

可以看到几个主要信息:

  • 虚拟屏幕的名字是我们设置的:Super-VirtualDisplay;

  • 虚拟屏幕的 layerStack是我们设置的:99;

  • layerStackSpace/framebufferSpace/orientedDisplaySpace/displaySpace 也是我们配置的;

  • 此时还没有任何图层显示到这个虚拟屏幕上 0 Layers;

虚拟屏幕显示画面

现在,我们往这块虚拟屏幕上显示点内容,看看效果

使用我们前面提供的demo: MultiDisplayDemoPro

Android Graphics 多屏同显/异显 - C++示例程序(升级版)

执行命令,-d 99 指定显示到虚拟屏幕

adb shell MultiDisplayDemoPro -f /sdcard/720P25FPS.mp4 -d 99

图片

此时,再去观察dumpsys SurfaceFlinger的信息,虚拟屏幕下就有一个layer了

Display 11529215050109536902 (virtual, "Super-VirtualDisplay")
   Composition Display State:
   isEnabled=true isSecure=false usesDeviceComposition=false 

   。。。。。

   1 Layers
  - Output Layer 0x71ac6e779b10(MultiDisplayDemo#94)

虚拟屏幕没有物理实体,但仍需要一个承载合成后数据的“载体”,我们demo中就是在主屏幕上创建了一个 Surface 来接收虚拟屏幕的数据,这样便于我们观察。

显示在左上角 pos=(100, 100) 的位置

+ Layer (VirtualDisplay-Surface#90) uid=0
  Region TransparentRegion (this=0 count=0)
  Region VisibleRegion (this=0 count=0)
  Region SurfaceDamageRegion (this=0 count=0)
      layerStack=   0, z=2147483647, pos=(100,100), size=(   0,   0), crop=[  0,   0,  -1,  -1], cornerRadius=0.000000, isProtected=0, isTrustedOverlay=0, isOpaque=0, invalidate=1, dataspace=BT709 sRGB Full range, defaultPixelFormat=Unknown/None, backgroundBlurRadius=0, color=(-1.000,-1.000,-1.000,1.000), flags=0x00000000, tr=[0.00, 0.00][0.00, 0.00]
      parent=none
      zOrderRelativeOf=none
      activeBuffer=[   0x   0:   0,Unknown/None], tr=[0.00, 0.00][0.00, 0.00] queued-frames=0 metadata={9:4bytes}, cornerRadiusCrop=[0.00, 0.00, 0.00, 0.00],  shadowRadius=0.000, 
+ Layer (bbq-wrapper#91) uid=0
  Region TransparentRegion (this=0 count=0)
  Region VisibleRegion (this=0 count=1)
    [100, 100, 1060, 640]
  Region SurfaceDamageRegion (this=0 count=0)
      layerStack=   0, z=        0, pos=(100,100), size=(   0,   0), crop=[  0,   0,  -1,  -1], cornerRadius=0.000000, isProtected=0, isTrustedOverlay=0, isOpaque=0, invalidate=0, dataspace=BT709 sRGB Full range, defaultPixelFormat=RGBA_8888, backgroundBlurRadius=0, color=(-1.000,-1.000,-1.000,1.000), flags=0x00000100, tr=[0.00, 0.00][0.00, 0.00]
      parent=VirtualDisplay-Surface#90
      zOrderRelativeOf=none
      activeBuffer=[ 960x 540:2816,RGBA_8888], tr=[0.00, 0.00][0.00, 0.00] queued-frames=0 metadata={dequeueTime:1902680300269, 9:4bytes}, cornerRadiusCrop=[0.00, 0.00, 0.00, 0.00],  shadowRadius=0.000, 

当然也可以选择其它“载体”,比如

  • 把虚拟屏幕合成后的数据放入编码器encoder再写入MP4文件,那就是screenrecord 的功能了;

  • 把虚拟屏幕合成后的数据放入编码器encoder再打包按照网络协议(RTSP...)发送出去,那就是 WifiDisplay(Miracast)的功能了;

阅读原文,下载源码

Android Graphics 显示系统 - VirtualDisplay的初印象 - 简单示例


http://www.kler.cn/a/302148.html

相关文章:

  • 【C++】设计模式
  • Flutter组件————FloatingActionButton
  • 数字工厂管理系统就是ERP系统吗
  • 在跨平台开发环境中构建高效的C++项目:从基础到最佳实践20241225
  • Spring Boot 项目创建
  • 贪心算法(三)
  • .Net 中各种线程同步锁
  • Gitea Action 简单配置(CI/CD)
  • java 学习从零到精通之历程
  • C4D2025来了!亮眼的新功能一览
  • 高亚科技与广东海悟携手,打造全流程电子竞标管理平台!
  • 《程序猿之设计模式实战 · 策略模式》
  • 深度解读MySQL意向锁的工作原理机制与应用场景
  • 使用Selenium与WebDriver实现跨浏览器自动化数据抓取
  • 信息安全工程师(1)计算机网络分类
  • Linux Makefile文本处理函数知识详解
  • 【Http 每天一小问 ,Post上传文件时, 文件和 -d(--data)和 -F(--form) 不能同时存在 ,怎么办】
  • Linux系统安装CUDA
  • JSON对象
  • JSDelivr NPM CDN 国内加速节点
  • java设计模式(持续更新中)
  • 英伟达与甲骨文携手加速企业级AI和数据处理
  • 搭建一个本地 SMTP 服务器
  • [苍穹外卖]-05Redis快速入门
  • 【算法】冒泡排序
  • CSP-J 算法基础 二分查找与二分答案