feat(camera): add bananarchy-photo CLI, Sxmo menu integration, and multi-capture ISPIF/VFE0 reset

This commit is contained in:
Luxferre
2026-10-19 23:51:09 +03:00
parent a14a7aa543
commit ad012360c3
10 changed files with 322 additions and 52 deletions
+187
View File
@@ -0,0 +1,187 @@
#!/bin/sh
# Bananarchy rear camera photo capture utility and Sxmo menu wrapper
# Captures 800x600 24-bit RGB frames from /dev/video0 (msm8905-cam / GC2395)
# via v4l2-ctl and encodes JPEG/PNG images via ffmpeg -f rawvideo.
set -eu
DEV="/dev/video0"
USE_FLASH=0
VIEW_AFTER=0
MENU_MODE=0
OUT_FILE=""
usage() {
cat <<'EOF'
Usage: bananarchy-photo [options] [output_file]
Options:
-d, --device <dev> V4L2 video device (default: /dev/video0)
-f, --flash Enable rear flashlight (white:torch) during capture
-v, --view Open captured photo in imv after saving
-m, --menu Open interactive Sxmo camera menu
-h, --help Show this help message
If output_file is omitted, saves to ~/Pictures/photo-YYYYMMDD-HHMMSS.jpg.
EOF
}
while [ $# -gt 0 ]; do
case "$1" in
-d|--device)
DEV="$2"
shift 2
;;
-f|--flash)
USE_FLASH=1
shift
;;
-v|--view)
VIEW_AFTER=1
shift
;;
-m|--menu)
MENU_MODE=1
shift
;;
-h|--help)
usage
exit 0
;;
--)
shift
break
;;
-*)
echo "bananarchy-photo: unknown option: $1" >&2
usage >&2
exit 1
;;
*)
OUT_FILE="$1"
shift
;;
esac
done
if [ $# -gt 0 ] && [ -z "$OUT_FILE" ]; then
OUT_FILE="$1"
fi
get_pictures_dir() {
pic_dir="${XDG_PICTURES_DIR:-$HOME/Pictures}"
mkdir -p "$pic_dir"
printf "%s\n" "$pic_dir"
}
notify_msg() {
if command -v sxmo_notify_user.sh >/dev/null 2>&1 && [ -n "${WAYLAND_DISPLAY:-}" ]; then
sxmo_notify_user.sh -t 2000 "$1" >/dev/null 2>&1 || true
fi
}
take_photo() {
flash_flag="$1"
target_path="$2"
if [ -z "$target_path" ]; then
pic_dir="$(get_pictures_dir)"
target_path="$pic_dir/photo-$(date +%Y%m%d-%H%M%S).jpg"
else
mkdir -p "$(dirname "$target_path")"
fi
if [ ! -e "$DEV" ]; then
echo "bananarchy-photo: camera device $DEV not found" >&2
notify_msg "Camera $DEV not found"
return 1
fi
prev_torch=""
if [ "$flash_flag" -eq 1 ] && [ -w /sys/class/leds/white:torch/brightness ]; then
prev_torch="$(cat /sys/class/leds/white:torch/brightness 2>/dev/null || echo 0)"
echo 1 > /sys/class/leds/white:torch/brightness 2>/dev/null || true
sleep 0.15
fi
frame_tmp="/tmp/bananarchy-frame-$$.rgb"
rc=0
v4l2-ctl -d "$DEV" \
--set-fmt-video=width=800,height=600,pixelformat=RGB3 \
--stream-mmap --stream-count=1 --stream-to="$frame_tmp" >/dev/null 2>&1 || rc=$?
if [ "$flash_flag" -eq 1 ] && [ -n "$prev_torch" ] && [ -w /sys/class/leds/white:torch/brightness ]; then
echo "$prev_torch" > /sys/class/leds/white:torch/brightness 2>/dev/null || true
fi
if [ "$rc" -ne 0 ] || [ ! -s "$frame_tmp" ]; then
rm -f "$frame_tmp"
echo "bananarchy-photo: failed to capture frame from $DEV" >&2
notify_msg "Photo capture failed"
return 1
fi
if ! ffmpeg -hide_banner -loglevel error \
-f rawvideo -pixel_format rgb24 -video_size 800x600 \
-i "$frame_tmp" -frames:v 1 -y "$target_path"; then
rm -f "$frame_tmp"
echo "bananarchy-photo: ffmpeg failed to encode $target_path" >&2
notify_msg "Photo encoding failed"
return 1
fi
rm -f "$frame_tmp"
printf "%s\n" "$target_path"
notify_msg "Saved $(basename "$target_path")"
if [ "$VIEW_AFTER" -eq 1 ] && [ -n "${WAYLAND_DISPLAY:-}" ] && command -v imv >/dev/null 2>&1; then
imv "$target_path" >/dev/null 2>&1 &
fi
return 0
}
run_menu() {
if [ -f /usr/share/sxmo/default_hooks/sxmo_hook_icons.sh ]; then
# shellcheck disable=SC1091
. /usr/share/sxmo/default_hooks/sxmo_hook_icons.sh
fi
ic_cam="${icon_cam:-*}"
ic_fll="${icon_fll:-*}"
ic_img="${icon_img:-*}"
ic_cls="${icon_cls:-x}"
choice="$(printf "%s\n" \
"$ic_cam Take photo" \
"$ic_fll Take photo (flash)" \
"$ic_img View photos" \
"$ic_cls Close" | sxmo_dmenu.sh -p "Camera" || true)"
case "$choice" in
*"Take photo (flash)"*)
VIEW_AFTER=1
take_photo 1 ""
;;
*"Take photo"*)
VIEW_AFTER=1
take_photo 0 ""
;;
*"View photos"*)
pic_dir="$(get_pictures_dir)"
if ls "$pic_dir"/*.jpg "$pic_dir"/*.png >/dev/null 2>&1; then
imv "$pic_dir" >/dev/null 2>&1 &
else
notify_msg "No photos in $pic_dir"
fi
;;
*)
exit 0
;;
esac
}
if [ "$MENU_MODE" -eq 1 ]; then
run_menu
else
take_photo "$USE_FLASH" "$OUT_FILE"
fi