diff --git a/bin/DroidCast/DroidCast_raw-release-1.0.apk b/bin/DroidCast/DroidCast_raw-release-1.0.apk index 3ef96d0a46..66b0bd8001 100644 Binary files a/bin/DroidCast/DroidCast_raw-release-1.0.apk and b/bin/DroidCast/DroidCast_raw-release-1.0.apk differ diff --git a/module/config/argument/args.json b/module/config/argument/args.json index 28e324f7c7..6abfd26881 100644 --- a/module/config/argument/args.json +++ b/module/config/argument/args.json @@ -120,6 +120,7 @@ "aScreenCap_nc", "DroidCast", "DroidCast_raw", + "DroidCast_lz4", "nemu_ipc", "ldopengl" ] diff --git a/module/config/argument/argument.yaml b/module/config/argument/argument.yaml index 5f2b9af961..edacc5efcc 100644 --- a/module/config/argument/argument.yaml +++ b/module/config/argument/argument.yaml @@ -41,6 +41,7 @@ Emulator: aScreenCap_nc, DroidCast, DroidCast_raw, + DroidCast_lz4, nemu_ipc, ldopengl, ] diff --git a/module/config/config_generated.py b/module/config/config_generated.py index d60ccb3954..462b308c92 100644 --- a/module/config/config_generated.py +++ b/module/config/config_generated.py @@ -21,7 +21,7 @@ class GeneratedConfig: Emulator_Serial = 'auto' Emulator_PackageName = 'auto' # auto, com.bilibili.azurlane, com.YoStarEN.AzurLane, com.YoStarJP.AzurLane, com.hkmanjuu.azurlane.gp, com.bilibili.blhx.huawei, com.bilibili.blhx.mi, com.tencent.tmgp.bilibili.blhx, com.bilibili.blhx.baidu, com.bilibili.blhx.qihoo, com.bilibili.blhx.nearme.gamecenter, com.bilibili.blhx.vivo, com.bilibili.blhx.mz, com.bilibili.blhx.dl, com.bilibili.blhx.lenovo, com.bilibili.blhx.uc, com.bilibili.blhx.mzw, com.yiwu.blhx.yx15, com.bilibili.blhx.m4399, com.bilibili.blhx.bilibiliMove, com.hkmanjuu.azurlane.gp.mc Emulator_ServerName = 'disabled' # disabled, cn_android-0, cn_android-1, cn_android-2, cn_android-3, cn_android-4, cn_android-5, cn_android-6, cn_android-7, cn_android-8, cn_android-9, cn_android-10, cn_android-11, cn_android-12, cn_android-13, cn_android-14, cn_android-15, cn_android-16, cn_android-17, cn_android-18, cn_android-19, cn_android-20, cn_android-21, cn_android-22, cn_android-23, cn_android-24, cn_android-25, cn_android-26, cn_android-27, cn_ios-0, cn_ios-1, cn_ios-2, cn_ios-3, cn_ios-4, cn_ios-5, cn_ios-6, cn_ios-7, cn_ios-8, cn_ios-9, cn_ios-10, cn_channel-0, cn_channel-1, cn_channel-2, cn_channel-3, cn_channel-4, en-0, en-1, en-2, en-3, en-4, en-5, jp-0, jp-1, jp-2, jp-3, jp-4, jp-5, jp-6, jp-7, jp-8, jp-9, jp-10, jp-11, jp-12, jp-13, jp-14, jp-15, jp-16, jp-17 - Emulator_ScreenshotMethod = 'auto' # auto, ADB, ADB_nc, uiautomator2, aScreenCap, aScreenCap_nc, DroidCast, DroidCast_raw, nemu_ipc, ldopengl + Emulator_ScreenshotMethod = 'auto' # auto, ADB, ADB_nc, uiautomator2, aScreenCap, aScreenCap_nc, DroidCast, DroidCast_raw, DroidCast_lz4, nemu_ipc, ldopengl Emulator_ControlMethod = 'MaaTouch' # ADB, uiautomator2, minitouch, Hermit, MaaTouch Emulator_ScreenshotDedithering = False Emulator_AdbRestart = False diff --git a/module/config/config_manual.py b/module/config/config_manual.py index b5bd318688..7098acfb40 100644 --- a/module/config/config_manual.py +++ b/module/config/config_manual.py @@ -78,7 +78,7 @@ def SERVER(self): ASCREENCAP_FILEPATH_LOCAL = './bin/ascreencap' ASCREENCAP_FILEPATH_REMOTE = '/data/local/tmp/ascreencap' - # 'DroidCast', 'DroidCast_raw' + # 'DroidCast', 'DroidCast_raw', 'DroidCast_lz4' DROIDCAST_VERSION = 'DroidCast' DROIDCAST_FILEPATH_LOCAL = './bin/DroidCast/DroidCast_raw-release-1.0.apk' DROIDCAST_FILEPATH_REMOTE = '/data/local/tmp/DroidCast_raw.apk' diff --git a/module/config/i18n/en-US.json b/module/config/i18n/en-US.json index 30110b4736..a02d11609c 100644 --- a/module/config/i18n/en-US.json +++ b/module/config/i18n/en-US.json @@ -416,7 +416,7 @@ }, "ScreenshotMethod": { "name": "Screenshot Method", - "help": "When using auto-select, a benchmark will be performed and automatically changed to the fastest screenshot method.\nGeneral speed: DroidCast_raw >> aScreenCap_nc > ADB_nc >>> aScreenCap > uiautomator2 ~= ADB.\nRun Tools - Performance Test to find the fastest method.", + "help": "When using auto-select, a benchmark will be performed and automatically changed to the fastest screenshot method.\nGeneral speed: DroidCast_lz4 > DroidCast_raw >> aScreenCap_nc > ADB_nc >>> aScreenCap > uiautomator2 ~= ADB.\nRun Tools - Performance Test to find the fastest method.", "auto": "Auto-select the fastest", "ADB": "ADB ", "ADB_nc": "ADB_nc", @@ -425,6 +425,7 @@ "aScreenCap_nc": "aScreenCap_nc", "DroidCast": "DroidCast", "DroidCast_raw": "DroidCast_raw", + "DroidCast_lz4": "DroidCast_lz4", "nemu_ipc": "nemu_ipc", "ldopengl": "ldopengl" }, diff --git a/module/config/i18n/ja-JP.json b/module/config/i18n/ja-JP.json index 2bf715bed6..2b98b631dc 100644 --- a/module/config/i18n/ja-JP.json +++ b/module/config/i18n/ja-JP.json @@ -425,6 +425,7 @@ "aScreenCap_nc": "aScreenCap_nc", "DroidCast": "DroidCast", "DroidCast_raw": "DroidCast_raw", + "DroidCast_lz4": "DroidCast_lz4", "nemu_ipc": "nemu_ipc", "ldopengl": "ldopengl" }, diff --git a/module/config/i18n/zh-CN.json b/module/config/i18n/zh-CN.json index 1e5a96911f..0e0581b167 100644 --- a/module/config/i18n/zh-CN.json +++ b/module/config/i18n/zh-CN.json @@ -416,7 +416,7 @@ }, "ScreenshotMethod": { "name": "模拟器截图方案", - "help": "使用自动选择时,将执行一次性能测试并自动更改为最快的截图方案\n一般情况下的速度: DroidCast_raw >> aScreenCap_nc > ADB_nc >>> aScreenCap > uiautomator2 ~= ADB\n运行 工具 - 性能测试 以寻找最快的方案", + "help": "使用自动选择时,将执行一次性能测试并自动更改为最快的截图方案\n一般情况下的速度: DroidCast_lz4 > DroidCast_raw >> aScreenCap_nc > ADB_nc >>> aScreenCap > uiautomator2 ~= ADB\n运行 工具 - 性能测试 以寻找最快的方案", "auto": "自动选择最快的", "ADB": "ADB", "ADB_nc": "ADB_nc", @@ -425,6 +425,7 @@ "aScreenCap_nc": "aScreenCap_nc", "DroidCast": "DroidCast", "DroidCast_raw": "DroidCast_raw", + "DroidCast_lz4": "DroidCast_lz4", "nemu_ipc": "nemu_ipc", "ldopengl": "ldopengl" }, diff --git a/module/config/i18n/zh-TW.json b/module/config/i18n/zh-TW.json index 0c36cc1550..55fc5143ad 100644 --- a/module/config/i18n/zh-TW.json +++ b/module/config/i18n/zh-TW.json @@ -416,7 +416,7 @@ }, "ScreenshotMethod": { "name": "模擬器截圖方案", - "help": "使用自動選擇時,將執行一次性能測試並自動更改為最快的截圖方案\n一般情況下的速度: DroidCast_raw >> aScreenCap_nc > ADB_nc >>> aScreenCap > uiautomator2 ~= ADB\n運行 工具 - 性能測試 以尋找最快的方案", + "help": "使用自動選擇時,將執行一次性能測試並自動更改為最快的截圖方案\n一般情況下的速度: DroidCast_lz4 > DroidCast_raw >> aScreenCap_nc > ADB_nc >>> aScreenCap > uiautomator2 ~= ADB\n運行 工具 - 性能測試 以尋找最快的方案", "auto": "自動選擇最快的", "ADB": "ADB", "ADB_nc": "ADB_nc", @@ -425,6 +425,7 @@ "aScreenCap_nc": "aScreenCap_nc", "DroidCast": "DroidCast", "DroidCast_raw": "DroidCast_raw", + "DroidCast_lz4": "DroidCast_lz4", "nemu_ipc": "nemu_ipc", "ldopengl": "ldopengl" }, diff --git a/module/daemon/benchmark.py b/module/daemon/benchmark.py index 9bc3d6c0bf..935da1bd39 100644 --- a/module/daemon/benchmark.py +++ b/module/daemon/benchmark.py @@ -176,7 +176,8 @@ def compare(res): def get_test_methods(self) -> t.Tuple[t.Tuple[str], t.Tuple[str]]: device = self.config.Benchmark_DeviceType # device == 'emulator' - screenshot = ['ADB', 'ADB_nc', 'uiautomator2', 'aScreenCap', 'aScreenCap_nc', 'DroidCast', 'DroidCast_raw'] + screenshot = ['ADB', 'ADB_nc', 'uiautomator2', 'aScreenCap', 'aScreenCap_nc', 'DroidCast', 'DroidCast_raw', + 'DroidCast_lz4'] click = ['ADB', 'uiautomator2', 'minitouch', 'MaaTouch'] def remove(*args): @@ -192,14 +193,12 @@ def remove(*args): screenshot = remove('ADB_nc', 'aScreenCap_nc') # VMOS if device == 'android_phone_vmos': - screenshot = ['ADB', 'aScreenCap', 'DroidCast', 'DroidCast_raw'] + screenshot = ['ADB', 'aScreenCap', 'DroidCast', 'DroidCast_raw', 'DroidCast_lz4'] click = ['ADB', 'Hermit', 'MaaTouch'] if self.device.nemu_ipc_available(): screenshot.append('nemu_ipc') if self.device.ldopengl_available(): screenshot.append('ldopengl') - if self.device.is_bluestacks_air: - screenshot = [l for l in screenshot if 'DroidCast' not in l] scene = self.config.Benchmark_TestScene if 'screenshot' not in scene: @@ -224,7 +223,7 @@ def run_simple_screenshot_benchmark(self): Returns: str: The fastest screenshot method on current device. """ - screenshot = ['ADB', 'ADB_nc', 'uiautomator2', 'aScreenCap', 'aScreenCap_nc', 'DroidCast', 'DroidCast_raw'] + screenshot = ['ADB', 'ADB_nc', 'uiautomator2', 'aScreenCap', 'aScreenCap_nc', 'DroidCast', 'DroidCast_raw', 'DroidCast_lz4'] def remove(*args): return [l for l in screenshot if l not in args] diff --git a/module/device/method/droidcast.py b/module/device/method/droidcast.py index a8fe50d207..c3fc904c56 100644 --- a/module/device/method/droidcast.py +++ b/module/device/method/droidcast.py @@ -3,6 +3,7 @@ from functools import wraps import cv2 +import lz4.block import numpy as np import requests from adbutils.errors import AdbError @@ -133,18 +134,18 @@ def droidcast_url(self, url='/preview'): return f'http://127.0.0.1:{self._droidcast_port}{url}' - def droidcast_raw_url(self, url='/screenshot'): + def droidcast_raw_url(self, url='/screenshot', compress=''): if self.is_mumu_over_version_356: w, h = self.droidcast_width, self.droidcast_height if self.orientation == 0: - return f'http://127.0.0.1:{self._droidcast_port}{url}?width={w}&height={h}' + return f'http://127.0.0.1:{self._droidcast_port}{url}?width={w}&height={h}&compress={compress}' elif self.orientation == 1: - return f'http://127.0.0.1:{self._droidcast_port}{url}?width={h}&height={w}' + return f'http://127.0.0.1:{self._droidcast_port}{url}?width={h}&height={w}&compress={compress}' else: # logger.warning('DroidCast receives invalid device orientation') pass - return f'http://127.0.0.1:{self._droidcast_port}{url}' + return f'http://127.0.0.1:{self._droidcast_port}{url}?compress={compress}' def droidcast_init(self): logger.hr('DroidCast init') @@ -176,6 +177,9 @@ def droidcast_init(self): elif self.config.DROIDCAST_VERSION == 'DroidCast_raw': logger.attr('DroidCast_raw', self.droidcast_raw_url()) self.droidcast_wait_startup() + elif self.config.DROIDCAST_VERSION == 'DroidCast_lz4': + logger.attr('DroidCast_lz4', self.droidcast_raw_url(compress='lz4')) + self.droidcast_wait_startup() else: logger.error(f'Unknown DROIDCAST_VERSION: {self.config.DROIDCAST_VERSION}') @@ -224,8 +228,8 @@ def screenshot_droidcast(self): return image @retry - def screenshot_droidcast_raw(self): - self.config.DROIDCAST_VERSION = 'DroidCast_raw' + def screenshot_droidcast_raw(self, use_lz4=False): + self.config.DROIDCAST_VERSION = 'DroidCast_raw' if not use_lz4 else 'DroidCast_lz4' shape = (720, 1280) if self.is_mumu_over_version_356: if not self.droidcast_width or not self.droidcast_height: @@ -235,7 +239,11 @@ def screenshot_droidcast_raw(self): rotate = self.is_mumu_over_version_356 and self.orientation == 1 - image = self.droidcast_session.get(self.droidcast_raw_url(), timeout=3).content + if use_lz4: + image_lz4 = self.droidcast_session.get(self.droidcast_raw_url(compress='lz4'), timeout=3).content + image = lz4.block.decompress(image_lz4, uncompressed_size=shape[0] * shape[1] * 2) + else: + image = self.droidcast_session.get(self.droidcast_raw_url(), timeout=3).content # DroidCast_raw returns a RGB565 bitmap try: @@ -297,6 +305,9 @@ def screenshot_droidcast_raw(self): return image + def screenshot_droidcast_lz4(self): + return self.screenshot_droidcast_raw(use_lz4=True) + def droidcast_wait_startup(self): """ Wait until DroidCast startup completed. diff --git a/module/device/screenshot.py b/module/device/screenshot.py index 9940ee0556..6e3b3fb341 100644 --- a/module/device/screenshot.py +++ b/module/device/screenshot.py @@ -39,6 +39,7 @@ def screenshot_methods(self): 'aScreenCap_nc': self.screenshot_ascreencap_nc, 'DroidCast': self.screenshot_droidcast, 'DroidCast_raw': self.screenshot_droidcast_raw, + 'DroidCast_lz4': self.screenshot_droidcast_lz4, 'scrcpy': self.screenshot_scrcpy, 'nemu_ipc': self.screenshot_nemu_ipc, 'ldopengl': self.screenshot_ldopengl,