fix(studio): 回放视图加一个无条件「停止」(Esc 同效),并让「文件一帧都不出」直接报错而不是一直等
- What: `ToolbarWidget` 新增 `set_reset_role("reset"/"stop")`,回放视图把轨道第二个按钮变成「停止」;
`StudioMainWindow._stop_replay_activity()` 一次停掉回放(play_timer)与「从视频重算」通道(worker),
并清掉三维面板上的重算画面,状态栏说明"已停止了什么";`_on_reset`/`_on_stop_shortcut`(Esc) 按角色路由;
`_start_playback`/`_pause_playback` 结束时调用 `_update_run_enabled()`,让停止按钮在有东西可停时才可用;
两个采集 worker 新增 `FILE_FIRST_FRAME_TIMEOUT_S=10s`:文件源一帧都没出来就报错结束会话
(原先 `saw_frame` 为假时 EOF 分支永不执行,循环空转到天荒地老、窗口一直停在"连接中")。
- Why: 用户报告"视频播放完之后无法再次按回放,卡住了",并建议加手动停止。复现得到两种状态:
① 普通回放播到末尾后再按回放**是可以**重新从头播的(探针实测 0.967→0→0.371,计时器在跑),
不是这条路径的问题;② 「从视频重算」通道跑文件时,工作线程可能既不出帧也不结束
(实测:1.5 s 的合成视频跑 25 s,packets=0 且 is_running=True),于是界面永远停在运行/连接状态,
操作者看到"卡住"。所以既给一个无论什么状态都能按的停止,也让"读不出帧"变成一条明确的错误。
- Verification: 新增/更新用例:`test_worker_frame_rate.py` 的"文件一帧都不出→error+消息"(缩短时限跑,
真实 worker);`test_ui_smoke.py` 三项:回放视图的停止按钮(播放中可用、按下停回放、重算中停下重算、
无事可停时说明)、Esc 同样能停、实时视图仍是「重置」;apps/studio 全量通过;shared 全量通过;
ui_check 583 项 0 失败(新增回放停止的 5 项检查,并给"场景已加载却仍在显示消息"那条加了诊断细节,
它此前偶发失败过一次、这次跑通)。
- Not in this change: 普通回放"播到末尾→再按回放"的路径(实测正常,未改);让回放直接播放"非记录"的视频
(仍走「从视频重算」);`_recompute_running` 与 worker 真实状态的进一步合并(现在停止按钮同时看两者)。
This commit is contained in:
@@ -373,6 +373,43 @@ def test_a_file_source_runs_on_the_video_s_own_timeline():
|
||||
)
|
||||
|
||||
|
||||
def test_a_file_that_yields_no_frames_ends_the_session_with_an_error(monkeypatch):
|
||||
"""A video this build cannot decode must report it, not wait forever.
|
||||
|
||||
The end-of-file branch needs at least one frame to have arrived (``saw_frame``),
|
||||
so a file that never produces one used to leave the loop spinning: no frames, no
|
||||
error, and the window in "connecting" until somebody pressed Stop. The shipping
|
||||
deadline is ten seconds; it is shortened here, because the point is the behaviour
|
||||
rather than the wait.
|
||||
"""
|
||||
import orisys_app_shared.acquisition.sdk_worker as worker_module
|
||||
|
||||
monkeypatch.setattr(worker_module, "FILE_FIRST_FRAME_TIMEOUT_S", 0.3)
|
||||
# A sensor that never produces a frame: what an unreadable codec looks like.
|
||||
monkeypatch.setattr(_Sensor, "get_img", lambda self: None)
|
||||
|
||||
CREATED.clear()
|
||||
saved = _install()
|
||||
errors: list = []
|
||||
packets: list = []
|
||||
worker = worker_module.SdkAcquisitionWorker(on_error=errors.append)
|
||||
try:
|
||||
worker.add_sink(packets.append)
|
||||
worker.start("unreadable.mp4", config_ref=BOX_CONFIG)
|
||||
deadline = time.perf_counter() + 10.0
|
||||
while time.perf_counter() < deadline and worker.is_running:
|
||||
time.sleep(0.05)
|
||||
assert not worker.is_running, (
|
||||
"the worker is still running on a file that produced no frames"
|
||||
)
|
||||
assert worker.consume_end_reason() == "error", worker.consume_end_reason()
|
||||
assert packets == []
|
||||
assert errors and "no frames" in errors[0], errors
|
||||
finally:
|
||||
worker.stop(wait=True)
|
||||
_restore(saved)
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover - manual runner
|
||||
failures = 0
|
||||
for name, function in sorted(globals().items()):
|
||||
|
||||
Reference in New Issue
Block a user