#!/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 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 "${DISPLAY:-}${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 "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]; then if command -v feh >/dev/null 2>&1 && [ -n "${DISPLAY:-}" ]; then feh --scale-down "$target_path" >/dev/null 2>&1 & elif command -v imv >/dev/null 2>&1; then imv "$target_path" >/dev/null 2>&1 & fi 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 if command -v feh >/dev/null 2>&1 && [ -n "${DISPLAY:-}" ]; then feh --scale-down "$pic_dir" >/dev/null 2>&1 & else imv "$pic_dir" >/dev/null 2>&1 & fi 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