| 237 | } |
| 238 | |
| 239 | static void decode_and_track(vapp_state& app, int fi) { |
| 240 | app.frame = sam3_decode_video_frame(app.video_path, fi); |
| 241 | if (app.frame.data.empty()) { |
| 242 | snprintf(app.status, sizeof(app.status), "Failed to decode frame %d.", fi); |
| 243 | app.playing = false; |
| 244 | return; |
| 245 | } |
| 246 | app.frame_index = fi; |
| 247 | |
| 248 | if (app.tracker_created) { |
| 249 | if (app.visual_only) |
| 250 | app.result = sam3_propagate_frame(*app.tracker, *app.state, *app.model, app.frame); |
| 251 | else |
| 252 | app.result = sam3_track_frame(*app.tracker, *app.state, *app.model, app.frame); |
| 253 | app.frame_encoded = true; |
| 254 | |
| 255 | // Record instance presence in timeline |
| 256 | if (fi >= (int)app.timeline.size()) |
| 257 | app.timeline.resize(fi + 1); |
| 258 | app.timeline[fi].instances.clear(); |
| 259 | for (const auto& det : app.result.detections) |
| 260 | app.timeline[fi].instances.push_back({det.instance_id, det.score}); |
| 261 | if (fi > app.timeline_max_frame) app.timeline_max_frame = fi; |
| 262 | |
| 263 | snprintf(app.status, sizeof(app.status), "Frame %d/%d — %d objects tracked", |
| 264 | fi, app.video_info.n_frames, (int)app.result.detections.size()); |
| 265 | } else { |
| 266 | // Just encode and show the frame without tracking |
| 267 | sam3_encode_image(*app.state, *app.model, app.frame); |
| 268 | app.frame_encoded = true; |
| 269 | app.result = {}; |
| 270 | snprintf(app.status, sizeof(app.status), "Frame %d/%d — no tracker active", |
| 271 | fi, app.video_info.n_frames); |
| 272 | } |
| 273 | } |
| 274 | |
| 275 | // Check if a click position lands on any tracked instance mask. |
| 276 | // Returns the instance_id or -1. |
no test coverage detected