Skip to content

feat: add play control button for local video playing - #67

Merged
creeper5820 merged 1 commit into
mainfrom
feat/local-video-control
Jul 6, 2026
Merged

feat: add play control button for local video playing#67
creeper5820 merged 1 commit into
mainfrom
feat/local-video-control

Conversation

@creeper5820

@creeper5820 creeper5820 commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

本次变更为本地视频播放补充了完整的控制链路,并同步更新前后端交互。

主要内容:

  • src/module/capturer/local_video.cpp 重构本地视频读取与控制逻辑,移除终端按键轮询方式,改为通过后台服务线程管理播放/暂停与逐帧控制;新增帧步进读取、latest_image 同步缓存及相关并发保护。
  • tool/res/start-streamer 扩展服务端接口,新增 /api/play_pause/api/step_forward/api/step_backward,将播放控制请求写入对应 FIFO;同时调整 context 读取逻辑,合并本地视频与录制状态信息。
  • tool/res/playing.html 增加本地视频控制按钮与交互状态展示,支持上一帧、播放/暂停、下一帧操作,并根据 local_video 状态动态启用/禁用按钮。

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

本次改动重构了本地视频捕获器的播放控制机制:将基于终端按键轮询的实现替换为基于 jthread 的后台服务线程,支持播放/暂停/步进;同时在 Web 播放页面新增对应的控制按钮与状态同步逻辑,并在 streamer 脚本中扩展 FIFO 路由与上下文读取以支持这些新接口。

Changes

本地视频播放控制

Layer / File(s) Summary
Capturer 数据结构与后台服务实现
src/module/capturer/local_video.cpp
重构 Impl 成员移除终端 raw mode 状态,新增 jthread 后台线程、step_frame_locked 帧步进函数、start_service/stop_service 控制循环处理 play_pause/step_forward/step_backward 动作。
configure/disconnect/wait_image 集成
src/module/capturer/local_video.cpp
configure() 计算目标帧率并启动后台服务;disconnect() 先停止后台服务再重置状态;wait_image() 在互斥锁保护下读写 latest_image,避免并发竞态。
播放控制页面 UI 与状态同步
tool/res/playing.html
新增播放控制按钮布局与面板(prev/暂停/next)、DOM 引用与点击事件、sendPlaybackCommand 封装 POST 请求,以及 fetchRecordContext 根据 source/playing 推导并更新按钮状态。
Streamer FIFO 路由与上下文读取
tool/res/start-streamer
新增 play_pause/step_forward/step_backward 的 FIFO 路径常量与路由;write_to_fifo 泛化为接收任意路径与值;readContext 扩展为读取多个上下文文件并合并字段;简化启动信息输出。

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant WebUI as playing.html
  participant Streamer as start-streamer
  participant FIFO
  participant Capturer as LocalVideo::Impl

  User->>WebUI: 点击播放/暂停按钮
  WebUI->>Streamer: POST /api/play_pause
  Streamer->>FIFO: 写入 fifoPlayPause
  FIFO->>Capturer: 后台服务读取动作
  Capturer->>Capturer: 切换 playing 状态
  Capturer-->>WebUI: 更新 latest_image(供轮询读取)
  WebUI->>Streamer: GET /api/context
  Streamer-->>WebUI: 返回 source/playing 状态
  WebUI->>WebUI: updatePlaybackButtons() 刷新按钮文案
Loading

Poem

小兔敲键盘,帧帧不再等,
线程后台跑,暂停播放灵,
网页按钮亮,前后一步轻,
FIFO 传心意,画面稳如萍。
🐇✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题与本次本地视频播放控制相关,虽未概括后端接口与状态同步等全部改动,但能准确反映主要方向。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/local-video-control

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/module/capturer/local_video.cpp (2)

138-143: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

重入配置前先停掉旧 service 线程。

Line 138 每次 configure() 都会启动后台线程,Line 143 又允许 connect() 重新进入 configure(config)。如果已有 service 正在运行,旧回调可能在新 capturer 构建和状态重置期间继续访问共享状态。建议在 location 校验通过后、capturer.emplace(...) 前调用 stop_service()

