diff --git a/4-seasons.sh b/4-seasons.sh index 344ada0..e4c9a6f 100755 --- a/4-seasons.sh +++ b/4-seasons.sh @@ -87,17 +87,36 @@ cleanup() { rm -f "$temp_file" "$temp_video" 2>/dev/null || true; } trap cleanup EXIT mapfile -t all_images < <(find "$image_dir" -type f -name "*.jpg" | sort) -images=() -bad=0 + +# Validate each frame: skip empty files, corrupt JPEGs, and optionally grey/uniform frames. +# SEASONS_GREY_STDDEV_MIN=0 (default) disables the grey filter. +# Set to e.g. 5 in sky-cam.conf to drop uniform grey frames (bad-signal captures). +GREY_MIN="${SEASONS_GREY_STDDEV_MIN:-0}" +images=(); bad=0; grey=0 for img in "${all_images[@]}"; do - if [ -r "$img" ] && [ -s "$img" ]; then - images+=("$img") - else - echo "WARNING: skipping unreadable/empty frame: $img" - ((bad++)) || true + # Empty or unreadable + if [ ! -r "$img" ] || [ ! -s "$img" ]; then + echo "WARNING: skipping empty/missing frame: $(basename "$img")" + ((bad++)) || true; continue fi + # Corrupt JPEG — ffprobe can't identify any video stream + if ! ffprobe -v quiet -select_streams v:0 \ + -show_entries stream=codec_name -of csv=p=0 "$img" 2>/dev/null \ + | grep -q .; then + echo "WARNING: skipping corrupt frame: $(basename "$img")" + ((bad++)) || true; continue + fi + # Optional: skip uniform-grey bad-signal frames (low pixel standard deviation) + if [ "$GREY_MIN" != "0" ] && command -v convert &>/dev/null; then + stddev=$(convert "$img" -colorspace Gray -format "%[fx:int(standard_deviation*255)]" info: 2>/dev/null || echo "255") + if [ "${stddev:-255}" -lt "$GREY_MIN" ]; then + ((grey++)) || true; continue + fi + fi + images+=("$img") done -[ "$bad" -gt 0 ] && echo "WARNING: skipped $bad bad frame(s) out of ${#all_images[@]} found" +[ "$bad" -gt 0 ] && echo "WARNING: skipped $bad corrupt/empty frame(s) of ${#all_images[@]}" +[ "$grey" -gt 0 ] && echo "INFO: skipped $grey grey/uniform frame(s) (SEASONS_GREY_STDDEV_MIN=${GREY_MIN})" for img in "${images[@]}"; do printf "file '%s'\nduration %s\n" "$img" "$INTERVAL" diff --git a/sky-cam.conf b/sky-cam.conf index e617e29..04d3b2c 100644 --- a/sky-cam.conf +++ b/sky-cam.conf @@ -255,6 +255,16 @@ CRF_MONTAGE_FINAL=22 # montage-mvt.sh — final archive montage (H ENCODE_PRESET=slow # ffmpeg preset for all encodes (slow/medium/fast) AUDIO_BITRATE=192k # montage-mvt.sh — music track on movement montages +# ── Frame validation (4-seasons.sh) ────────────────────────────────────────── +# Corrupt or empty frames (e.g. first frame after a camera reconnect) are always +# skipped automatically via ffprobe. +# +# SEASONS_GREY_STDDEV_MIN: also skip uniform-grey frames caused by a bad RTSP +# signal. These are valid JPEGs but contain a near-solid grey image. +# Value is the minimum pixel standard deviation on a 0–255 scale. +# 0 = disabled (default). Try 5–10 if your camera produces grey frames on reconnect. +SEASONS_GREY_STDDEV_MIN=0 + # ── Montage attribution overlay ─────────────────────────────────────────────── # A translucent bar across the top of each movement montage, naming the # music source ("The Four Seasons — Antonio Vivaldi ...").