Files
xuetang/app/packaging/runtime_media_smoke.py
2026-09-08 11:40:15 +08:00

86 lines
3.0 KiB
Python

"""Frozen-process gate for the Qt multimedia runtime.
PyInstaller executes this file as a runtime hook. Normal application starts
are untouched; ``--media-smoke-test`` exits before the application entry point
after proving that the frozen Qt multimedia modules and a decoder backend can
be loaded in an offscreen Qt event loop.
"""
from __future__ import annotations
import sys
MEDIA_SMOKE_ARGUMENT = "--media-smoke-test"
def _emit(message: str, *, error: bool = False) -> None:
# Windowed PyInstaller executables set stdout/stderr to None on Windows.
# The exit status is the gate contract; diagnostics are best-effort.
stream = sys.stderr if error else sys.stdout
if stream is not None:
print(message, file=stream, flush=True)
def _run_media_smoke_gate() -> None:
# Keep these imports inside the gate. Missing frozen extension modules or
# linked Qt multimedia libraries must make this process fail, while normal
# launches retain the application's existing fallback behaviour.
from PySide6.QtCore import QTimer
from PySide6.QtMultimedia import QAudioOutput, QMediaFormat, QMediaPlayer
from PySide6.QtMultimediaWidgets import QVideoWidget
from PySide6.QtWidgets import QApplication
application = QApplication.instance()
owns_application = application is None
if application is None:
application = QApplication(["DoctorWorkstationMediaSmoke"])
player = QMediaPlayer()
audio_output = QAudioOutput()
video_widget = QVideoWidget()
player.setAudioOutput(audio_output)
player.setVideoOutput(video_widget)
if not player.isAvailable():
raise RuntimeError("Qt reports that no multimedia backend is available")
decode_formats = QMediaFormat().supportedFileFormats(QMediaFormat.ConversionMode.Decode)
if not decode_formats:
raise RuntimeError("Qt multimedia loaded without a supported decoder format")
video_widget.resize(16, 16)
video_widget.show()
QTimer.singleShot(0, application.quit)
event_status = application.exec()
video_widget.close()
player.setVideoOutput(None)
player.setAudioOutput(None)
if event_status != 0:
raise RuntimeError(f"Qt multimedia offscreen event loop exited with {event_status}")
# QApplication cannot be recreated safely in-process. The runtime hook is
# a one-shot frozen gate, but retaining this distinction makes direct test
# imports predictable.
if owns_application:
application.processEvents()
def _dispatch() -> int | None:
if MEDIA_SMOKE_ARGUMENT not in sys.argv[1:]:
return None
try:
_run_media_smoke_gate()
except Exception as exc:
_emit(
f"Frozen Qt multimedia smoke gate failed: {type(exc).__name__}: {exc}",
error=True,
)
return 70
_emit("Frozen Qt multimedia smoke gate passed.")
return 0
_media_smoke_status = _dispatch()
if _media_smoke_status is not None:
raise SystemExit(_media_smoke_status)