feat(camera): add bananarchy-photo CLI, Sxmo menu integration, and multi-capture ISPIF/VFE0 reset
This commit is contained in:
Executable
+187
@@ -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
|
||||
@@ -0,0 +1,8 @@
|
||||
[Desktop Entry]
|
||||
Name=Camera
|
||||
Comment=Bananarchy rear camera photo capture
|
||||
Exec=bananarchy-photo --menu
|
||||
Icon=camera-photo
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Graphics;Photography;
|
||||
@@ -38,6 +38,7 @@ write_line_app badwolf "$icon_glb Badwolf" "badwolf"
|
||||
write_line_app baobab "$icon_pie Baobab" "baobab"
|
||||
write_line_app bluetuith "$icon_bth Bluetuith" "sxmo_terminal.sh bluetuith"
|
||||
write_line_app calcurse "$icon_clk Calcurse" "sxmo_terminal.sh calcurse"
|
||||
write_line_app bananarchy-photo "$icon_cam Camera" "bananarchy-photo --menu"
|
||||
write_line_app celluloid "$icon_mvi Celluloid" "celluloid"
|
||||
write_line_app chatty "$icon_msg Chatty" "chatty"
|
||||
([ -z "$WAYLAND_DISPLAY" ] && command -v clipmenu >/dev/null) && \
|
||||
|
||||
@@ -180,13 +180,14 @@ case "$WMCLASS" in
|
||||
*imv*)
|
||||
# imv
|
||||
CHOICES="
|
||||
$icon_arr Next ^ 1 ^ sxmo_type -k Right
|
||||
$icon_arl Previous ^ 1 ^ sxmo_type -k Left
|
||||
$icon_zmi Zoom in ^ 1 ^ sxmo_type -k i
|
||||
$icon_zmo Zoom out ^ 1 ^ sxmo_type -k minus
|
||||
$icon_exp Zoom to fit ^ 1 ^ sxmo_type -k r
|
||||
$icon_ror Rotate ^ 1 ^ sxmo_type -M ctrl r
|
||||
$icon_inf Toggle filename ^ 1 ^ sxmo_type -k d
|
||||
$icon_arr Next ^ 1 ^ sxmo_type.sh -k Right
|
||||
$icon_arl Previous ^ 1 ^ sxmo_type.sh -k Left
|
||||
$icon_zmi Zoom in ^ 1 ^ sxmo_type.sh -k i
|
||||
$icon_zmo Zoom out ^ 1 ^ sxmo_type.sh -k minus
|
||||
$icon_exp Zoom to fit ^ 1 ^ sxmo_type.sh -k r
|
||||
$icon_ror Rotate ^ 1 ^ sxmo_type.sh -M ctrl r
|
||||
$icon_inf Toggle filename ^ 1 ^ sxmo_type.sh -k d
|
||||
$icon_cls Quit ^ 0 ^ sxmo_type.sh -k q
|
||||
"
|
||||
WINNAME=Imv
|
||||
;;
|
||||
@@ -818,7 +819,13 @@ case "$WMCLASS" in
|
||||
rfkill list bluetooth -no ID,SOFT,HARD | grep -vq " blocked" &&
|
||||
printf %b "$icon_bth Bluetooth ^ 1 ^ sxmo_bluetoothmenu.sh"
|
||||
)
|
||||
$(command -v megapixels >/dev/null && echo "$icon_cam Camera ^ 0 ^ GDK_SCALE=2 megapixels")
|
||||
$(
|
||||
if command -v bananarchy-photo >/dev/null; then
|
||||
echo "$icon_cam Camera ^ 0 ^ bananarchy-photo --menu"
|
||||
elif command -v megapixels >/dev/null; then
|
||||
echo "$icon_cam Camera ^ 0 ^ GDK_SCALE=2 megapixels"
|
||||
fi
|
||||
)
|
||||
$(
|
||||
if brightness="$(brightnessctl -l -m | grep -e "white:torch" -e "white:flash" | cut -d ',' -f 3)" && [ -n "$brightness" ]; then
|
||||
printf "%s Flashlight " "$icon_fll"
|
||||
|
||||
Reference in New Issue
Block a user