diff --git a/src/api/media_api.rs b/src/api/media_api.rs index 247a812..9d30dba 100644 --- a/src/api/media_api.rs +++ b/src/api/media_api.rs @@ -323,10 +323,10 @@ async fn trace_video( let start_fn = (start_sec * fps) as i32; let end_fn = (start_sec + duration) as i32; - // Query all traces with identity names in the visible frame range + // Query all traces with identity names and bbox positions in the visible frame range let identities_table = schema::table_name("identities"); - let all_rows: Vec<(i32, i32, Option)> = sqlx::query_as(&format!( - "SELECT fd.trace_id, fd.frame_number, i.name \ + let all_rows: Vec<(i32, i32, i32, i32, i32, i32, Option)> = sqlx::query_as(&format!( + "SELECT fd.trace_id, fd.frame_number, fd.x, fd.y, fd.width, fd.height, i.name \ FROM {} fd \ LEFT JOIN {} i ON fd.identity_id = i.id \ WHERE fd.file_uuid = $1 AND fd.frame_number BETWEEN $2 AND $3 AND fd.trace_id IS NOT NULL \ @@ -337,12 +337,14 @@ async fn trace_video( .fetch_all(state.db.pool()).await .unwrap_or_default(); - // Group frames by trace_id, compute start_frame per trace + // Group frames by trace_id, compute start_frame per trace; collect bbox per frame use std::collections::HashMap; let mut trace_frames: HashMap> = HashMap::new(); let mut trace_identity: HashMap = HashMap::new(); - for (tid, fn_, name_opt) in &all_rows { + let mut bbox_per_frame: HashMap<(i32, i32), (i32, i32, i32, i32)> = HashMap::new(); // (tid, fn) -> (x, y, w, h) + for (tid, fn_, x, y, w, h, name_opt) in &all_rows { trace_frames.entry(*tid).or_default().push(*fn_); + bbox_per_frame.insert((*tid, *fn_), (*x, *y, *w, *h)); if let Some(name) = name_opt { trace_identity.entry(*tid).or_insert_with(|| name.clone()); } else { @@ -400,6 +402,23 @@ async fn trace_video( y_pos += 22; } + // Green thin bounding boxes with trace_id label for each face detection + for (tid, frames) in &sorted_traces { + for fn_ in frames.iter() { + if let Some((x, y, w, h)) = bbox_per_frame.get(&(*tid, *fn_)) { + let n = *fn_ as i64 - frame_offset; + parts.push(format!( + "drawbox=x={}:y={}:w={}:h={}:color=green@0.7:thickness=2:enable='between(n,{},{})'", + x, y, w, h, n, n + )); + parts.push(format!( + "drawtext=text='{}':x={}:y={}:fontsize=16:fontcolor=green:box=1:boxcolor=black@0.5:enable='between(n,{},{})'", + tid, x + 2, y + 2, n, n + )); + } + } + } + let filter_text = parts.join(","); let filter_file = std::env::temp_dir().join(format!("vf_{}.txt", uuid::Uuid::new_v4())); let _ = std::fs::write(&filter_file, &filter_text);