3
This commit is contained in:
@@ -48,7 +48,7 @@ from PyQt5.QtWidgets import (
|
|||||||
QComboBox, QFileDialog, QTextEdit, QFrame, QMessageBox,
|
QComboBox, QFileDialog, QTextEdit, QFrame, QMessageBox,
|
||||||
QSizePolicy, QGroupBox, QDialog, QAction, QWidgetAction
|
QSizePolicy, QGroupBox, QDialog, QAction, QWidgetAction
|
||||||
)
|
)
|
||||||
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer
|
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer, QEventLoop
|
||||||
from PyQt5.QtGui import QImage, QPixmap, QFont
|
from PyQt5.QtGui import QImage, QPixmap, QFont
|
||||||
|
|
||||||
from d2c_batch import batch_convert, software_d2c, software_d2c_inv
|
from d2c_batch import batch_convert, software_d2c, software_d2c_inv
|
||||||
@@ -1648,8 +1648,9 @@ class MainWindow(QMainWindow):
|
|||||||
# ─────────────────────────────────
|
# ─────────────────────────────────
|
||||||
|
|
||||||
def _refresh_devices(self):
|
def _refresh_devices(self):
|
||||||
if self._refresh_worker and self._refresh_worker.isRunning():
|
if getattr(self, '_refreshing', False):
|
||||||
return
|
return
|
||||||
|
self._refreshing = True
|
||||||
self.color_combo.clear()
|
self.color_combo.clear()
|
||||||
self.depth_combo.clear()
|
self.depth_combo.clear()
|
||||||
self.preset_combo.clear()
|
self.preset_combo.clear()
|
||||||
@@ -1662,66 +1663,143 @@ class MainWindow(QMainWindow):
|
|||||||
for lbl in (self.device_status, self.d2c_device_status):
|
for lbl in (self.device_status, self.d2c_device_status):
|
||||||
lbl.setText("正在扫描设备…")
|
lbl.setText("正在扫描设备…")
|
||||||
lbl.setStyleSheet(f"color:#aaa; font-size:{_fs(12)}px;")
|
lbl.setStyleSheet(f"color:#aaa; font-size:{_fs(12)}px;")
|
||||||
self._refresh_worker = RefreshDevicesWorker()
|
# 先返回事件循环让 UI 重绘,再执行阻塞的 SDK 调用
|
||||||
self._refresh_worker.done.connect(self._on_refresh_done)
|
QTimer.singleShot(0, self._do_refresh_sync)
|
||||||
self._refresh_worker.error.connect(self._on_refresh_error)
|
|
||||||
self._refresh_worker.finished.connect(self._on_refresh_finished)
|
def _do_refresh_sync(self):
|
||||||
self._refresh_worker.start()
|
import threading
|
||||||
|
|
||||||
|
result: dict = {}
|
||||||
|
finished = threading.Event()
|
||||||
|
|
||||||
|
def _sdk_work():
|
||||||
|
try:
|
||||||
|
from pyorbbecsdk import Pipeline, OBSensorType
|
||||||
|
p = Pipeline()
|
||||||
|
|
||||||
|
sn = "unknown"
|
||||||
|
try:
|
||||||
|
sn = p.get_device().get_device_info().get_serial_number()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
color_items = []
|
||||||
|
color_list = p.get_stream_profile_list(OBSensorType.COLOR_SENSOR)
|
||||||
|
for i in range(color_list.get_count()):
|
||||||
|
vp = color_list.get_stream_profile_by_index(i).as_video_stream_profile()
|
||||||
|
if vp is None:
|
||||||
|
continue
|
||||||
|
fmt = str(vp.get_format()).split(".")[-1]
|
||||||
|
cfg = {"width": vp.get_width(), "height": vp.get_height(),
|
||||||
|
"fps": vp.get_fps(), "format": fmt}
|
||||||
|
color_items.append((
|
||||||
|
f"{vp.get_width()}×{vp.get_height()} @ {vp.get_fps()} fps [{fmt}]",
|
||||||
|
cfg))
|
||||||
|
|
||||||
|
depth_items = []
|
||||||
|
depth_list = p.get_stream_profile_list(OBSensorType.DEPTH_SENSOR)
|
||||||
|
for i in range(depth_list.get_count()):
|
||||||
|
vp = depth_list.get_stream_profile_by_index(i).as_video_stream_profile()
|
||||||
|
if vp is None:
|
||||||
|
continue
|
||||||
|
fmt = str(vp.get_format()).split(".")[-1]
|
||||||
|
cfg = {"width": vp.get_width(), "height": vp.get_height(),
|
||||||
|
"fps": vp.get_fps(), "format": fmt}
|
||||||
|
depth_items.append((
|
||||||
|
f"{vp.get_width()}×{vp.get_height()} @ {vp.get_fps()} fps [{fmt}]",
|
||||||
|
cfg))
|
||||||
|
|
||||||
|
preset_items, current_preset = [], None
|
||||||
|
try:
|
||||||
|
pl = p.get_device().get_available_preset_list()
|
||||||
|
current_preset = p.get_device().get_current_preset_name()
|
||||||
|
if pl and len(pl) > 0:
|
||||||
|
preset_items = [("── 不切换 ──", None)] + [
|
||||||
|
(pl[i], pl[i]) for i in range(len(pl))]
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
result['ok'] = {
|
||||||
|
'sn': sn,
|
||||||
|
'color_items': color_items,
|
||||||
|
'depth_items': depth_items,
|
||||||
|
'preset_items': preset_items,
|
||||||
|
'current_preset': current_preset,
|
||||||
|
}
|
||||||
|
except Exception as exc:
|
||||||
|
result['err'] = str(exc)
|
||||||
|
finally:
|
||||||
|
finished.set()
|
||||||
|
|
||||||
|
t = threading.Thread(target=_sdk_work, daemon=True)
|
||||||
|
t.start()
|
||||||
|
|
||||||
|
# 主线程跑局部事件循环,保持窗口可移动;每 20ms 检查 SDK 线程是否完成
|
||||||
|
loop = QEventLoop()
|
||||||
|
poll = QTimer()
|
||||||
|
poll.setInterval(20)
|
||||||
|
|
||||||
|
def _check():
|
||||||
|
if finished.is_set():
|
||||||
|
poll.stop()
|
||||||
|
loop.quit()
|
||||||
|
|
||||||
|
poll.timeout.connect(_check)
|
||||||
|
poll.start()
|
||||||
|
loop.exec_()
|
||||||
|
t.join()
|
||||||
|
|
||||||
|
# 回到主线程填充 UI
|
||||||
|
try:
|
||||||
|
if 'err' in result:
|
||||||
|
raise RuntimeError(result['err'])
|
||||||
|
|
||||||
|
r = result['ok']
|
||||||
|
for label, cfg in r['color_items']:
|
||||||
|
self._color_profiles_data.append(cfg)
|
||||||
|
self.color_combo.addItem(label, cfg)
|
||||||
|
self.d2c_color_combo.addItem(label, cfg)
|
||||||
|
for label, cfg in r['depth_items']:
|
||||||
|
self._depth_profiles_data.append(cfg)
|
||||||
|
self.depth_combo.addItem(label, cfg)
|
||||||
|
self.d2c_depth_combo.addItem(label, cfg)
|
||||||
|
|
||||||
|
preset_items = r['preset_items']
|
||||||
|
current_preset = r['current_preset']
|
||||||
|
if preset_items:
|
||||||
|
for label, data in preset_items:
|
||||||
|
self.preset_combo.addItem(label, data)
|
||||||
|
idx = self.preset_combo.findData(current_preset)
|
||||||
|
if idx >= 0:
|
||||||
|
self.preset_combo.setCurrentIndex(idx)
|
||||||
|
self.preset_combo.setEnabled(True)
|
||||||
|
fm = self.preset_combo.fontMetrics()
|
||||||
|
max_w = max(fm.horizontalAdvance(self.preset_combo.itemText(i))
|
||||||
|
for i in range(self.preset_combo.count()))
|
||||||
|
padded = max_w + _sz(48)
|
||||||
|
self.preset_combo.view().setMinimumWidth(padded)
|
||||||
|
self.preset_combo.setMinimumWidth(padded)
|
||||||
|
self.preset_combo.updateGeometry()
|
||||||
|
else:
|
||||||
|
self.preset_combo.addItem("(设备不支持)", None)
|
||||||
|
self.preset_combo.setEnabled(False)
|
||||||
|
|
||||||
|
sn = r['sn']
|
||||||
|
nc, nd = len(self._color_profiles_data), len(self._depth_profiles_data)
|
||||||
|
msg = f"已连接 SN: {sn} 彩色 {nc} 项 / 深度 {nd} 项"
|
||||||
|
style = f"color:#4aaa4a; font-size:{_fs(12)}px;"
|
||||||
|
|
||||||
|
except Exception as exc:
|
||||||
|
msg = f"未找到设备:{exc}"
|
||||||
|
style = f"color:#cc6666; font-size:{_fs(12)}px;"
|
||||||
|
|
||||||
def _on_refresh_done(self, result: dict):
|
|
||||||
self.refresh_btn.setEnabled(True)
|
|
||||||
self.d2c_refresh_btn.setEnabled(True)
|
|
||||||
for label, cfg in result["color_items"]:
|
|
||||||
self._color_profiles_data.append(cfg)
|
|
||||||
self.color_combo.addItem(label, cfg)
|
|
||||||
self.d2c_color_combo.addItem(label, cfg)
|
|
||||||
for label, cfg in result["depth_items"]:
|
|
||||||
self._depth_profiles_data.append(cfg)
|
|
||||||
self.depth_combo.addItem(label, cfg)
|
|
||||||
self.d2c_depth_combo.addItem(label, cfg)
|
|
||||||
preset_items = result.get("preset_items", [])
|
|
||||||
current_preset = result.get("current_preset")
|
|
||||||
if preset_items:
|
|
||||||
for label, data in preset_items:
|
|
||||||
self.preset_combo.addItem(label, data)
|
|
||||||
idx = self.preset_combo.findData(current_preset)
|
|
||||||
if idx >= 0:
|
|
||||||
self.preset_combo.setCurrentIndex(idx)
|
|
||||||
self.preset_combo.setEnabled(True)
|
|
||||||
fm = self.preset_combo.fontMetrics()
|
|
||||||
max_w = max(fm.horizontalAdvance(self.preset_combo.itemText(i))
|
|
||||||
for i in range(self.preset_combo.count()))
|
|
||||||
padded = max_w + _sz(48)
|
|
||||||
self.preset_combo.view().setMinimumWidth(padded)
|
|
||||||
self.preset_combo.setMinimumWidth(padded)
|
|
||||||
self.preset_combo.updateGeometry()
|
|
||||||
else:
|
|
||||||
self.preset_combo.addItem("(设备不支持)", None)
|
|
||||||
self.preset_combo.setEnabled(False)
|
|
||||||
sn = result.get("sn", "unknown")
|
|
||||||
nc, nd = len(self._color_profiles_data), len(self._depth_profiles_data)
|
|
||||||
msg = f"已连接 SN: {sn} 彩色 {nc} 项 / 深度 {nd} 项"
|
|
||||||
style = f"color:#4aaa4a; font-size:{_fs(12)}px;"
|
|
||||||
self.device_status.setText(msg)
|
self.device_status.setText(msg)
|
||||||
self.device_status.setStyleSheet(style)
|
self.device_status.setStyleSheet(style)
|
||||||
self.d2c_device_status.setText(msg)
|
self.d2c_device_status.setText(msg)
|
||||||
self.d2c_device_status.setStyleSheet(style)
|
self.d2c_device_status.setStyleSheet(style)
|
||||||
|
self._refreshing = False
|
||||||
def _on_refresh_error(self, msg: str):
|
|
||||||
self.refresh_btn.setEnabled(True)
|
self.refresh_btn.setEnabled(True)
|
||||||
self.d2c_refresh_btn.setEnabled(True)
|
self.d2c_refresh_btn.setEnabled(True)
|
||||||
full = f"未找到设备:{msg}"
|
|
||||||
style = f"color:#cc6666; font-size:{_fs(12)}px;"
|
|
||||||
self.device_status.setText(full)
|
|
||||||
self.device_status.setStyleSheet(style)
|
|
||||||
self.d2c_device_status.setText(full)
|
|
||||||
self.d2c_device_status.setStyleSheet(style)
|
|
||||||
|
|
||||||
def _on_refresh_finished(self):
|
|
||||||
w = self._refresh_worker
|
|
||||||
self._refresh_worker = None
|
|
||||||
if w:
|
|
||||||
w.deleteLater()
|
|
||||||
|
|
||||||
# ─────────────────────────────────
|
# ─────────────────────────────────
|
||||||
# Stream Toggle
|
# Stream Toggle
|
||||||
|
|||||||
Reference in New Issue
Block a user