建议修复
         if (_config.location.empty() || !std::filesystem::exists(_config.location)) {
             return std::unexpected { "Local video is not found or location is empty" };
         }
 
+        stop_service();
+
         config = _config;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/module/capturer/local_video.cpp` around lines 138 - 143, `configure()`
can be re-entered through `connect()`, which may start a new background service
while an old one is still running and touching shared state. Update `configure`
in `local_video.cpp` so that, after the location check succeeds and before
`capturer.emplace(...)`, it first calls `stop_service()` to shut down any
existing service thread. Use the `configure`, `connect`, `start_service`, and
`stop_service` symbols to place the fix correctly.

165-173: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

allow_skipping=true 时需要实际跳过落后的帧。

当前落后时只是把 last_read_time 调到 Clock::now(),但 capturer 仍然只读取下一帧;处理耗时高于帧间隔时,本地视频会降速播放而不是追赶。建议按 -wait_duration / interval_duration 计算应跳过的帧数,并在读取前 seek 到对应帧;allow_skipping=false 则继续严格逐帧读取。

Based on learnings: 在 src/module/capturer 中,allow_skipping=false 应严格顺序播放所有帧,allow_skipping=true 应保持预期播放速率并在落后时追赶,且两种模式都应有测试覆盖。

Also applies to: 186-190

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/module/capturer/local_video.cpp` around lines 165 - 173, In
local_video.cpp, the allow_skipping path in the capturer still only advances
last_read_time and does not actually skip any frames, so a slow capture will
drift instead of catching up. Update the read logic around the
time_before_read/next_read_time_expected wait_duration check to compute how many
frames were missed, seek the source to the correct frame before reading, and
keep strict sequential reads when config.allow_skipping is false. Add or adjust
tests for the local video capturer behavior in both modes.

Source: Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/module/capturer/local_video.cpp`:
- Around line 40-51: `step_frame_locked()` and `wait_image()` are touching the
same `cv::VideoCapture` without serialization, so their `read`/`set` operations
can interleave and corrupt frame position. Add a shared mutex around all
`capturer` access in these paths, or introduce a dedicated `capturer_mutex`, and
make sure both the seeking logic in `step_frame_locked()` and the capture loop
in `wait_image()` use the same lock before calling `read()` or `set()`.

In `@tool/res/playing.html`:
- Around line 448-454: `sendPlaybackCommand()` only catches network errors and
still treats `4xx/5xx` responses as success; update this helper to inspect the
`fetch` response and throw or log when `response.ok` is false so FIFO write
failures are not silently swallowed. Keep the existing `console.error` path for
failures, and if needed in the same success/failure flow, trigger
`fetchRecordContext()` after the playback command to reduce UI lag while the 1s
polling continues to refresh state.

---

Outside diff comments:
In `@src/module/capturer/local_video.cpp`:
- Around line 138-143: `configure()` can be re-entered through `connect()`,
which may start a new background service while an old one is still running and
touching shared state. Update `configure` in `local_video.cpp` so that, after
the location check succeeds and before `capturer.emplace(...)`, it first calls
`stop_service()` to shut down any existing service thread. Use the `configure`,
`connect`, `start_service`, and `stop_service` symbols to place the fix
correctly.
- Around line 165-173: In local_video.cpp, the allow_skipping path in the
capturer still only advances last_read_time and does not actually skip any
frames, so a slow capture will drift instead of catching up. Update the read
logic around the time_before_read/next_read_time_expected wait_duration check to
compute how many frames were missed, seek the source to the correct frame before
reading, and keep strict sequential reads when config.allow_skipping is false.
Add or adjust tests for the local video capturer behavior in both modes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7ff34f1b-e3d4-424a-8e9c-6b0bed053f91

📥 Commits

Reviewing files that changed from the base of the PR and between 2307f67 and ee0d2f2.

📒 Files selected for processing (3)
  • src/module/capturer/local_video.cpp
  • tool/res/playing.html
  • tool/res/start-streamer

Comment on lines +40 to +51
auto step_frame_locked(int offset) -> void {
if (!capturer.has_value()) return;

auto frame = cv::Mat { };
if (offset < 0) {
const auto pos = static_cast<int>(capturer->get(cv::CAP_PROP_POS_FRAMES));
if (pos < 2) return;
capturer->set(cv::CAP_PROP_POS_FRAMES, pos - 2);
if (!capturer->read(frame) || frame.empty()) return;
} else {
if (!capturer->read(frame) || frame.empty()) return;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# 核对 local_video.cpp 中所有 capturer 访问点是否都处在同一互斥保护策略下。
rg -nP 'capturer(->|\.)?(read|set|get|reset|emplace|has_value|isOpened)?' src/module/capturer/local_video.cpp -C 3

Repository: Alliance-Algorithm/rmcs_auto_aim_v2

Length of output: 2767


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 读取 local_video.cpp 相关区段,确认 capturer 与 mutex 的实际保护范围
sed -n '1,240p' src/module/capturer/local_video.cpp | cat -n

Repository: Alliance-Algorithm/rmcs_auto_aim_v2

Length of output: 9712


用同一把锁串行化 capturer 访问。
step_frame_locked()wait_image() 都在读写同一个 cv::VideoCapture,但现在只保护了 latest_imagewait_image() 里的 read/set 仍可能和步进回调交错,导致帧位置和返回图像不稳定。把 capturer 的定位/读取也纳入同一临界区,或单独引入 capturer_mutex

🧰 Tools
🪛 Cppcheck (2.21.0)

[error] 41-41: Found an exit path from function with non-void return type that has missing return statement

(missingReturn)


[error] 47-47: Found an exit path from function with non-void return type that has missing return statement

(missingReturn)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/module/capturer/local_video.cpp` around lines 40 - 51,
`step_frame_locked()` and `wait_image()` are touching the same
`cv::VideoCapture` without serialization, so their `read`/`set` operations can
interleave and corrupt frame position. Add a shared mutex around all `capturer`
access in these paths, or introduce a dedicated `capturer_mutex`, and make sure
both the seeking logic in `step_frame_locked()` and the capture loop in
`wait_image()` use the same lock before calling `read()` or `set()`.

