使用 python 实现高帧率、低延时、支持多个 iOS 设备同时屏幕共享的工具

原文由YueChen发表于TesterHome社区网站,点击原文链接可与YueChen交流。

前段时间发布了一个 python 获取 iOS 性能数据的文章,也算开了个小口子能在获取 iOS 测试数据上更加方便了些,如果对 iOS 性能相关兴趣可以移步:https://www.jianshu.com/p/4edf1a0cae42

屏幕共享和远控平台现在发展也比较火热,但是 iOS 设备在画面同步和视频录制上,一直都没有一个比较不错的方案,也简单调研了下之前可以获取到 iOS 屏幕数据的方法:

  • iOS-minicap stf 团队实现的帧率非常不错,缺点无法多台设备
  • Airplay mirror 苹果多媒体多屏互动技术,效果都很好,有一点点缺陷就是同一个 wifi 下每次需要手机主动触发屏幕镜像才可以同步画面
  • com.apple.mobile.screenshotr 协议,这个也挺慢的
  • XCTest 和 XCUITest 二次改造的 wda 可以支持多台设备,但是帧率延时还是偏低
  • 基于 WebRtc iOS屏幕共享,这个需要 SDK 嵌入 APP 支持,而且需要端上主动触发,操作起来不是很方便。
  • 等等...

本项目介绍

该项目是 python 实现可以通过 USB 连接 iOS 设备进行屏幕共享,支持:

  • 高帧率(30〜60fps)
  • 高画质
  • 低延迟
  • 秒启动
  • 非侵入性(无需任何安装和代码嵌入)
  • 支持 iOS 多设备并行

项目地址:https://github.com/YueChen-C/ios-screen-record 先点个小星星吧

Mac OSX 安装

  1. brew install libusb pkg-config
  2. 如需使用 gstreamer 媒体服务则需要安装 brew install gstreamer gst-plugins-bad gst-plugins-good gst-plugins-base gst-plugins-ugly
  3. python install -r requirements.txt

使用

usb 连接你的 iOS 手机,解锁并信任喲(手机锁屏不行)

# 可以使用 vlc 工具播放udp地址: udp/h264://@:8880
# 直接转发 h264 到 udp 广播,因为 mac 限制 udp 大小,要切割包,所以延时会变高,暂时仅作为测试使用
$ main.py --udid=xxxx udp

# 录制 h264/wav 文件, 使用 vlc 工具打开文件
$ main.py --udid=xxxx record -h264File=/home/out.h264  -wavFile=/home/out.wav

# gstreamer 媒体流工具渲染显示画面,推荐方式
$ main.py --udid=xxxx gstreamer

基本原理

usb 相关说明

每个 usb 连接设备时都会有一些配置信息,我们数据交互时,会使用某个配置与 usb 设备进行交互,这里用个 iOS 设备举例:

当我们使用 LibUsb 这个库 https://libusb.info/ 获取 iOS USB 设备信息时可以获取到配置信息 bNumConfigurations 5 个, 下面部分信息片段:

DEVICE ID 05ac:12a8 on Bus 020 Address 031 =================
 bLength                :   0x12 (18 bytes)
 bDescriptorType        :    0x1 Device
 bcdUSB                 :  0x200 USB 2.0
 bDeviceClass           :    0x0 Specified at interface
 bDeviceSubClass        :    0x0
 bDeviceProtocol        :    0x0
 bMaxPacketSize0        :   0x40 (64 bytes)
 idVendor               : 0x05ac
 idProduct              : 0x12a8
 bcdDevice              : 0x1208 Device 18.08
 iManufacturer          :    0x1 Apple Inc.
 iProduct               :    0x2 iPhone
 iSerialNumber          :    0x3 *********************
 bNumConfigurations     :    0x5
 CONFIGURATION 1: 500 mA ==================================

如何开启隐藏配置

事实上在 iOS USB 级别上还有个隐藏配置信息,用来传输屏幕音视频相关数据,pyhton 开启方式 device.ctrl_transfer(0x40, 0x52, 0, 2, b'') 发送了这个指令之后,再次获取配置信息时,就会发现 bNumConfigurations 的数量变成了6个,多出来这个配置信息就是我们要使用的,使用这个 USB 配置,并连接相应端口后,就能传输音视频画面了

接口端点定位

虽然我们使用这个音视频传输配置,但是这个配置下面还有多个 INTERFACE 接口,但是只有 bInterfaceSubClass=0x2A 这个接口才是需要用的,因此要还需要定位到这个配置下,然后会看到 INTERFACE 下面还有两个端口 ENDPOINT 0x86: Bulk IN(用来接收数据)和 ENDPOINT 0x5: Bulk OUT(用来发送数据),到此 usb 设置相关基本完成了

 INTERFACE 2: Vendor Specific ===========================
     bLength            :    0x9 (9 bytes)
     bDescriptorType    :    0x4 Interface
     bInterfaceNumber   :    0x2
     bAlternateSetting  :    0x0
     bNumEndpoints      :    0x2
     bInterfaceClass    :   0xff Vendor Specific
     bInterfaceSubClass :   0x2a
     bInterfaceProtocol :   0xff
     iInterface         :   0x11 Valeria
      ENDPOINT 0x86: Bulk IN ===============================
       bLength          :    0x7 (7 bytes)
       bDescriptorType  :    0x5 Endpoint
       bEndpointAddress :   0x86 IN
       bmAttributes     :    0x2 Bulk
       wMaxPacketSize   :  0x200 (512 bytes)
       bInterval        :    0x0
      ENDPOINT 0x5: Bulk OUT ===============================
       bLength          :    0x7 (7 bytes)
       bDescriptorType  :    0x5 Endpoint
       bEndpointAddress :    0x5 OUT
       bmAttributes     :    0x2 Bulk
       wMaxPacketSize   :  0x200 (512 bytes)
       bInterval        :    0x0

如果想分析 usb 数据的话执行:sudo ifconfig XHC20 up 命令后使用 wiershark 抓网卡 XHC20 就可以看到 部分 usb 数据交互

开始传输数据

大概流程

  1. 启用隐藏设备配置信息
  2. 锁定开启传输端点
  3. 等待接收PING包
  4. 用PING包响应
  5. 等待SYNC CWPA数据包接收设备音频 时间戳 >>>开始音频交互
  6. 创建本地时间戳记录,将该时间戳放入SYNC CWPA并发送
  7. 发送ASYN_HPD1(参数参考 ios 的 CoreAudio 框架)
  8. 发送ASYN_HPA1(参数参考 ios 的 CoreAudio 框架)和在步骤 6 中接收到的设备音频 时间戳
  9. 接收同步AFMT并返回没有错误信号(表示准备就绪)
  10. 接收CVRP视频 时间戳 >>>开始视频交互
  11. 使用本地视频 时间戳 回复
  12. 使用步骤 10 的时间戳 发送 NEED 消息
  13. 接收两个 ASYN
  14. 接收 CLOK 消息,创建新的时间戳记录并回复消息
  15. 接收 TIME 消息,使用 14 步创建的时间回复消息

前面交互完成后就能正式接收音视频消息了

如果想具体了解相关传输报文协议可以查看下方链接,本项目是参考这个大佬文章,最终使用 python 来实现的 https://github.com/danielpaulus/quicktime_video_hack/blob/master/doc/technical_documentation.md

原文由YueChen发表于TesterHome社区网站,点击原文链接可与YueChen交流。

image

今日份的知识已摄入~

想了解更多前沿测试开发技术,结识行业大牛:
欢迎关注「第十届MTSC大会·上海」>>>
1个主会场+12大专场,大咖云集精英齐聚
12个专场包括:
知乎、物流、开源、游戏、酷家乐、音视频、客户端
服务端、数字经济、效能提升、质量保障、智能化测试

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容