ok-script 0.0.84__tar.gz → 0.0.96__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ok-script-0.0.84 → ok-script-0.0.96}/PKG-INFO +1 -1
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/OK.py +26 -2
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/capture/BaseCaptureMethod.py +0 -10
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/capture/HwndWindow.py +20 -19
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/capture/adb/DeviceManager.py +24 -27
- ok-script-0.0.96/ok/capture/adb/WindowsCaptureFactory.py +42 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/capture/windows/BitBltCaptureMethod.py +12 -7
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/capture/windows/WindowsGraphicsCaptureMethod.py +73 -60
- ok-script-0.0.96/ok/capture/windows/dump.py +81 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/color/Color.py +34 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/config/Config.py +3 -1
- ok-script-0.0.96/ok/feature/CompressCoco.py +75 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/feature/Feature.py +11 -5
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/feature/FeatureSet.py +132 -75
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/feature/FindFeature.py +2 -2
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/firebase/Analytics.py +2 -2
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/App.py +11 -4
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/MainWindow.py +7 -22
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/StartController.py +2 -2
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/debug/DebugTab.py +20 -21
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/debug/FrameWidget.py +4 -6
- ok-script-0.0.96/ok/gui/debug/LogWindow.py +191 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/debug/Screenshot.py +0 -1
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/resources.py +433 -432
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/start/StartCard.py +9 -0
- ok-script-0.0.96/ok/gui/tasks/OneTimeTaskTab.py +20 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/tasks/TaskCard.py +5 -5
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/tasks/TaskOpButton.py +2 -8
- ok-script-0.0.84/ok/gui/tasks/OneTimeTaskTab.py → ok-script-0.0.96/ok/gui/tasks/TaskTab.py +5 -7
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/tasks/TriggerTaskTab.py +5 -2
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/interaction/BaseInteraction.py +9 -3
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/interaction/Win32Interaction.py +18 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/ocr/OCR.py +4 -4
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/task/BaseTask.py +30 -14
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/task/ExecutorOperation.py +20 -10
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/task/TaskExecutor.py +49 -47
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/task/TriggerTask.py +1 -2
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/update/GithubMultiDownloader.py +48 -11
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/update/Updater.py +49 -28
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/util/Handler.py +1 -0
- ok-script-0.0.96/ok/util/list.py +9 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok_script.egg-info/PKG-INFO +1 -1
- {ok-script-0.0.84 → ok-script-0.0.96}/ok_script.egg-info/SOURCES.txt +3 -2
- {ok-script-0.0.84 → ok-script-0.0.96}/setup.py +1 -1
- ok-script-0.0.84/ok/capture/adb/WindowsCaptureFactory.py +0 -41
- ok-script-0.0.84/ok/capture/windows/dump.py +0 -31
- ok-script-0.0.84/ok/gui/debug/LoggerWidget.py +0 -77
- ok-script-0.0.84/ok/task/OneTimeTask.py +0 -35
- ok-script-0.0.84/ok/util/list.py +0 -2
- {ok-script-0.0.84 → ok-script-0.0.96}/README.md +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/alas/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/alas/emulator_base.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/alas/emulator_windows.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/alas/platform_base.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/alas/platform_windows.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/alas/utils.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/capture/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/capture/adb/ADBCaptureMethod.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/capture/adb/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/capture/adb/bin/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/capture/image/ImageCaptureMethod.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/capture/image/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/capture/windows/BaseWindowsCaptureMethod.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/capture/windows/DesktopDuplicationCaptureMethod.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/capture/windows/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/capture/windows/d3d11.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/capture/windows/utils.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/capture/windows/window.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/color/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/config/InfoDict.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/config/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/feature/Box.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/feature/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/firebase/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/Communicate.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/MessageWindow.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/TabTitles.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/about/AboutTab.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/about/HttpTextEdit.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/about/VersionCard.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/about/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/common/OKIcon.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/common/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/common/config.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/common/style_sheet.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/debug/AspectRatioWidget.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/debug/InfoWidget.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/debug/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/i18n/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/i18n/path.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/i18n/update.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/icon/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/icon/icon.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/overlay/OverlayWindow.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/overlay/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/qss/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/settings/SettingTab.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/settings/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/start/SelectCaptureListView.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/start/StartTab.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/start/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/tasks/ConfigItemFactory.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/tasks/ConfigLabelAndWidget.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/tasks/LabelAndDoubleSpinBox.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/tasks/LabelAndDropDown.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/tasks/LabelAndLineEdit.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/tasks/LabelAndList.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/tasks/LabelAndSpinBox.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/tasks/LabelAndSwitchButton.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/tasks/LabelAndWidget.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/tasks/ModifyListDialog.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/tasks/ModifyListItem.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/tasks/StartButton.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/tasks/TooltipTableWidget.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/tasks/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/util/Alert.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/util/InitWorker.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/util/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/widget/Card.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/widget/EmptyCard.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/widget/FramelessDialog.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/widget/ListTableWidgetItem.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/widget/NumericTableWidgetItem.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/widget/StartLoadingDialog.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/widget/StatusBar.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/widget/Tab.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/widget/TabWidget.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/widget/UpdateConfigWidgetItem.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/widget/YesNonWidgetItem.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/gui/widget/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/interaction/ADBInteraction.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/interaction/DoNothingInteraction.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/interaction/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/logging/Logger.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/logging/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/ocr/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/Windows/Foundation/Collections.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/Windows/Foundation/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/Windows/Globalization/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/Windows/Graphics/Capture/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/Windows/Graphics/DirectX/Direct3D11/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/Windows/Graphics/DirectX/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/Windows/Graphics/Imaging/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/Windows/Graphics/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/Windows/Media/Ocr/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/Windows/Media/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/Windows/Security/Cryptography/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/Windows/Security/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/Windows/Storage/Streams/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/Windows/Storage/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/Windows/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/delegate.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/export.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/idldsl.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/inspectable.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/roapi.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/types.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/rotypes/winstring.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/save/BlackBarProcessor.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/save/PostProcessor.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/save/SaveByInterval.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/save/SaveByKeyPress.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/save/SaveMethodBase.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/save/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/scene/FeatureScene.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/scene/Scene.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/scene/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/stats/StreamStats.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/stats/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/task/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/update/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/update/gen_md5.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/util/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/util/exit_event.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/util/json.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/util/path.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/util/thread.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/util/win32_process.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok/util/yaml.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok_script.egg-info/dependency_links.txt +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok_script.egg-info/requires.txt +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/ok_script.egg-info/top_level.txt +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/setup.cfg +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/tests/__init__.py +0 -0
- {ok-script-0.0.84 → ok-script-0.0.96}/tests/test_updater.py +0 -0
|
@@ -37,6 +37,9 @@ class OK:
|
|
|
37
37
|
config['debug'] = config.get("debug", False)
|
|
38
38
|
self.debug = config['debug']
|
|
39
39
|
try:
|
|
40
|
+
if self.debug:
|
|
41
|
+
import win32api
|
|
42
|
+
win32api.SetConsoleCtrlHandler(self.console_handler, True)
|
|
40
43
|
self.config = config
|
|
41
44
|
self.init_device_manager()
|
|
42
45
|
from ok.gui.debug.Screenshot import Screenshot
|
|
@@ -59,6 +62,7 @@ class OK:
|
|
|
59
62
|
if self.config.get("use_gui"):
|
|
60
63
|
if not self.init_error:
|
|
61
64
|
self.app.show_main_window()
|
|
65
|
+
logger.debug('start app.exec()')
|
|
62
66
|
self.app.exec()
|
|
63
67
|
else:
|
|
64
68
|
self.task_executor.start()
|
|
@@ -97,7 +101,7 @@ class OK:
|
|
|
97
101
|
if template_matching is not None:
|
|
98
102
|
coco_feature_json = self.config.get('template_matching').get('coco_feature_json')
|
|
99
103
|
from ok.feature.FeatureSet import FeatureSet
|
|
100
|
-
self.feature_set = FeatureSet(coco_feature_json,
|
|
104
|
+
self.feature_set = FeatureSet(self.debug, coco_feature_json,
|
|
101
105
|
default_horizontal_variance=template_matching.get(
|
|
102
106
|
'default_horizontal_variance', 0),
|
|
103
107
|
default_vertical_variance=template_matching.get('default_vertical_variance',
|
|
@@ -110,7 +114,7 @@ class OK:
|
|
|
110
114
|
trigger_tasks=self.config.get('trigger_tasks', []),
|
|
111
115
|
scenes=self.config['scenes'],
|
|
112
116
|
feature_set=self.feature_set,
|
|
113
|
-
config_folder=self.config.get("config_folder"))
|
|
117
|
+
config_folder=self.config.get("config_folder"), debug=self.debug)
|
|
114
118
|
|
|
115
119
|
ok.gui.executor = self.task_executor
|
|
116
120
|
|
|
@@ -135,6 +139,26 @@ class OK:
|
|
|
135
139
|
while not self.exit_event.is_set():
|
|
136
140
|
time.sleep(1)
|
|
137
141
|
|
|
142
|
+
def console_handler(self, event):
|
|
143
|
+
import win32con
|
|
144
|
+
if event == win32con.CTRL_C_EVENT:
|
|
145
|
+
logger.info("CTRL+C event dump threads")
|
|
146
|
+
from ok.capture.windows.dump import dump_threads
|
|
147
|
+
dump_threads()
|
|
148
|
+
self.quit()
|
|
149
|
+
elif event == win32con.CTRL_CLOSE_EVENT:
|
|
150
|
+
logger.info("Close event quit")
|
|
151
|
+
self.quit()
|
|
152
|
+
elif event == win32con.CTRL_LOGOFF_EVENT:
|
|
153
|
+
logger.info("Logoff event quit")
|
|
154
|
+
self.quit()
|
|
155
|
+
elif event == win32con.CTRL_SHUTDOWN_EVENT:
|
|
156
|
+
logger.info("Shutdown event quit")
|
|
157
|
+
self.quit()
|
|
158
|
+
else: # Perform clean-up tasks here
|
|
159
|
+
print("Performing clean-up...")
|
|
160
|
+
return True
|
|
161
|
+
|
|
138
162
|
def quit(self):
|
|
139
163
|
logger.debug('quit app')
|
|
140
164
|
self.exit_event.set()
|
|
@@ -24,20 +24,10 @@ class BaseCaptureMethod:
|
|
|
24
24
|
|
|
25
25
|
@property
|
|
26
26
|
def width(self):
|
|
27
|
-
if self._size[0] == 0:
|
|
28
|
-
try:
|
|
29
|
-
self.get_frame()
|
|
30
|
-
except Exception as e:
|
|
31
|
-
logger.error('width get frame error', e)
|
|
32
27
|
return self._size[0]
|
|
33
28
|
|
|
34
29
|
@property
|
|
35
30
|
def height(self):
|
|
36
|
-
if self._size[1] == 0:
|
|
37
|
-
try:
|
|
38
|
-
self.get_frame()
|
|
39
|
-
except Exception as e:
|
|
40
|
-
logger.error('height get frame error', e)
|
|
41
31
|
return self._size[1]
|
|
42
32
|
|
|
43
33
|
def get_frame(self) -> np.ndarray | None:
|
|
@@ -29,7 +29,6 @@ class HwndWindow:
|
|
|
29
29
|
left_cut = 0
|
|
30
30
|
ext_left_bounds = 0 # for BitBlt
|
|
31
31
|
ext_top_bounds = 0 # for BitBlt
|
|
32
|
-
window_change_listeners = []
|
|
33
32
|
frame_aspect_ratio = 0
|
|
34
33
|
hwnd = None
|
|
35
34
|
frame_width = 0
|
|
@@ -42,31 +41,23 @@ class HwndWindow:
|
|
|
42
41
|
real_x_offset = 0
|
|
43
42
|
real_y_offset = 0
|
|
44
43
|
|
|
45
|
-
def __init__(self, exit_event, title, exe_name=None, frame_width=0, frame_height=0):
|
|
44
|
+
def __init__(self, exit_event, title, exe_name=None, frame_width=0, frame_height=0, player_id=-1):
|
|
46
45
|
super().__init__()
|
|
47
46
|
self.app_exit_event = exit_event
|
|
48
47
|
self.exe_name = exe_name
|
|
49
48
|
self.title = title
|
|
50
49
|
self.stop_event = threading.Event()
|
|
51
50
|
self.visible = False
|
|
51
|
+
self.player_id = player_id
|
|
52
52
|
self.update_window(title, exe_name, frame_width, frame_height)
|
|
53
53
|
self.thread = threading.Thread(target=self.update_window_size, name="update_window_size")
|
|
54
54
|
self.thread.start()
|
|
55
55
|
|
|
56
|
-
def update_title_and_exe(self, title, exe):
|
|
57
|
-
self.title = title
|
|
58
|
-
self.exe_name = exe
|
|
59
|
-
self.hwnd = None
|
|
60
|
-
self.visible = False
|
|
61
|
-
self.exists = False
|
|
62
|
-
self.width = 0
|
|
63
|
-
self.height = 0
|
|
64
|
-
self.do_update_window_size()
|
|
65
|
-
|
|
66
56
|
def stop(self):
|
|
67
57
|
self.stop_event.set()
|
|
68
58
|
|
|
69
|
-
def update_window(self, title, exe_name, frame_width, frame_height):
|
|
59
|
+
def update_window(self, title, exe_name, frame_width, frame_height, player_id=-1):
|
|
60
|
+
self.player_id = player_id
|
|
70
61
|
self.title = title
|
|
71
62
|
self.exe_name = exe_name
|
|
72
63
|
self.update_frame_size(frame_width, frame_height)
|
|
@@ -100,7 +91,7 @@ class HwndWindow:
|
|
|
100
91
|
name, self.hwnd, self.exe_full_path, self.real_x_offset, self.real_y_offset, self.real_width, self.real_height = find_hwnd(
|
|
101
92
|
self.title,
|
|
102
93
|
self.exe_name,
|
|
103
|
-
self.frame_width, self.frame_height)
|
|
94
|
+
self.frame_width, self.frame_height, player_id=self.player_id)
|
|
104
95
|
self.exists = self.hwnd is not None
|
|
105
96
|
if self.hwnd is not None:
|
|
106
97
|
self.exists = win32gui.IsWindow(self.hwnd)
|
|
@@ -168,6 +159,8 @@ def find_hwnd(title, exe_name, frame_width, frame_height, player_id=-1):
|
|
|
168
159
|
elif not re.search(title, text):
|
|
169
160
|
return True
|
|
170
161
|
name, full_path, cmdline = get_exe_by_hwnd(hwnd)
|
|
162
|
+
if not name:
|
|
163
|
+
return True
|
|
171
164
|
x, y, border, title_height, width, height, scaling, ext_left_bounds, ext_top_bounds = get_window_bounds(
|
|
172
165
|
hwnd)
|
|
173
166
|
ret = (hwnd, full_path, width, height, x, y, text)
|
|
@@ -184,10 +177,9 @@ def find_hwnd(title, exe_name, frame_width, frame_height, player_id=-1):
|
|
|
184
177
|
|
|
185
178
|
win32gui.EnumWindows(callback, None)
|
|
186
179
|
if len(results) > 0:
|
|
187
|
-
biggest =
|
|
180
|
+
biggest = None
|
|
188
181
|
for result in results:
|
|
189
|
-
|
|
190
|
-
if (biggest is None or (result[2] * result[3]) > biggest[2] * biggest[3]) and bit_blt_test_hwnd(result[0]):
|
|
182
|
+
if biggest is None or (result[2] * result[3]) > biggest[2] * biggest[3]:
|
|
191
183
|
biggest = result
|
|
192
184
|
x_offset = 0
|
|
193
185
|
y_offset = 0
|
|
@@ -210,6 +202,12 @@ def get_player_id_from_cmdline(cmdline):
|
|
|
210
202
|
if i != 0:
|
|
211
203
|
if cmdline[i].isdigit():
|
|
212
204
|
return int(cmdline[i])
|
|
205
|
+
for i in range(len(cmdline)):
|
|
206
|
+
if i != 0:
|
|
207
|
+
value = re.search(r'index=(\d+)', cmdline[i])
|
|
208
|
+
# Return the value if it exists, otherwise return None
|
|
209
|
+
if value is not None:
|
|
210
|
+
return int(value.group(1))
|
|
213
211
|
return 0
|
|
214
212
|
|
|
215
213
|
|
|
@@ -248,8 +246,11 @@ def get_exe_by_hwnd(hwnd):
|
|
|
248
246
|
_, pid = win32process.GetWindowThreadProcessId(hwnd)
|
|
249
247
|
|
|
250
248
|
# Get the process name and executable path
|
|
251
|
-
|
|
252
|
-
|
|
249
|
+
if pid > 0:
|
|
250
|
+
process = psutil.Process(pid)
|
|
251
|
+
return process.name(), process.exe(), process.cmdline()
|
|
252
|
+
else:
|
|
253
|
+
return None, None, None
|
|
253
254
|
|
|
254
255
|
|
|
255
256
|
if __name__ == '__main__':
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from adbutils import AdbTimeout
|
|
1
|
+
from adbutils import AdbTimeout, AdbError
|
|
2
2
|
|
|
3
3
|
from ok.alas.platform_windows import get_emulator_exe
|
|
4
4
|
from ok.capture.HwndWindow import HwndWindow, find_hwnd
|
|
@@ -53,27 +53,25 @@ class DeviceManager:
|
|
|
53
53
|
logger.debug(f'connect adb')
|
|
54
54
|
return self._adb
|
|
55
55
|
|
|
56
|
-
def adb_connect(self, addr):
|
|
56
|
+
def adb_connect(self, addr, try_connect=True):
|
|
57
57
|
try:
|
|
58
|
-
for
|
|
58
|
+
for device in self.adb.device_list():
|
|
59
59
|
if self.exit_event.is_set():
|
|
60
60
|
logger.error(f"adb_connect exit_event is set")
|
|
61
61
|
return None
|
|
62
|
-
if
|
|
63
|
-
if info
|
|
62
|
+
if device.serial == addr:
|
|
63
|
+
if device.info['state'] == 'offline':
|
|
64
64
|
logger.debug(f'adb_connect offline disconnect first {addr}')
|
|
65
65
|
self.adb.disconnect(addr)
|
|
66
66
|
else:
|
|
67
67
|
logger.debug(f'adb_connect already connected {addr}')
|
|
68
|
-
return
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
return device
|
|
69
|
+
if try_connect:
|
|
70
|
+
self.adb.connect(addr, timeout=3)
|
|
71
|
+
logger.debug(f'adb_connect {addr}')
|
|
72
|
+
return self.adb_connect(addr, try_connect=False)
|
|
73
73
|
except AdbTimeout as e:
|
|
74
74
|
logger.error(f"adb connect error try kill server {addr}", e)
|
|
75
|
-
# self.adb.server_kill()
|
|
76
|
-
# self._adb = None
|
|
77
75
|
except Exception as e:
|
|
78
76
|
logger.error(f"adb connect error return none {addr}", e)
|
|
79
77
|
|
|
@@ -101,9 +99,7 @@ class DeviceManager:
|
|
|
101
99
|
|
|
102
100
|
def do_refresh(self, current=False):
|
|
103
101
|
self.update_pc_device()
|
|
104
|
-
|
|
105
102
|
self.refresh_emulators(current)
|
|
106
|
-
|
|
107
103
|
self.refresh_phones(current)
|
|
108
104
|
|
|
109
105
|
if self.exit_event.is_set():
|
|
@@ -120,8 +116,8 @@ class DeviceManager:
|
|
|
120
116
|
if imei is not None:
|
|
121
117
|
preferred = self.get_preferred_device()
|
|
122
118
|
if current and preferred is not None and preferred['imei'] != imei:
|
|
123
|
-
logger.debug(f"refresh current only skip others {preferred['imei']} != imei")
|
|
124
|
-
|
|
119
|
+
logger.debug(f"refresh current only skip others {preferred['imei']} != {imei}")
|
|
120
|
+
continue
|
|
125
121
|
found = False
|
|
126
122
|
for device in self.device_dict.values():
|
|
127
123
|
if device.get('adb_imei') == imei:
|
|
@@ -131,7 +127,7 @@ class DeviceManager:
|
|
|
131
127
|
width, height = self.get_resolution(adb_device)
|
|
132
128
|
logger.debug(f'refresh_phones found an phone {adb_device}')
|
|
133
129
|
phone_device = {"address": adb_device.serial, "device": "adb", "connected": True, "imei": imei,
|
|
134
|
-
"nick": adb_device.prop.model or imei,
|
|
130
|
+
"nick": adb_device.prop.model or imei, "player_id": -1,
|
|
135
131
|
"resolution": f'{width}x{height}'}
|
|
136
132
|
self.device_dict[imei] = phone_device
|
|
137
133
|
|
|
@@ -147,13 +143,13 @@ class DeviceManager:
|
|
|
147
143
|
logger.debug(f"refresh current only skip others {preferred['imei']} != {emulator.name}")
|
|
148
144
|
break
|
|
149
145
|
adb_device = self.adb_connect(emulator.serial)
|
|
150
|
-
width, height = self.get_resolution(adb_device)
|
|
146
|
+
width, height = self.get_resolution(adb_device) if adb_device is not None else 0, 0
|
|
151
147
|
name, hwnd, full_path, x, y, width, height = find_hwnd(None,
|
|
152
148
|
emulator.path, width, height, emulator.player_id)
|
|
153
149
|
connected = adb_device is not None and name is not None
|
|
154
150
|
emulator_device = {"address": emulator.serial, "device": "adb",
|
|
155
151
|
"full_path": emulator.path, "connected": connected,
|
|
156
|
-
"imei": emulator.name,
|
|
152
|
+
"imei": emulator.name, "player_id": emulator.player_id,
|
|
157
153
|
"nick": name or emulator.name, "emulator": emulator}
|
|
158
154
|
if adb_device is not None:
|
|
159
155
|
emulator_device["resolution"] = f"{width}x{height}"
|
|
@@ -236,11 +232,11 @@ class DeviceManager:
|
|
|
236
232
|
preferred = self.get_preferred_device()
|
|
237
233
|
return preferred.get('hwnd')
|
|
238
234
|
|
|
239
|
-
def ensure_hwnd(self, title, exe, frame_width=0, frame_height=0):
|
|
235
|
+
def ensure_hwnd(self, title, exe, frame_width=0, frame_height=0, player_id=-1):
|
|
240
236
|
if self.hwnd is None:
|
|
241
|
-
self.hwnd = HwndWindow(self.exit_event, title, exe, frame_width, frame_height)
|
|
237
|
+
self.hwnd = HwndWindow(self.exit_event, title, exe, frame_width, frame_height, player_id)
|
|
242
238
|
else:
|
|
243
|
-
self.hwnd.update_window(title, exe, frame_width, frame_height)
|
|
239
|
+
self.hwnd.update_window(title, exe, frame_width, frame_height, player_id)
|
|
244
240
|
|
|
245
241
|
def use_windows_capture(self, override_config=None, require_bg=False, use_bit_blt_only=False):
|
|
246
242
|
if not override_config:
|
|
@@ -267,12 +263,12 @@ class DeviceManager:
|
|
|
267
263
|
self.use_windows_capture()
|
|
268
264
|
if not isinstance(self.interaction, Win32Interaction):
|
|
269
265
|
self.interaction = Win32Interaction(self.capture_method)
|
|
270
|
-
preferred['connected'] = self.capture_method.connected()
|
|
266
|
+
preferred['connected'] = self.capture_method is not None and self.capture_method.connected()
|
|
271
267
|
else:
|
|
272
268
|
width, height = self.get_resolution()
|
|
273
269
|
if self.config.get('capture') == "windows":
|
|
274
|
-
self.ensure_hwnd(None, preferred.get('full_path'), width, height)
|
|
275
|
-
self.use_windows_capture({'can_bit_blt': True}, require_bg=True, use_bit_blt_only=
|
|
270
|
+
self.ensure_hwnd(None, preferred.get('full_path'), width, height, preferred['player_id'])
|
|
271
|
+
self.use_windows_capture({'can_bit_blt': True}, require_bg=True, use_bit_blt_only=False)
|
|
276
272
|
else:
|
|
277
273
|
if not isinstance(self.capture_method, ADBCaptureMethod):
|
|
278
274
|
logger.debug(f'use adb capture')
|
|
@@ -281,7 +277,7 @@ class DeviceManager:
|
|
|
281
277
|
self.capture_method = ADBCaptureMethod(self, self.exit_event, width=width,
|
|
282
278
|
height=height)
|
|
283
279
|
if self.debug and preferred.get('full_path'):
|
|
284
|
-
self.ensure_hwnd(None, preferred.get('full_path'), width, height)
|
|
280
|
+
self.ensure_hwnd(None, preferred.get('full_path'), width, height, preferred['player_id'])
|
|
285
281
|
elif self.hwnd is not None:
|
|
286
282
|
self.hwnd.stop()
|
|
287
283
|
self.hwnd = None
|
|
@@ -341,12 +337,13 @@ class DeviceManager:
|
|
|
341
337
|
if device is not None:
|
|
342
338
|
try:
|
|
343
339
|
return device.shell(*args, **kwargs)
|
|
340
|
+
except AdbError as e:
|
|
341
|
+
logger.debug(f'shell adb error {args} {e}')
|
|
344
342
|
except Exception as e:
|
|
345
343
|
addr = self.get_preferred_device()['address']
|
|
346
344
|
self.refresh_emulators()
|
|
347
345
|
new_addr = self.get_preferred_device()['address']
|
|
348
346
|
logger.error(f"shell_wrapper error occurred, try refresh_emulators {addr} {new_addr}", e)
|
|
349
|
-
return None
|
|
350
347
|
else:
|
|
351
348
|
raise Exception('Device is none')
|
|
352
349
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from ok.logging.Logger import get_logger
|
|
2
|
+
|
|
3
|
+
logger = get_logger(__name__)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def update_capture_method(config, capture_method, hwnd, require_bg=False, use_bit_blt_only=False):
|
|
7
|
+
try:
|
|
8
|
+
if config.get('can_bit_blt'):
|
|
9
|
+
logger.debug(
|
|
10
|
+
f"try BitBlt method {config} {hwnd} current_type:{type(capture_method)}")
|
|
11
|
+
from ok.capture.windows.BitBltCaptureMethod import BitBltCaptureMethod
|
|
12
|
+
target_method = BitBltCaptureMethod
|
|
13
|
+
capture_method = get_capture(capture_method, target_method, hwnd)
|
|
14
|
+
if capture_method.test_is_not_pure_color():
|
|
15
|
+
return capture_method
|
|
16
|
+
else:
|
|
17
|
+
logger.info("test_is_not_pure_color failed, can't use BitBlt")
|
|
18
|
+
if use_bit_blt_only:
|
|
19
|
+
return None
|
|
20
|
+
from ok.capture.windows.WindowsGraphicsCaptureMethod import windows_graphics_available
|
|
21
|
+
if windows_graphics_available():
|
|
22
|
+
from ok.capture.windows.WindowsGraphicsCaptureMethod import WindowsGraphicsCaptureMethod
|
|
23
|
+
target_method = WindowsGraphicsCaptureMethod
|
|
24
|
+
capture_method = get_capture(capture_method, target_method, hwnd)
|
|
25
|
+
return capture_method
|
|
26
|
+
|
|
27
|
+
if not require_bg:
|
|
28
|
+
from ok.capture.windows.DesktopDuplicationCaptureMethod import DesktopDuplicationCaptureMethod
|
|
29
|
+
target_method = DesktopDuplicationCaptureMethod
|
|
30
|
+
capture_method = get_capture(capture_method, target_method, hwnd)
|
|
31
|
+
return capture_method
|
|
32
|
+
except Exception as e:
|
|
33
|
+
logger.error(f'update_capture_method exception, return None: ', e)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_capture(capture_method, target_method, hwnd):
|
|
37
|
+
if not isinstance(capture_method, target_method):
|
|
38
|
+
if capture_method is not None:
|
|
39
|
+
capture_method.close()
|
|
40
|
+
capture_method = target_method(hwnd)
|
|
41
|
+
capture_method.hwnd_window = hwnd
|
|
42
|
+
return capture_method
|
|
@@ -10,7 +10,7 @@ from typing_extensions import override
|
|
|
10
10
|
|
|
11
11
|
from ok.capture.windows.BaseWindowsCaptureMethod import BaseWindowsCaptureMethod
|
|
12
12
|
from ok.capture.windows.utils import try_delete_dc, BGRA_CHANNEL_COUNT
|
|
13
|
-
from ok.
|
|
13
|
+
from ok.color.Color import is_close_to_pure_color
|
|
14
14
|
from ok.logging.Logger import get_logger
|
|
15
15
|
|
|
16
16
|
# This is an undocumented nFlag value for PrintWindow
|
|
@@ -60,12 +60,17 @@ class BitBltCaptureMethod(BaseWindowsCaptureMethod):
|
|
|
60
60
|
return False
|
|
61
61
|
return True
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
def test_is_not_pure_color(self):
|
|
64
|
+
frame = self.do_get_frame()
|
|
65
|
+
if frame is None:
|
|
66
|
+
logger.error(f'Failed to test_is_not_pure_color frame is None {self.hwnd_window}')
|
|
67
|
+
return False
|
|
68
|
+
else:
|
|
69
|
+
if is_close_to_pure_color(frame):
|
|
70
|
+
logger.error(f'Failed to test_is_not_pure_color failed {self.hwnd_window}')
|
|
71
|
+
return False
|
|
72
|
+
else:
|
|
73
|
+
return True
|
|
69
74
|
|
|
70
75
|
|
|
71
76
|
def bit_blt_capture_frame(hwnd, border, title_height, width, height, ext_left_bounds, ext_top_bounds,
|
|
@@ -23,7 +23,7 @@ logger = get_logger(__name__)
|
|
|
23
23
|
class WindowsGraphicsCaptureMethod(BaseWindowsCaptureMethod):
|
|
24
24
|
name = "Windows Graphics Capture"
|
|
25
25
|
description = "fast, most compatible, capped at 60fps"
|
|
26
|
-
|
|
26
|
+
last_dx_frame = None
|
|
27
27
|
last_frame_time = 0
|
|
28
28
|
frame_pool = None
|
|
29
29
|
item = None
|
|
@@ -38,67 +38,78 @@ class WindowsGraphicsCaptureMethod(BaseWindowsCaptureMethod):
|
|
|
38
38
|
|
|
39
39
|
def frame_arrived_callback(self, x, y):
|
|
40
40
|
try:
|
|
41
|
-
|
|
41
|
+
self.last_frame_time = time.time()
|
|
42
|
+
next_frame = self.frame_pool.TryGetNextFrame()
|
|
43
|
+
if next_frame is not None:
|
|
44
|
+
self.last_dx_frame = next_frame
|
|
45
|
+
else:
|
|
46
|
+
logger.warning('frame_arrived_callback TryGetNextFrame returned None')
|
|
42
47
|
except Exception as e:
|
|
43
48
|
logger.error(f"TryGetNextFrame error {e}")
|
|
44
49
|
self.close()
|
|
45
50
|
return
|
|
51
|
+
|
|
52
|
+
def convert_dx_frame(self):
|
|
53
|
+
frame = self.last_dx_frame
|
|
54
|
+
self.last_dx_frame = None
|
|
46
55
|
if not frame:
|
|
56
|
+
logger.warning('convert_dx_frame self.last_dx_frame is none')
|
|
57
|
+
return None
|
|
58
|
+
|
|
59
|
+
need_reset_framepool = False
|
|
60
|
+
if frame.ContentSize.Width != self.last_size.Width or frame.ContentSize.Height != self.last_size.Height:
|
|
61
|
+
need_reset_framepool = True
|
|
62
|
+
self.last_size = frame.ContentSize
|
|
63
|
+
|
|
64
|
+
if need_reset_framepool:
|
|
65
|
+
logger.info('need_reset_framepool')
|
|
66
|
+
self.reset_framepool(frame.ContentSize)
|
|
47
67
|
return
|
|
48
|
-
|
|
49
|
-
img = None
|
|
50
|
-
with frame:
|
|
51
|
-
need_reset_framepool = False
|
|
52
|
-
need_reset_device = False
|
|
53
|
-
if frame.ContentSize.Width != self.last_size.Width or frame.ContentSize.Height != self.last_size.Height:
|
|
54
|
-
need_reset_framepool = True
|
|
55
|
-
self.last_size = frame.ContentSize
|
|
68
|
+
need_reset_device = False
|
|
56
69
|
|
|
57
|
-
|
|
58
|
-
self.reset_framepool(frame.ContentSize)
|
|
59
|
-
return
|
|
60
|
-
tex = None
|
|
70
|
+
tex = None
|
|
61
71
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
72
|
+
cputex = None
|
|
73
|
+
try:
|
|
74
|
+
from ok.rotypes.Windows.Graphics.DirectX.Direct3D11 import IDirect3DDxgiInterfaceAccess
|
|
75
|
+
from ok.rotypes.roapi import GetActivationFactory
|
|
76
|
+
tex = frame.Surface.astype(IDirect3DDxgiInterfaceAccess).GetInterface(
|
|
77
|
+
d3d11.ID3D11Texture2D.GUID).astype(d3d11.ID3D11Texture2D)
|
|
78
|
+
desc = tex.GetDesc()
|
|
79
|
+
desc2 = d3d11.D3D11_TEXTURE2D_DESC()
|
|
80
|
+
desc2.Width = desc.Width
|
|
81
|
+
desc2.Height = desc.Height
|
|
82
|
+
desc2.MipLevels = desc.MipLevels
|
|
83
|
+
desc2.ArraySize = desc.ArraySize
|
|
84
|
+
desc2.Format = desc.Format
|
|
85
|
+
desc2.SampleDesc = desc.SampleDesc
|
|
86
|
+
desc2.Usage = d3d11.D3D11_USAGE_STAGING
|
|
87
|
+
desc2.CPUAccessFlags = d3d11.D3D11_CPU_ACCESS_READ
|
|
88
|
+
desc2.BindFlags = 0
|
|
89
|
+
desc2.MiscFlags = 0
|
|
90
|
+
cputex = self.dxdevice.CreateTexture2D(ctypes.byref(desc2), None)
|
|
91
|
+
self.immediatedc.CopyResource(cputex, tex)
|
|
92
|
+
mapinfo = self.immediatedc.Map(cputex, 0, d3d11.D3D11_MAP_READ, 0)
|
|
93
|
+
img = np.ctypeslib.as_array(ctypes.cast(mapinfo.pData, PBYTE),
|
|
94
|
+
(desc.Height, mapinfo.RowPitch // 4, 4))[
|
|
95
|
+
:, :desc.Width].copy()
|
|
96
|
+
self.immediatedc.Unmap(cputex, 0)
|
|
97
|
+
return img
|
|
98
|
+
except OSError as e:
|
|
99
|
+
if e.winerror == d3d11.DXGI_ERROR_DEVICE_REMOVED or e.winerror == d3d11.DXGI_ERROR_DEVICE_RESET:
|
|
100
|
+
need_reset_framepool = True
|
|
101
|
+
need_reset_device = True
|
|
102
|
+
logger.error('convert_dx_frame win error', e)
|
|
103
|
+
else:
|
|
104
|
+
raise e
|
|
105
|
+
finally:
|
|
106
|
+
if tex is not None:
|
|
107
|
+
tex.Release()
|
|
108
|
+
if cputex is not None:
|
|
109
|
+
cputex.Release()
|
|
110
|
+
if need_reset_framepool:
|
|
111
|
+
self.reset_framepool(frame.ContentSize, need_reset_device)
|
|
112
|
+
return self.get_frame()
|
|
102
113
|
|
|
103
114
|
@property
|
|
104
115
|
def hwnd_window(self):
|
|
@@ -139,7 +150,7 @@ class WindowsGraphicsCaptureMethod(BaseWindowsCaptureMethod):
|
|
|
139
150
|
self.evtoken = item.add_Closed(delegate)
|
|
140
151
|
self.frame_pool = Direct3D11CaptureFramePool.CreateFreeThreaded(self.rtdevice,
|
|
141
152
|
DirectXPixelFormat.B8G8R8A8UIntNormalized,
|
|
142
|
-
|
|
153
|
+
2, item.Size)
|
|
143
154
|
self.session = self.frame_pool.CreateCaptureSession(item)
|
|
144
155
|
pool = self.frame_pool
|
|
145
156
|
pool.add_FrameArrived(
|
|
@@ -193,10 +204,10 @@ class WindowsGraphicsCaptureMethod(BaseWindowsCaptureMethod):
|
|
|
193
204
|
@override
|
|
194
205
|
def do_get_frame(self):
|
|
195
206
|
if self.start_or_stop():
|
|
196
|
-
frame = self.
|
|
197
|
-
|
|
207
|
+
frame = self.convert_dx_frame()
|
|
208
|
+
if frame is None:
|
|
209
|
+
return
|
|
198
210
|
latency = time.time() - self.last_frame_time
|
|
199
|
-
self.last_frame_time = time.time()
|
|
200
211
|
|
|
201
212
|
frame = self.crop_image(frame)
|
|
202
213
|
|
|
@@ -205,18 +216,20 @@ class WindowsGraphicsCaptureMethod(BaseWindowsCaptureMethod):
|
|
|
205
216
|
if new_width <= 0 or new_width <= 0:
|
|
206
217
|
logger.warning(f"get_frame size <=0 {new_width}x{new_height}")
|
|
207
218
|
frame = None
|
|
208
|
-
if latency >
|
|
219
|
+
if latency > 2:
|
|
209
220
|
logger.warning(f"latency too large return None frame: {latency}")
|
|
210
221
|
return None
|
|
211
222
|
else:
|
|
223
|
+
# logger.debug(f'frame latency: {latency}')
|
|
212
224
|
return frame
|
|
213
225
|
|
|
214
226
|
def reset_framepool(self, size, reset_device=False):
|
|
227
|
+
logger.info(f'reset_framepool')
|
|
215
228
|
from ok.rotypes.Windows.Graphics.DirectX import DirectXPixelFormat
|
|
216
229
|
if reset_device:
|
|
217
230
|
self.create_device()
|
|
218
231
|
self.frame_pool.Recreate(self.rtdevice,
|
|
219
|
-
DirectXPixelFormat.B8G8R8A8UIntNormalized,
|
|
232
|
+
DirectXPixelFormat.B8G8R8A8UIntNormalized, 2, size)
|
|
220
233
|
|
|
221
234
|
def crop_image(self, frame):
|
|
222
235
|
if frame is not None:
|