Comment thread tool/res/playing.html
Comment on lines +448 to +454
async function sendPlaybackCommand(url) {
try {
await fetch(url, { method: 'POST', body: '1' });
} catch (error) {
console.error('Playback command failed:', error);
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

sed -n '400,520p' tool/res/playing.html

Repository: Alliance-Algorithm/rmcs_auto_aim_v2

Length of output: 4862


🏁 Script executed:

rg -n "fetchRecordContext|setInterval|sendPlaybackCommand|updatePlaybackButtons|isPlaying|isLocalVideo" tool/res/playing.html

Repository: Alliance-Algorithm/rmcs_auto_aim_v2

Length of output: 1358


🏁 Script executed:

sed -n '740,785p' tool/res/playing.html

Repository: Alliance-Algorithm/rmcs_auto_aim_v2

Length of output: 1286


补上 fetch 的 HTTP 状态检查 tool/res/playing.html:448-454

sendPlaybackCommand() 现在只会捕获网络异常,4xx/5xx 仍会被当作成功处理,FIFO 写入失败会被静默吞掉。这里应在 response.okfalse 时显式报错;状态刷新本身已由现有的 1s 轮询覆盖,必要时再额外触发一次 fetchRecordContext() 以减少点击后的 UI 延迟。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tool/res/playing.html` around lines 448 - 454, `sendPlaybackCommand()` only
catches network errors and still treats `4xx/5xx` responses as success; update
this helper to inspect the `fetch` response and throw or log when `response.ok`
is false so FIFO write failures are not silently swallowed. Keep the existing
`console.error` path for failures, and if needed in the same success/failure
flow, trigger `fetchRecordContext()` after the playback command to reduce UI lag
while the 1s polling continues to refresh state.

@creeper5820
creeper5820 merged commit c6c25b1 into main Jul 6, 2026
2 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in RMCS Auto Aim V2 Jul 6, 2026
@creeper5820
creeper5820 deleted the feat/local-video-control branch July 6, 2026 17:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant