minicap

minicap 是开源项目 STF 中的高速截图工具。STF 利用此工具不断的传输图片信息并在 web 端绘制实现 Real-time screen view。

minicap 使用

  1. 将 minicap 所需的文件 "minicap" 和 "minicap.so" push 至手机中
  2. 启动 minicap,映射一个端口用来获取 minicap 数据
  3. 获取 minicap 的数据并进行解析处理

一、push 文件至手机中

minicap 的使用有很强的针对性,针对不同架构的 CPU 和 SDK 制作了不同的 "minicap" 和 "minicap.so" 文件。

获取 CPU 版本

$ABI=adb shell getprop ro.product.cpu.abi

获取 SDK 版本

$SDK=adb shell getprop ro.build.version.sdk

push 文件(红色字体为 minicap 项目路径,具体依个人情况而定)

adb push libs/$ABI/minicap /data/local/tmp/

adb push jni/minicap-shared/aosp/libs/android-$SDK/$ABI/minicap.so /data/local/tmp/

二、启动 minicap

检查 minicap 是否可用

adb shell LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp/minicap -P 1080x1920@1080x1920/0 -t

若在结果中包含 "OK" 字样则表示可用

-P 后面的参数格式:{RealWidth}x{RealHeight}@{VirtualWidth}x{VirtualHeight}/{Orientation}

Orientation 可以理解为手机的旋转角度,可选参数为 0 | 90 | 180 | 270

如何获取 Orientation

  1. 利用命令 adb shell dumpsys display(win 下 grep 更换为 findstr)获取分辨率 和 rotation 方向(adb 一般获取到为 0 or 1)(同学们自己动手做一次文件差异对比就知道用什么参数了)
  2. 官方提供的方法 (传送门) 首先编译出 app(不管 win 还是 linux 不要忘记参数'assembleDebug'),安装后就可以启动一个 service,该 services 可以返回手机当前的方向。该 app 已集成在STFService.apk 中,使用请参考文档

启动 adb shell LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp/minicap -P 1080x1920@1080x1920/0

此时相当于启动了一个 socket 服务端。然后设置下访问端口adb forward tcp:1313 localabstract:minicap(其意思是将 pc 上的端口 1313 重定向至手机上的 minicap)然后就可以通过 1313 端口来获取 minicap 不断发出来的信息了。

三、minicap 数据解析

minicap 会不断的返回很多二进制信息,这些二进制信息代表什么意思?

其返回的信息可以分为两类Global header binary formatFrame binary format(以下简称为 Banner 和 Frame), 其数据格式如下:

每次客户端连接 minicap 服务时,最先收到的24字节为 Banner 数据段(该数据段只会在最开始发送一次)。
然后接收到的数据可视为 N个Frame 数据段,Frame数据的前4个字节为 Frame 中 JPG 数据的长度,其后为JPG内容数据。

官方示例

(注:官方示例的数据处理方法是建立在收到的二进制数据以 16 进制形式表现的情况下)

根据使用者解析语言不同还需要注意大小端存储的问题

数据解析思路:

tempdata //保存还没有被处理的数据
framehead //保存fram的前4个字节
framejpg  //保存frame中jpg数据
jpglength //JPG数据长度

for {
  minicapread(data)
}

function minicapread(data) {
  data = append(tempdata,data)

  // ------------Banner start------------
  if banner not ok{
    if data length >= 24{
      getBanner(data)
      data = data - Banner // 减去banner长度余下的数据
    }else{
      tempdata = data
      return
    }
  }
  // ------------Banner end------------
  
  // ------------JPG length start------------
  if framhead length < 4{
    if data length >= (framehead length - 4) {
      framehead = getHead(data)
      jpglength = getJpgLength(framhead) 
      data = data - framehead
    }else{
      framehead = append(framehead,data)
      return
    }
  }
  // ------------JPG length end------------

  // ------------JPG start------------
  if framejpg length < jpglength{
    if data length >= (jpglength - framejpg length){
      framjpg = getJpg(data)
      data = data - framejpg
    }else{
      framejpg = append(framejpg,data)
      return
    }
  }
  // ------------JPG end------------
  
  tempdata = append(tempdata,data)
}

minicap 获取数据与 Orientation 的联系

假设分辨率为 1080x1920, 以 左上角为 0,0 坐标

当屏幕为竖屏显示时以 Orientation=0 启动 minicap 服务,此时我们会得到正常的宽高为 1080x1920 的截图。

若翻转手机为横屏显示数据时,依然得到宽高为 1080x1920 的截图且高度在 1080 以上时的部分为黑色填充。只有关闭 minicap 以 Orientation=90 重新启动,可以获取到宽高为 1920x1080 的正常截图。

也就是说想要实时正确获取屏幕显示,要监控屏幕方向,并以新的方向重启 minicap 服务。(可查看 STF 的输出日志)


↙↙↙阅读原文可查看相关链接,并与作者交流