From 4c02de5fd43bde631d7cf54367f94b67dde65673 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 21 Apr 2026 17:32:31 +0000 Subject: [PATCH] Overlay: yellow text, lower-right position; test-sunrise uses captured frames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - fontcolor: white → yellow (both scripts) - y position: (h-th)/2 → h-th-18 (vertically centered → lower-right corner) - test-sunrise.sh: reverted to reading last 60 frames from capture directory (~10 minutes at 10s interval) instead of live RTSP capture https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ --- daily_sunrise_video.sh | 4 +- test-sunrise.sh | 95 +++++++++++++++++++----------------------- 2 files changed, 44 insertions(+), 55 deletions(-) diff --git a/daily_sunrise_video.sh b/daily_sunrise_video.sh index 9463ae2..cbd525d 100644 --- a/daily_sunrise_video.sh +++ b/daily_sunrise_video.sh @@ -153,9 +153,9 @@ if [ "${SUNRISE_OVERLAY_ENABLED:-true}" = "true" ]; then else DT="drawtext=textfile='${temp_text}'" fi - DT="${DT}:fontcolor=white@${SUNRISE_OVERLAY_OPACITY}" + DT="${DT}:fontcolor=yellow@${SUNRISE_OVERLAY_OPACITY}" DT="${DT}:fontsize=h/22:line_spacing=4" - DT="${DT}:x=w-tw-18:y=(h-th)/2" + DT="${DT}:x=w-tw-18:y=h-th-18" DT="${DT}:shadowcolor=black@0.55:shadowx=1:shadowy=1" fi diff --git a/test-sunrise.sh b/test-sunrise.sh index 188fe2b..1a75c30 100755 --- a/test-sunrise.sh +++ b/test-sunrise.sh @@ -1,8 +1,8 @@ #!/bin/bash -# test-sunrise.sh — smoke-test the sunrise pipeline using freshly captured frames. +# test-sunrise.sh — smoke-test the sunrise pipeline using recent captured frames. # -# Captures NUM_FRAMES × CAPTURE_INTERVAL seconds of RTSP frames from SUNRISE_CAM, -# then runs the same 4-step pipeline as daily_sunrise_video.sh: +# Uses the last ~10 minutes of JPEGs from SUNRISE_CAM then runs the same +# 4-step pipeline as daily_sunrise_video.sh: # 1. raw video from captured JPEGs # 2. speed-adjust to SUNRISE_TARGET_SECS # 3. grab SUNRISE_TARGET_SECS of live RTSP audio @@ -10,7 +10,7 @@ # # Usage: # ./test-sunrise.sh [output_path] -# ./test-sunrise.sh ~/drives/data2-main/test2.mp4 +# ./test-sunrise.sh ~/drives/data2-main/test3.mp4 set -euo pipefail @@ -25,48 +25,23 @@ SUNRISE_OVERLAY_OPACITY="${SUNRISE_OVERLAY_OPACITY:-0.45}" OUTPUT="${1:-/tmp/sunrise-test.mp4}" CAM="$SUNRISE_CAM" -NUM_FRAMES=12 # ~2 minutes at 10s interval +TODAY=$(date +%Y-%m-%d) +image_dir="$BASE_DIR/$CAM/$TODAY" +NUM_FRAMES=60 # ~10 minutes at 10s interval -# ── RTSP URL ────────────────────────────────────────────────────────────────── -rtsp_var="CAM_RTSP_${CAM}" -RTSP_URL="${!rtsp_var:-}" -if [ -z "$RTSP_URL" ]; then - echo "ERROR: CAM_RTSP_${CAM} not set in .env" - echo " Add it: CAM_RTSP_${CAM}='rtsp://user:pass@ip:554/stream'" +# ── Collect frames ──────────────────────────────────────────────────────────── +if [ ! -d "$image_dir" ]; then + echo "ERROR: no frames today at $image_dir" + echo " Is capture.sh running? systemctl --user status sky-cam-capture-${CAM}.service" exit 1 fi -# ── Temp files ──────────────────────────────────────────────────────────────── -TMP_FRAME_DIR=$(mktemp -d --suffix=-sunrise-frames) -TMP_LIST=$(mktemp --suffix=.txt) -TMP_RAW=$(mktemp --suffix=.mp4) -TMP_SPED=$(mktemp --suffix=.mp4) -TMP_AUDIO=$(mktemp --suffix=.m4a) -TMP_TEXT=$(mktemp --suffix=.txt) -cleanup() { - rm -rf "$TMP_FRAME_DIR" - rm -f "$TMP_LIST" "$TMP_RAW" "$TMP_SPED" "$TMP_AUDIO" "$TMP_TEXT" 2>/dev/null || true -} -trap cleanup EXIT - -# ── Capture fresh frames ───────────────────────────────────────────────────── -CAPTURE_SECS=$(( NUM_FRAMES * ${CAPTURE_INTERVAL:-10} )) -echo "Capturing ${NUM_FRAMES} frames over ${CAPTURE_SECS}s from $CAM..." -ffmpeg -loglevel warning \ - -rtsp_transport tcp \ - -i "$RTSP_URL" \ - -t "$CAPTURE_SECS" \ - -vf "fps=1/${CAPTURE_INTERVAL:-10}" \ - -f image2 -strftime 1 \ - -q:v 2 \ - "${TMP_FRAME_DIR}/%H-%M-%S.jpg" || true - -mapfile -t frames < <(find "$TMP_FRAME_DIR" -name "*.jpg" | sort) +mapfile -t frames < <(find "$image_dir" -name "*.jpg" | sort | tail -n "$NUM_FRAMES") if [ "${#frames[@]}" -lt 1 ]; then - echo "ERROR: no frames captured from $CAM — check RTSP URL in .env" + echo "ERROR: no frames found in $image_dir" exit 1 fi -echo "Captured: ${#frames[@]} frames" +echo "Frames: ${#frames[@]} most-recent from $image_dir" # ── Mid-point frame → overlay time ─────────────────────────────────────────── mid_idx=$(( ${#frames[@]} / 2 )) @@ -75,6 +50,15 @@ mid_hms=$(basename "$mid_frame" .jpg) # HH-MM-SS MID_TIME=$(echo "$mid_hms" | cut -c1-5 | tr '-' ':') # HH:MM echo "Mid-point frame: $mid_hms → overlay time: $MID_TIME" +# ── Temp files ──────────────────────────────────────────────────────────────── +TMP_LIST=$(mktemp --suffix=.txt) +TMP_RAW=$(mktemp --suffix=.mp4) +TMP_SPED=$(mktemp --suffix=.mp4) +TMP_AUDIO=$(mktemp --suffix=.m4a) +TMP_TEXT=$(mktemp --suffix=.txt) +cleanup() { rm -f "$TMP_LIST" "$TMP_RAW" "$TMP_SPED" "$TMP_AUDIO" "$TMP_TEXT" 2>/dev/null || true; } +trap cleanup EXIT + # Write each character on its own line for drawtext's textfile option. # Avoids \n escape ambiguity across ffmpeg filter-string escaping levels. printf '%s\n%s\n%s\n%s\n%s' \ @@ -96,8 +80,7 @@ if [ -z "$FONT" ]; then fi # ── Write concat list ───────────────────────────────────────────────────────── -# Explicit duration per frame so raw video represents real elapsed time: -# 12 frames × CAPTURE_INTERVAL seconds = ~2 minutes. +# Explicit duration per frame so raw video represents real elapsed time. # The final entry needs a duplicate without duration (ffmpeg concat requirement). for f in "${frames[@]}"; do printf "file '%s'\nduration %s\n" "$f" "${CAPTURE_INTERVAL:-10}" @@ -125,20 +108,26 @@ ffmpeg -loglevel warning \ -t "$SUNRISE_TARGET_SECS" \ -y "$TMP_SPED" -# ── Step 3: grab audio centred on mid-point ──────────────────────────────────── +# ── Step 3: grab audio ──────────────────────────────────────────────────────── echo "Step 3/4: recording ${SUNRISE_TARGET_SECS}s of live audio from camera..." +rtsp_var="CAM_RTSP_${CAM}" +RTSP_URL="${!rtsp_var:-}" HAS_AUDIO=false -if ffmpeg -loglevel warning \ - -rtsp_transport tcp \ - -i "$RTSP_URL" \ - -t "$SUNRISE_TARGET_SECS" \ - -vn -c:a aac -b:a 64k \ - -y "$TMP_AUDIO"; then - HAS_AUDIO=true - echo " Audio: captured OK" +if [ -n "$RTSP_URL" ]; then + if ffmpeg -loglevel warning \ + -rtsp_transport tcp \ + -i "$RTSP_URL" \ + -t "$SUNRISE_TARGET_SECS" \ + -vn -c:a aac -b:a 64k \ + -y "$TMP_AUDIO"; then + HAS_AUDIO=true + echo " Audio: captured OK" + else + echo " Audio: capture failed — continuing without audio" + fi else - echo " Audio: capture failed — continuing without audio" + echo " Audio: CAM_RTSP_${CAM} not set — skipping" fi # ── Step 4: mix audio + burn overlay ───────────────────────────────────────── @@ -151,9 +140,9 @@ if [ -n "$FONT" ]; then else DT="drawtext=textfile='${TMP_TEXT}'" fi -DT="${DT}:fontcolor=white@${SUNRISE_OVERLAY_OPACITY}" +DT="${DT}:fontcolor=yellow@${SUNRISE_OVERLAY_OPACITY}" DT="${DT}:fontsize=h/22:line_spacing=4" -DT="${DT}:x=w-tw-18:y=(h-th)/2" +DT="${DT}:x=w-tw-18:y=h-th-18" DT="${DT}:shadowcolor=black@0.55:shadowx=1:shadowy=1" if $HAS_AUDIO; then