Skip to content

Instantly share code, notes, and snippets.

@UnJavaScripter
Created February 18, 2023 21:27
Show Gist options
  • Save UnJavaScripter/fd50432588eae785b64974d67c9bfbb7 to your computer and use it in GitHub Desktop.
Save UnJavaScripter/fd50432588eae785b64974d67c9bfbb7 to your computer and use it in GitHub Desktop.
A bash script that allows the user to pick a gphoto2 compatible camera connected to their linux device to create a virtual webcam using v4l2loopback
#!/bin/bash
##
# Error "An error occurred in the io-library ('Timeout reading from or writing to the port'): No error description available ERROR: Movie capture error... Exiting."
# -> https://github.com/gphoto/gphoto2/issues/495
##
generate_virtual_camera_names() {
local length=$1
local test_strings=()
for i in $(seq 0 $((length - 1))); do
test_strings+=("Virtual_Camera_$i")
done
(IFS=,; echo "${test_strings[*]}")
}
generate_virtual_camera_ids() {
local length=$1
local test_strings=()
for i in $(seq 0 $((length - 1))); do
test_strings+=($((10 + $i)))
done
(IFS=,; echo "${test_strings[*]}")
}
cleanup () {
echo; echo 'Removing v4l2loopback'
sudo modprobe -r v4l2loopback
echo; echo 'Removing /dev/video10 device'
sudo rm -fr /dev/video10
}
if [[ $1 == "cleanup" ]]; then
echo "Cleaning things up..."
cleanup
exit 0
fi
on_exit () {
trap TERM
cleanup
exit 0
}
trap "on_exit" INT
start_camera() {
echo "Attaching camera $1 to virtual device at /dev/video10"
# gphoto2 --port $1 --stdout --capture-movie | ffmpeg -hide_banner -loglevel panic -nostats -i - -vcodec rawvideo -pix_fmt yuv420p -f v4l2 /dev/video10
gphoto2 --port $1 --stdout --capture-movie | ffmpeg -i - -vcodec rawvideo -pix_fmt yuv420p -f v4l2 /dev/video10
}
create_virtual_camera() {
echo "Creating virtual camera device /dev/video10"
echo;
#sudo modprobe v4l2loopback exclusive_caps=1 video_nr=10,11 card_label="Virtual Camera","Virtual Camera Aux"
sudo modprobe v4l2loopback exclusive_caps=1 video_nr=10 card_label="Virtual Camera" devices=1
echo;
}
##########
## Menu
# By Alexander Klimetschek
# At https://unix.stackexchange.com/a/415155
##########
function select_option {
# little helpers for terminal print control and key input
ESC=$( printf "\033")
cursor_blink_on() { printf "$ESC[?25h"; }
cursor_blink_off() { printf "$ESC[?25l"; }
cursor_to() { printf "$ESC[$1;${2:-1}H"; }
print_option() { printf " $1 "; }
print_selected() { printf " $ESC[7m $1 $ESC[27m"; }
get_cursor_row() { IFS=';' read -sdR -p $'\E[6n' ROW COL; echo ${ROW#*[}; }
key_input() { read -s -n3 key 2>/dev/null >&2
if [[ $key = $ESC[A ]]; then echo up; fi
if [[ $key = $ESC[B ]]; then echo down; fi
if [[ $key = "" ]]; then echo enter; fi; }
# initially print empty new lines (scroll down if at bottom of screen)
for opt; do printf "\n"; done
# determine current screen position for overwriting the options
local lastrow=`get_cursor_row`
local startrow=$(($lastrow - $#))
# ensure cursor and input echoing back on upon a ctrl+c during read -s
trap "cursor_blink_on; stty echo; printf '\n'; exit" 2
cursor_blink_off
local selected=0
while true; do
# print options by overwriting the last lines
local idx=0
for opt; do
cursor_to $(($startrow + $idx))
if [ $idx -eq $selected ]; then
print_selected "$opt"
else
print_option "$opt"
fi
((idx++))
done
# user key control
case `key_input` in
enter) break;;
up) ((selected--));
if [ $selected -lt 0 ]; then selected=$(($# - 1)); fi;;
down) ((selected++));
if [ $selected -ge $# ]; then selected=0; fi;;
esac
done
# cursor position back to normal
cursor_to $lastrow
printf "\n"
cursor_blink_on
return $selected
}
echo "Select one option using up/down keys and enter to confirm:"
echo
options=$(gphoto2 --auto-detect | awk 'NR > 2 { print $0 }')
IFS=$'\n' read -d '' -ra optionsArr <<< "$options"
select_option "${optionsArr[@]}"
choice=$?
echo "Creating Virtual Camera for ${optionsArr[$choice]}"
echo "..."
cleanup
sleep 1
create_virtual_camera
name=$(echo ${optionsArr[$choice]} | sed 's/\susb:/\n/g' | awk 'NR==1')
port=usb:$(echo ${optionsArr[$choice]} | sed 's/\susb:/\n/g' | awk 'NR==2')
sleep 1
start_camera "${port% }"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment