diff --git a/README.md b/README.md index 4976d75..51c38e1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # crowsnest -A webcam daemon for Raspi Lite images like mainsailOS +A webcam daemon for Raspberry Pi OS Lite images like mainsailOS --- @@ -11,15 +11,30 @@ See https://en.wikipedia.org/wiki/Crow's_nest So, this will be the 'lookout point' for your Printer. -### Install on MainsailOS 0.5.0 as update +### Install on Raspberry Pi OS cd ~ git clone https://github.com/mainsail-crew/crowsnest.git cd crowsnest - ./installer_ms050.sh + ./install.sh -An installer for other Distribution than MainsailOS will come. -Give me some time to prepare! +_This is not tested on other Distributions. If you test that on other Distributions,\ +feel free to open a Pull Request to enhance Documentation._ +After successful Instalation you should consider to add + + [update_manager webcamd] + type: git_repo + path: ~/crowsnest + origin: https://github.com/mainsail-crew/crowsnest.git + +to your moonraker.conf, to get latest and possibly greatest Features. + +### To unsinstall 'crowsnest' + cd crowsnest + ./uninstall.sh + + +### _NOTE: This project has WIP Status! Changes may occure and possibly break things!_ --- @@ -39,7 +54,7 @@ By default it look like this: log_level: quiet [cam 1] - streamer: mjpg + streamer: ustreamer port: 8080 device: /dev/video0 resolution: 640x480 @@ -144,7 +159,7 @@ If you enable that option, everytime you restart, your existing log file will be Now the more interessting part. [cam 1] - streamer: mjpg + streamer: ustreamer port: 8080 device: /dev/video0 resolution: 640x480 @@ -161,7 +176,6 @@ This section should be pretty much self explantory. means your choosen streamservice will be mjpg_streamer.\ You can choose: -- mjpg - well known [Jacksonliam's mjpg-streamer-experimental](https://github.com/jacksonliam/mjpg-streamer) - ustreamer - A streamserver from Pi-KVM Project\ active maintained by [Maxim Devaev](https://github.com/mdevaev)\ @@ -211,18 +225,10 @@ If you enable this in your [cam whatevernameyouset],\ you can add parameters according to your needs.\ Those will be appended to the default/preconfigured parameters. -_In case of mjpg_streamer you could (at this Point) only add parameters -to the "input\_*.so" section!_ - To setup Services to your need you have to take a closer look to the documentation of the Projects named above.\ As a pointer in the right direction: -- mjpg - - This one is a bit more complex due the fact it depends on your cam type. - - For 'Raspicam' see [Plugin: input_raspicam](https://github.com/jacksonliam/mjpg-streamer/blob/master/mjpg-streamer-experimental/plugins/input_raspicam/README.md) - - For USB Type Cams see [Plugin: input_uvc](https://github.com/jacksonliam/mjpg-streamer/blob/master/mjpg-streamer-experimental/plugins/input_uvc/README.md) - - ustreamer - For sake of simplicity I converted ustreamers manpage to [ustreamer's manpage](./ustreamer_manpage.md) diff --git a/custompios/crowsnest/config b/custompios/crowsnest/config index 20cffdf..493b71b 100644 --- a/custompios/crowsnest/config +++ b/custompios/crowsnest/config @@ -1,26 +1,29 @@ +# Version 3 + +# crowsnest [ -n "$CROWSNEST_CROWSNEST_REPO_SHIP" ] || CROWSNEST_CROWSNEST_REPO_SHIP=https://github.com/mainsail-crew/crowsnest.git [ -n "$CROWSNEST_CROWSNEST_REPO_BRANCH" ] || CROWSNEST_CROWSNEST_REPO_BRANCH=master -[ -n "$CROWSNEST_CROWSNEST_DEPS" ] || CROWSNEST_DEPS="git crudini" +[ -n "$CROWSNEST_CROWSNEST_DEPS" ] || CROWSNEST_DEPS="git crudini bsdutils" [ -n "$CROWSNEST_DEFAULT_CONF" ] || CROWSNEST_DEFAULT_CONF="mainsail_default.conf" [ -n "$CROWSNEST_DEFAULT_CONF_DIR" ] || CROWSNEST_DEFAULT_CONF_DIR="/home/${BASE_USER}/klipper_config" [ -n "$CROWSNEST_MOONRAKER_SUPPORT" ] || CROWSNEST_MOONRAKER_SUPPORT="y" -# mjpg-streamer -[ -n "$CROWSNEST_MJPG_REPO_SHIP" ] || CROWSNEST_MJPG_REPO_SHIP=https://github.com/jacksonliam/mjpg-streamer.git -[ -n "$CROWSNEST_MJPG_REPO_BRANCH" ] || CROWSNEST_MJPG_REPO_BRANCH=master -[ -n "$CROWSNEST_MJPG_REPO_DEPTH" ] || CROWSNEST_MJPG_REPO_DEPTH=1 -[ -n "$CROWSNEST_MJPG_DEPS" ] || CROWSNEST_MJPG_DEPS="git build-essential libv4l-dev imagemagick ffmpeg" - # ustreamer [ -n "$CROWSNEST_USTREAMER_REPO_SHIP" ] || CROWSNEST_USTREAMER_REPO_SHIP=https://github.com/pikvm/ustreamer.git [ -n "$CROWSNEST_USTREAMER_REPO_BRANCH" ] || CROWSNEST_USTREAMER_REPO_BRANCH=master [ -n "$CROWSNEST_USTREAMER_REPO_DEPTH" ] || CROWSNEST_USTREAMER_REPO_DEPTH=1 -[ -n "$CROWSNEST_USTREAMER_DEPS" ] || CROWSNEST_USTREAMER_DEPS="git build-essential libevent-dev libjpeg8-dev \ +[ -n "$CROWSNEST_USTREAMER_DEPS" ] || CROWSNEST_USTREAMER_DEPS="git build-essential libevent-dev libjpeg62-turbo-dev \ libbsd-dev libraspberrypi-dev libgpiod-dev cmake cmake-data" -[ -n "$CROWSNEST_USTREAMER_WITH_OMX" ] || CROWSNEST_USTREAMER_WITH_OMX="y" +[ -n "$CROWSNEST_USTREAMER_WITH_OMX" ] || CROWSNEST_USTREAMER_WITH_OMX="n" [ -n "$CROWSNEST_USTREAMER_WITH_GPIO" ] || CROWSNEST_USTREAMER_WITH_GPIO="n" # v4l2rtspserver [ -n "$CROWSNEST_V4L2RTSP_REPO_SHIP" ] || CROWSNEST_V4L2RTSP_REPO_SHIP=https://github.com/mpromonet/v4l2rtspserver.git [ -n "$CROWSNEST_V4L2RTSP_REPO_BRANCH" ] || CROWSNEST_V4L2RTSP_REPO_BRANCH=master -[ -n "$CROWSNEST_V4L2RTSP_DEPS" ] || CROWSNEST_V4L2RTSP_DEPS="git build-essential liblivemedia-dev liblog4cpp5-dev" \ No newline at end of file +[ -n "$CROWSNEST_V4L2RTSP_DEPS" ] || CROWSNEST_V4L2RTSP_DEPS="git build-essential liblivemedia-dev liblog4cpp5-dev" + +### Stay for possible later use. +# # simple-rtsp-server +# [ -n "$CROWSNEST_RTSPSIMPLE_RELEASE" ] || CROWSNEST_RTSPSIMPLE_RELEASE="https://github.com/aler9/rtsp-simple-server/releases/download/v0.17.9/rtsp-simple-server_v0.17.9_linux_armv6.tar.gz" +# [ -n "$CROWSNEST_RTSPSIMPLE_DEPS" ] || CROWSNEST_RTSPSIMPLE_DEPS="curl ffmpeg" +# [ -n "$CROWSNEST_RTSPSIMPLE_DIR" ] || CROWSNEST_RTSPSIMPLE_DIR="/home/${BASE_USER}/rtsp-simple-server" \ No newline at end of file diff --git a/custompios/crowsnest/start_chroot_script b/custompios/crowsnest/start_chroot_script index 208705b..5d49ecd 100644 --- a/custompios/crowsnest/start_chroot_script +++ b/custompios/crowsnest/start_chroot_script @@ -5,6 +5,7 @@ # Copyright 2021 # https://github.com/mainsail-crew/crowsnest # GPL V3 +# Version 2 ######## @@ -70,68 +71,20 @@ if [ -d "/home/${BASE_USER}/crowsnest" ]; then to '/etc/systemd/system/webcamd.service'.. " cp -p file_templates/webcamd.service /etc/systemd/system/ ## Make sure raspicam become /dev/video0 Workaround - sudo sh -c "echo bcm2835-v4l2 >> /etc/modules" + sudo sh -c 'echo "bcm2835-v4l2" >> /etc/modules' ## Enable systemd service echo_green "Enable webcamd.service ..." systemctl_if_exists enable webcamd.service popd > /dev/null fi -echo_green "Installing mjpeg-streamer ..." -### Clone and compile mjpg_streamer -## Due the fact that used mjpg_streamer has a weird folder structure -## We need some 'magic' to workaround that. -echo_green "Cloning mjpg-streamer Sources." -gitclone CROWSNEST_MJPG_REPO mjpg_tmp -sudo -u ${BASE_USER} mkdir -p mjpg-streamer -sudo -u ${BASE_USER} mv mjpg_tmp/mjpg-streamer-experimental/* mjpg-streamer/ - -## This Part is out of the original mjpg-streamer Module -## Credits to: Raymond Himle -## (Adapted from the OctoPi image creation scripts. Thanks Gina and Guysoft!) -echo_green "Installing mjpg-streamer Dependencies." -apt update -check_install_pkgs ${CROWSNEST_MJPG_DEPS} -apt install -y --allow-downgrades cmake=3.13.4-1 cmake-data=3.13.4-1 -if [ $( is_in_apt libjpeg62-turbo-dev ) -eq 1 ]; then - apt-get -y --force-yes install libjpeg62-turbo-dev -elif [ $( is_in_apt libjpeg8-dev ) -eq 1 ]; then - apt-get -y --force-yes install libjpeg8-dev -fi - -## Compile mjpg_streamer -echo_green "Compiling mjpg-streamer" -pushd mjpg-streamer > /dev/null -MJPG_STREAMER_BUILD_DIR=_build -[ -d ${MJPG_STREAMER_BUILD_DIR} ] || (mkdir ${MJPG_STREAMER_BUILD_DIR} && \ - chown ${BASE_USER}:${BASE_USER} ${MJPG_STREAMER_BUILD_DIR}) -[ -f ${MJPG_STREAMER_BUILD_DIR}/Makefile ] || (cd ${MJPG_STREAMER_BUILD_DIR} && \ - sudo -u ${BASE_USER} cmake -DCMAKE${MJPG_STREAMER_BUILD_DIR}_TYPE=Release ..) - sudo -u ${BASE_USER} make -j $(nproc) -C ${MJPG_STREAMER_BUILD_DIR} - sudo -u ${BASE_USER} cp ${MJPG_STREAMER_BUILD_DIR}/mjpg_streamer . - sudo -u ${BASE_USER} find ${MJPG_STREAMER_BUILD_DIR} -name "*.so" -type f -exec cp {} . \; -popd > /dev/null - -## Cleanup -echo_green "Removing temporary Repo Folder." -rm -rf mjpg_tmp -## Due the fact mjpg uses an older version of cmake we have to upgrade it. -apt install cmake cmake-data -## Create sym links -echo_green "Creating sym links..." -sudo ln -sf $PWD/mjpg-streamer/mjpg_streamer /usr/local/bin/ -# Finished -echo_green "Successful installed mjpg-streamer." - - ### Install ustreamer echo_green "Installing ustreamer ..." ### Clone and compile ustreamer echo_green "Cloning ustreamer Sources." gitclone CROWSNEST_USTREAMER_REPO ustreamer echo_green "Installing ustreamer Dependencies." -apt update -apt --yes install ${CROWSNEST_USTREAMER_DEPS} +check_install_pkgs ${CROWSNEST_USTREAMER_DEPS} ## Compile ustreamer echo_green "Compiling ustreamer" pushd ustreamer > /dev/null @@ -144,7 +97,7 @@ elif [ "${CROWSNEST_USTREAMER_WITH_OMX}" = "y" ] && \ echo_green "Compile ustreamer with OMX Support..." WITH_OMX=1 make -j $(nproc) else - "Compile ustreamer without OMX and GPIO Support..." + echo_green "Compile ustreamer without OMX and GPIO Support..." make -j $(nproc) fi popd > /dev/null @@ -152,20 +105,35 @@ popd > /dev/null ## Create sym links echo_green "Creating sym links..." sudo ln -sf $PWD/ustreamer/ustreamer /usr/local/bin/ +sudo ln -sf $PWD/ustreamer/ustreamer-dump /usr/local/bin/ # Finished echo_green "Successful installed ustreamer." +### Stay for possibly later use. +# ### Install rtsp-simple-server +# echo_green "Installing 'rtsp-simple-server' ..." +# # Install Dependencies +# echo_green "Installing 'rtsp-simple-server' Dependencies ..." +# check_install_pkgs "${CROWSNEST_RTSPSIMPLE_DEPS}" +# # Download Release Binary +# echo_green "Download 'rtsp-simple-server' ..." +# curl -o /tmp/rtsp-simple-server.tar.gz -L "${CROWSNEST_SIMPLERTSP_RELEASE}" +# sudo -u ${BASE_USER} mkdir -p "${CROWSNEST_RTSPSIMPLE_DIR}" +# sudo -u ${BASE_USER} tar xfz /tmp/rtsp-simple-server.tar.gz -C "${CROWSNEST_RTSPSIMPLE_DIR}" +# ## Create sym links +# echo_green "Creating sym links..." +# sudo ln -sf ${CROWSNEST_RTSPSIMPLE_DIR}/rtsp-simple-server /usr/local/bin/ +# # Finished +# echo_green "Successful installed 'rtsp-simple-server'." + ### Install v4l2rtspserver echo_green "Installing v4l2rtspserver ..." -### Clone and compile ustreamer +### Clone and compile v4l2rtspserver echo_green "Cloning v4l2rtspserver Sources." gitclone CROWSNEST_V4L2RTSP_REPO v4l2rtspserver echo_green "Installing v4l2rtspserv Dependencies." -apt update -apt --yes install ${CROWSNEST_V4L2RTSP_DEPS} -# It seems v4l2rtspserver has trouble to compile with cmake 3.16 -apt install -y --allow-downgrades cmake=3.13.4-1 cmake-data=3.13.4-1 -## Compile ustreamer +check_install_pkgs ${CROWSNEST_V4L2RTSP_DEPS} +## Compile v4l2rtspserver echo_green "Compiling v4l2rtspserver" pushd v4l2rtspserver > /dev/null cmake -j $(nproc) . && make -j $(nproc) diff --git a/file_templates/buster-backports.list b/file_templates/buster-backports.list new file mode 100644 index 0000000..4d1b8c5 --- /dev/null +++ b/file_templates/buster-backports.list @@ -0,0 +1 @@ +deb http://deb.debian.org/debian buster-backports main contrib non-free \ No newline at end of file diff --git a/file_templates/logrotate_webcamd b/file_templates/logrotate_webcamd new file mode 100644 index 0000000..e3f40ec --- /dev/null +++ b/file_templates/logrotate_webcamd @@ -0,0 +1,19 @@ +##### +# webcamd logrotate file +# written by Stephan Wendel aka KwadFan +# +# GPL v3 +##### + + +/home/pi/kliper_logs/webcamd.log { + rotate 3 + missingok + notifempty + compress + delaycompress + daily + dateext + dateformat %F + maxsize 32M +} \ No newline at end of file diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..4eda12e --- /dev/null +++ b/install.sh @@ -0,0 +1,312 @@ +#!/usr/bin/env bash +# Crow's Nest +# A multiple Cam and Stream Service for mainsailOS +# Written by Stephan Wendel aka KwadFan +# Copyright 2021 +# https://github.com/mainsail-crew/crowsnest +# GPL V3 +# Version 2 +######## + +set -e + +## Debug +# set -x + +# Global Vars +BASE_USER=$(whoami) +TITLE="crowsnest - A Webcam Daemon for Raspberry Pi OS" + +### Non root +if [ ${UID} == '0' ]; then + echo -e "DO NOT RUN THIS SCRIPT AS ROOT!\nExiting..." + exit 1 +fi + +### noninteractive Check +if [ -z "${DEBIAN_FRONTEND}" ]; then + export DEBIAN_FRONTEND=noninteractive +fi + +### Functions + +### Messages +### Welcome Message +function welcome_msg { + echo -e "${TITLE}\n" + echo -e "\tSome Parts of the Installer requires 'root' privileges." + echo -e "\tYou will be prompted for your 'sudo' password, if needed.\n" +} + +function detect_msg { + echo -e "Found an existing 'webcamd'. This will be removed." + echo -e "Since we dont use mjpg-streamer it will also removed." + echo -e "You can use KIAUH for example to reinstall.\n" +} + +function goodbye_msg { + echo -e "\nInstallation complete.\n\tPlease reboot your machine!" + echo -e "I hope you enjoy crowsnest, GoodBye ..." +} + +### Installer + +### General +## These two functions are reused from custompios common.sh +## Credits to guysoft! +## https://github.com/guysoft/CustomPiOS + +function install_cleanup_trap() { + # kills all child processes of the current process on SIGINT or SIGTERM + trap 'cleanup' SIGINT SIGTERM +} + +function cleanup() { + # make sure that all child processed die when we die + local pids=$(jobs -pr) + echo -e "Killed by user ...\r\nGoodBye ...\r" + [ -n "$pids" ] && kill $pids && sleep 5 && kill -9 $pids +} +## + +function err_exit { + if [ "${1}" != "0" ]; then + echo -e "ERROR: Error ${1} occured on line ${2}" + echo -e "ERROR: Stopping $(basename "$0")." + echo -e "Goodbye..." + fi + if [ -n "$(jobs -pr)" ]; then + kill $(jobs -pr) + fi + exit 1 +} + +### Init ERR Trap +trap 'err_exit $? $LINENO' ERR + +### Import config from custompios. +function import_config { + if [ -f "${HOME}/crowsnest/custompios/crowsnest/config" ]; then + source ${HOME}/crowsnest/custompios/crowsnest/config + else + echo -e "${TITLE}\n" + echo -e "OOPS!\nConfiguration File missing! Exiting..." + echo -e "Try to git clone a second time please ...\n" + exit 1 + fi +} + +### Detect webcamd. +function detect_existing_webcamd { + local remove + if [ -x "/usr/local/bin/webcamd" ] && [ -d "${HOME}/mjpg-streamer" ]; then + detect_msg + read -rp "Do you want to remove existing 'webcamd'? (YES/NO) " remove + if [ "${remove}" = "YES" ]; then + echo -en "\nStopping webcamd.service ...\r" + # sudo systemctl stop webcamd.service &> /dev/null + echo -e "Stopping webcamd.service ... \t[OK]\r" + remove_existing_webcamd + else + echo -e "\nYou answered '${remove}'! Installation will be aborted..." + echo -e "GoodBye...\n" + exit 1 + fi + fi +} + +### Remove existing webcamd +function remove_existing_webcamd { + if [ -x "/usr/local/bin/webcamd" ]; then + echo -en "Removing 'webcamd' ...\r" + sudo rm -f /usr/local/bin/webcamd > /dev/null + echo -e "Removing 'webcamd' ... \t\t[OK]\r" + fi + if [ -d "${HOME}/mjpg-streamer" ]; then + echo -en "Removing 'mjpg-streamer' ...\r" + sudo rm -rf ${HOME}/mjpg-streamer > /dev/null + echo -e "Removing 'mjpg-streamer' ... \t[OK]\r" + fi + if [ -f "/etc/systemd/system/webcamd.service" ]; then + echo -en "Removing 'webcamd.service' ...\r" + sudo rm -f /etc/systemd/system/webcamd.service > /dev/null + echo -e "Removing 'webcamd.service' ... \t[OK]\r" + fi + if [ -f "/var/log/webcamd.log" ]; then + echo -en "Removing 'webcamd.log' ...\r" + sudo rm -f /var/log/webcamd.log > /dev/null + sudo rm -f ${HOME}/klipper_logs/webcamd.log > /dev/null + echo -e "Removing 'webcamd.log' ... \t[OK]\r" + fi + if [ -f "/etc/logrotate.d/webcamd" ]; then + echo -en "Removing 'webcamd' logrotate...\r" + sudo rm -f /etc/logrotate.d/webcamd > /dev/null + echo -e "Removing 'webcamd' logrotate ... \t[OK]\r" + fi + echo -e "\nOld 'webcamd' completly removed." + echo -e "webcam.txt kept,but no longer necessary ..." +} + +### Install Dependencies +## Enable buster-backports ( needed for golang-go > 1.11 ) +function enable_backports { + local template sources + template="${HOME}/crowsnest/file_templates/buster-backports.list" + sources="/etc/apt/sources.list.d/" + if [ "$(grep -c "buster" /etc/apt/sources.list)" -ne "0" ]; then + echo -e "\n'Debian 10 Buster' ( or based of ) detected ..." + echo -e "We need to install Debian Backports for golang >=1.11\n" + echo -en "Adding buster-backports to 'apt' ...\r" + sudo cp "${template}" "${sources}" &> /dev/null + echo -e "Adding buster-backports to 'apt' ... [OK]\r" + echo -e "Adding buster-backports keyring to 'apt' ...\r" + sudo apt-key adv --keyserver keyring.debian.org --recv-keys 648ACFD622F3D138 + sudo apt-key adv --keyserver keyring.debian.org --recv-keys 0E98404D386FA1D9 + echo -e "Adding buster-backports keyring to 'apt' ... [OK]\r" + echo -e "\nRunning 'apt update' to initialize backports ..." + sudo apt update + fi +} + +function install_crowsnest { + local template servicefile logrotatefile bin_path webcamd_bin + bin_path="/usr/local/bin" + webcamd_bin="${HOME}/crowsnest/webcamd" + template="$PWD/sample_configs/${CROWSNEST_DEFAULT_CONF}" + servicefile="$PWD/file_templates/webcamd.service" + logrotatefile="${HOME}/crowsnest/file_templates/logrotate_webcamd" + echo -e "\nInstall webcamd Service ..." + ## Install Dependencies + echo -e "Installing 'crowsnest' Dependencies ..." + sudo apt install --yes --no-install-recommends $CROWSNEST_DEPS > /dev/null + echo -e "Installing 'crowsnest' Dependencies ... [OK]" + ## Link webcamd to $PATH + echo -en "Linking webcamd ...\r" + sudo ln -sf "${webcamd_bin}" "${bin_path}" > /dev/null + echo -e "Linking webcamd ... [OK]\r" + ## Copy webcam.conf + # Make sure not to overwrite existing! + if [ ! -f "${CROWSNEST_DEFAULT_CONF_DIR}/webcam.conf" ]; then + echo -en "Copying webcam.conf ...\r" + sudo -u "${BASE_USER}" cp -rf $PWD/sample_configs/${CROWSNEST_DEFAULT_CONF} "${CROWSNEST_DEFAULT_CONF_DIR}"/webcam.conf + echo -e "Copying webcam.conf ... [OK]\r" + fi + ## Link webcamd.service + echo -en "Copying webcamd.service file ...\r" + sudo ln -sf "${servicefile}" /etc/systemd/system/webcamd.service > /dev/null + echo -e "Copying webcamd.service file ... [OK]\r" + ## Link logrotate + echo -en "Linking logrotate file ...\r" + sudo ln -sf "${logrotatefile}" /etc/logrotate.d/webcamd + echo -e "Linking logrotate file ... [OK]\r" + echo -en "Reload systemd to enable new deamon ...\r" + sudo systemctl daemon-reload + echo -e "Reload systemd to enable new daemon ... [OK]" + echo -en "Enable webcamd.service on boot ...\r" + sudo systemctl enable webcamd.service + echo -e "Enable webcamd.service on boot ... [OK]\r" +} + +function install_ustreamer { + local bin_path ustreamer_bin ustreamer_dump_bin + ustreamer_bin="${HOME}/ustreamer/ustreamer" + ustreamer_dump_bin="${HOME}/ustreamer/ustreamer-dump" + bin_path="/usr/local/bin" + echo -e "\nInstalling ustreamer ..." + echo -e "Installing ustreamer Dependencies ..." + sudo apt install --yes --no-install-recommends $CROWSNEST_USTREAMER_DEPS > /dev/null + echo -e "Installing ustreamer Dependencies ... \t[OK]" + echo -e "Cloning ustreamer Repo ..." + pushd ${HOME} > /dev/null + git clone "${CROWSNEST_USTREAMER_REPO_SHIP}" --depth=1 + popd > /dev/null + echo -e "Cloning ustreamer Repo ... [OK]" + pushd ${HOME}/ustreamer > /dev/null + echo -e "Compiling ustreamer ..." + if [ "${CROWSNEST_USTREAMER_WITH_OMX}" = "y" ] && \ + [ "${CROWSNEST_USTREAMER_WITH_GPIO}" = "y" ]; then + echo -e "Compile ustreamer with OMX and GPIO Support..." + WITH_OMX=1 WITH_GPIO=1 make -j$(nproc) + elif [ "${CROWSNEST_USTREAMER_WITH_OMX}" = "y" ] && \ + [ "${CROWSNEST_USTREAMER_WITH_GPIO}" = "n" ]; then + echo -e "Compile ustreamer with OMX Support..." + WITH_OMX=1 make -j $(nproc) + else + echo -e"Compile ustreamer without OMX and GPIO Support..." + make -j $(nproc) + fi + popd > /dev/null + echo -en "Linking ustreamer ...\r" + sudo ln -sf "${ustreamer_bin}" "${bin_path}" > /dev/null + sudo ln -sf "${ustreamer_dump_bin}" "${bin_path}" > /dev/null + echo -e "Linking ustreamer ... [OK]\r" + echo -e "Installing ustreamer ... [OK]" +} + +function install_v4l2rtspserver { + local bin_path v4l2rtsp_bin + v4l2rtsp_bin="${HOME}/v4l2rtspserver/v4l2rtspserver" + bin_path="/usr/local/bin" + echo -e "\nInstalling v4l2rtspserver ..." + echo -e "Installing v4l2rtspserver Dependencies ..." + sudo apt install --yes --no-install-recommends $CROWSNEST_V4L2RTSP_DEPS > /dev/null + echo -e "Installing v4l2rtspserver Dependencies ... \t[OK]" + echo -e "Cloning v4l2rtspserver Repo ..." + pushd ${HOME} > /dev/null + git clone "${CROWSNEST_V4L2RTSP_REPO_SHIP}" --depth=1 + popd > /dev/null + echo -e "Cloning v4l2rtspserver Repo ... [OK]" + pushd ${HOME}/v4l2rtspserver > /dev/null + echo -e "Compiling v4l2rtspserver ..." + cmake . && make -j $(nproc) + popd > /dev/null + echo -en "Linking v4l2rtspserver ...\r" + sudo ln -sf "${v4l2rtsp_bin}" "${bin_path}" > /dev/null + echo -e "Linking v4l2rtspserver ... [OK]\r" + echo -e "Installing v4l2rtspserver ... [OK]" +} + +## Stay for later use. +# function install_rtspsimple { +# local bin_path rtsp_bin +# bin_path="/usr/local/bin" +# rtsp_bin="${CROWSNEST_RTSPSIMPLE_DIR}/rtsp-simple-server" +# # We are using armv6l Version to be downwards compatible. +# ## Install Dependencies +# echo -e "Installing 'rtsp-simple-server' Dependencies ..." +# sudo apt install --yes --no-install-recommends $CROWSNEST_RTSPSIMPLE_DEPS > /dev/null +# echo -e "Installing 'rtsp-simple-server' Dependencies ... [OK]" +# # Download Release Binary +# echo -e "Download 'rtsp-simple-server' ..." +# curl -o /tmp/rtsp-simple-server.tar.gz -L "${CROWSNEST_RTSPSIMPLE_RELEASE}" +# echo -e "Download 'rtsp-simple-server' ... [OK]" +# echo -en "Unpacking 'rtsp-simple-server' ...\r" +# mkdir -p "${CROWSNEST_RTSPSIMPLE_DIR}" > /dev/null +# tar xfz /tmp/rtsp-simple-server.tar.gz -C "${CROWSNEST_RTSPSIMPLE_DIR}" > /dev/null +# echo -e "Unpacking 'rtsp-simple-server' ... [OK]" +# echo -en "Linking 'rtsp-simple-server' ...\r" +# sudo ln -sf "${rtsp_bin}" "${bin_path}" > /dev/null +# echo -e "Linking 'rtsp-simple-server' ... [OK]\r" +# } + +function install_raspicam_fix { + sudo sh -c 'echo "bcm2835-v4l2" >> /etc/modules' +} + +#### MAIN +install_cleanup_trap +import_config +welcome_msg +detect_existing_webcamd +## Golang not needed for now! +# enable_backports +echo -e "Running apt update first ..." +sudo apt update +install_crowsnest +install_ustreamer +install_v4l2rtspserver +# install_rtspsimple +install_raspicam_fix +goodbye_msg + +exit 0 \ No newline at end of file diff --git a/installer_ms050.sh b/installer_ms050.sh deleted file mode 100755 index 836bb44..0000000 --- a/installer_ms050.sh +++ /dev/null @@ -1,120 +0,0 @@ -#!/bin/bash - -set -e -# set -x -export DEBIAN_FRONTEND=noninteractive - - -if [ "${UID}" == "0" ]; then - echo -e "\nDO NOT RUN THIS SCRIPT AS 'root' !!!\n" - exit 1 -fi -echo -e "Some Commands have to run as 'root' via sudo." -echo -e "You will be asked for password if needed.\n" - -# Stoping existing Daemon -echo -e "Stopping existing webcamd...\n" -sudo systemctl stop webcamd - -# Remove existing webcamd. -echo -e "Backup existing files...\n" -mkdir -p ${HOME}/webcamd-backup -if [ -e "/etc/systemd/system/webcamd.service" ]; then - cp -p /etc/systemd/system/webcamd.service ${HOME}/webcamd-backup -fi -if [ -e "/usr/local/bin/webcamd" ]; then - cp -p /usr/local/bin/webcamd ${HOME}/webcamd-backup/ -fi -if [ -e "/etc/logrotate.d/webcamd" ]; then - cp -p /etc/logrotate.d/webcamd ${HOME}/webcamd-backup/webcamd.logrotate -fi - -# Remove existing. -echo -e "Removing existing webcamd...\n" -sudo rm -rf /etc/logrotate.d/webcamd -sudo rm -rf /usr/local/bin/webcamd -sudo rm -rf /etc/systemd/system/webcamd.service -sudo rm -rf ${HOME}/klipper_logs/webcamd.log -sudo rm -rf /var/log/webcamd.log - -# Install Dependency -sudo apt update -sudo apt install crudini logger -y - -# Install Project "crowsnest" -echo -e "Installing webcamd and enable Service" -sudo ln -s $PWD/webcamd /usr/local/bin/webcamd -sudo cp -r $PWD/file_templates/webcamd.service /etc/systemd/system/ -cp -r $PWD/sample_configs/minimal.conf ${HOME}/klipper_config/webcam.conf -sudo systemctl daemon-reload -sudo systemctl enable webcamd - - -# Install ustreamer -# Make sure its clean -if [ -d "${HOME}/ustreamer" ]; then - rm -rf ${HOME}/ustreamer/ -fi - -echo -e "Compiling ustreamer..." -cd ~ -git clone https://github.com/pikvm/ustreamer.git -cd ustreamer -if [[ "$(cat /proc/device-tree/model | cut -d ' ' -f1)" = "Raspberry" ]]; then - sudo apt update - sudo apt install build-essential libevent-dev libjpeg-dev libbsd-dev \ - libraspberrypi-dev libgpiod-dev -y - export WITH_OMX=1 - make -j $(nproc) # push limit - echo -e "Create symlink..." - sudo ln -sf ${HOME}/ustreamer/ustreamer /usr/local/bin/ -else - sudo apt update - sudo apt install build-essential libevent-dev libjpeg-dev libbsd-dev \ - libgpiod-dev -y - make -j $(nproc) - echo -e "Create symlink..." - sudo ln -sf ${HOME}/ustreamer/ustreamer /usr/local/bin/ -fi - -# Install v4l2rtspserver -# Make sure its clean -if [ -d "${HOME}/v4l2rtspserver" ]; then - rm -rf ${HOME}/v4l2rtspserver/ -fi -echo -e "Compiling v4l2rtspserver..." -cd ~ -git clone https://github.com/mpromonet/v4l2rtspserver.git -cd v4l2rtspserver -sudo apt install cmake liblivemedia-dev liblog4cpp5-dev -y -cmake . && make -j $(nproc) # push limit -echo -e "Create symlink..." -sudo ln -sf ${HOME}/v4l2rtspserver/v4l2rtspserver /usr/local/bin/ - -# create mjpg_streamer symlink -echo -e "Create mjpg_streamer symlink..." -sudo ln -sf ${HOME}/mjpg-streamer/mjpg_streamer /usr/local/bin/ - -# Start webcamd -sudo sh -c "echo bcm2835-v4l2 >> /etc/modules" -sudo systemctl start webcamd - - -# webcamd to moonraker.conf -echo -e "Adding update manager to moonraker.conf" - -update_section=$(grep -c '\[update_manager webcamd\]' \ -${HOME}/klipper_config/moonraker.conf) -if [ "${update_section}" -eq 0 ]; then - echo -e "\n" >> ${HOME}/klipper_config/moonraker.conf - while read -r line; do - echo -e "${line}" >> ${HOME}/klipper_config/moonraker.conf - done < "$PWD/file_templates/moonraker_update.txt" - echo -e "\n" >> ${HOME}/klipper_config/moonraker.conf -else - echo -e "[update_manager webcamd] already exist in moonraker.conf [SKIPPED]" -fi - -echo -e "Finished Installation..." -echo -e "Please reboot the PI." -exit 0 diff --git a/mjpg-www/index.html b/mjpg-www/index.html deleted file mode 100644 index aeee029..0000000 --- a/mjpg-www/index.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - Webcam - mjpg_streamer - - - - - -
- Webcam - mjpg_streamer -
- -
-
-
Stream
- -
- -
-
Snapshot - - - - - - -
- -
-
- - - - - diff --git a/mjpg-www/script.js b/mjpg-www/script.js deleted file mode 100644 index 66afdcc..0000000 --- a/mjpg-www/script.js +++ /dev/null @@ -1,8 +0,0 @@ -document.getElementById("reloadSVG").style.display = "inline"; - -function reloadSnapshot() { - snapshotUrl = - "./?action=snapshot"; - document.getElementById("snapshotImg").src = - snapshotUrl + "?" + new Date().getTime(); -} \ No newline at end of file diff --git a/mjpg-www/style.css b/mjpg-www/style.css deleted file mode 100644 index 27331e1..0000000 --- a/mjpg-www/style.css +++ /dev/null @@ -1,85 +0,0 @@ -body { - background-color: #121212; - color: #fff; - font-size: 1.5rem; - font-family: Roboto, sans-serif; - margin: 0px; - user-select: none; -} - -a { - text-decoration: none; - color: #bbb; -} - -header { - background-color: #272727; - height: 48px; - line-height: 48px; - box-shadow: 0 0 5px #000; -} - -header a, -header span { - display: inline-block; - height: 100%; - padding: 0 20px; -} - -.container { - padding: 20px; - display: flex; - flex-flow: row wrap; - justify-content: center; - gap: 20px 30px; -} - -.panel { - background-color: #1e1e1e; - border-radius: 4px; - min-width: 350px; - max-width: 500px; - flex-grow: 4; - - box-shadow: 0 10px 20px #000; -} - -.title { - background-color: #272727; - height: 48px; - line-height: 48px; - padding-left: 20px; - border-radius: 4px; - display: flex; - font-size: 1.3rem; -} - -.panel img { - width: 100%; -} - -span:first-of-type { - flex: 1; -} - -.reload svg { - display: none; - fill: #ccc; - height: 16px; - margin: 0 20px; - cursor: pointer; -} - -.reload svg:hover { - fill: #fff; -} - -.reload svg:not(:active) { - transition: transform 0.4s ease-in-out; - transform: rotate(360deg); -} - -.reload noscript { - font-size: 0.6rem; - color: #ccc; -} \ No newline at end of file diff --git a/sample_configs/KwadFan_sample.conf b/sample_configs/KwadFan_sample.conf index ff9dfe7..54cfdab 100644 --- a/sample_configs/KwadFan_sample.conf +++ b/sample_configs/KwadFan_sample.conf @@ -3,7 +3,7 @@ log_path: ~/klipper_logs/webcamd.log # klipper_logs!!! log_level: debug # quiet/verbose/debug [cam 1] -streamer: ustreamer # mjpeg/ustreamer/rtsp +streamer: ustreamer # ustreamer/rtsp port: 8081 # Port device: /dev/video0 # See Log for available ... resolution: 640x480 # widthxheight format @@ -12,7 +12,7 @@ max_fps: 15 # If Hardware Supports this it will be f [cam 2] -streamer: mjpg +streamer: ustreamer port: 8080 device: /dev/v4l/by-id/usb-PixArt_Imaging_Inc._USB2.0_Camera-video-index0 resolution: 640x480 diff --git a/sample_configs/mainsail_default.conf b/sample_configs/mainsail_default.conf index 298f2b2..b89c05d 100644 --- a/sample_configs/mainsail_default.conf +++ b/sample_configs/mainsail_default.conf @@ -8,7 +8,7 @@ log_path: ~/klipper_logs/webcamd.log # Default logfile in ~/klipper_logs/webc log_level: verbose # Valid Options are quiet/verbose/debug [cam 1] -streamer: mjpg # mjpeg/ustreamer/rtsp +streamer: ustreamer # ustreamer/rtsp port: 8080 # Port device: /dev/video0 # See Log for available ... resolution: 640x480 # widthxheight format diff --git a/sample_configs/minimal.conf b/sample_configs/minimal.conf index 109568c..a5967f1 100644 --- a/sample_configs/minimal.conf +++ b/sample_configs/minimal.conf @@ -3,7 +3,7 @@ log_path: ~/klipper_logs/webcamd.log # Default logfile in ~/klipper_logs/webc log_level: quiet # Valid Options are quiet/verbose/debug [cam 1] -streamer: mjpg # mjpeg/ustreamer/rtsp +streamer: ustreamer # ustreamer/rtsp port: 8080 # Port device: /dev/video0 # See Log for available ... resolution: 640x480 # widthxheight format diff --git a/uninstall.sh b/uninstall.sh new file mode 100755 index 0000000..c4968c7 --- /dev/null +++ b/uninstall.sh @@ -0,0 +1,165 @@ +#!/usr/bin/env bash +# Crow's Nest +# A multiple Cam and Stream Service for mainsailOS +# Written by Stephan Wendel aka KwadFan +# Copyright 2021 +# https://github.com/mainsail-crew/crowsnest +# GPL V3 +# Version 1.1 +######## + +set -e + +## Debug +# set -x + +# Global Vars +BASE_USER=$(whoami) +TITLE="crowsnest - A Webcam Daemon for Raspberry Pi OS" + +### Functions + +### Messages +### Welcome Message +function welcome_msg { + echo -e "${TITLE}\n" + echo -e "\tSome Parts of the Uninstaller requires 'root' privileges." + echo -e "\tYou will be prompted for your 'sudo' password, if needed.\n" +} + +function goodbye_msg { + echo -e "Please remove manually the 'crowsnest' folder in ${HOME}" + echo -e "Remove [update manager webcamd] section from moonraker.conf!" + echo -e "After that is done, please reboot!\nGoodBye...\n" +} + +### General +## These two functions are reused from custompios common.sh +## Credits to guysoft! +## https://github.com/guysoft/CustomPiOS + +function install_cleanup_trap() { + # kills all child processes of the current process on SIGINT or SIGTERM + trap 'cleanup' SIGINT SIGTERM +} + +function cleanup() { + # make sure that all child processed die when we die + local pids=$(jobs -pr) + echo -e "Killed by user ...\r\nGoodBye ...\r" + [ -n "$pids" ] && kill $pids && sleep 5 && kill -9 $pids +} +## + +function err_exit { + if [ "${1}" != "0" ]; then + echo -e "ERROR: Error ${1} occured on line ${2}" + echo -e "ERROR: Stopping $(basename "$0")." + echo -e "Goodbye..." + fi + if [ -n "$(jobs -pr)" ]; then + kill $(jobs -pr) + fi + exit 1 +} + +### Init ERR Trap +trap 'err_exit $? $LINENO' ERR + + +### Uninstall crowsnest +function ask_uninstall { + local remove + if [ -x "/usr/local/bin/webcamd" ] && [ -d "${HOME}/crowsnest" ]; then + read -rp "Do you REALLY want to remove existing 'crowsnest'? (YES/NO) " remove + if [ "${remove}" = "YES" ]; then + sudo echo -e "\nPlease enter your password!" + uninstall_crowsnest + uninstall_ustreamer + uninstall_v4l2rtsp + uninstall_rtspsimple + remove_raspicam_fix + goodbye_msg + else + echo -e "\nYou answered '${remove}'! Uninstall will be aborted..." + echo -e "GoodBye...\n" + exit 1 + fi + else + echo -e "\n'crowsnest' seems not installed." + echo -e "Exiting. GoodBye ..." + fi +} + +function uninstall_crowsnest { + local servicefile bin_path + servicefile="/etc/systemd/system/webcamd.service" + bin_path="/usr/local/bin/webcamd" + echo -en "\nStopping webcamd.service ...\r" + sudo systemctl stop webcamd.service &> /dev/null + echo -e "Stopping webcamd.service ... \t[OK]\r" + echo -en "Uninstalling webcamd.service...\r" + if [ -f "${servicefile}" ]; then + sudo rm -f "${servicefile}" + fi + if [ -x "${bin_path}" ]; then + sudo rm -f "${bin_path}" + fi + echo -e "Uninstalling webcamd.service...[OK]\r" +} + +function uninstall_ustreamer { + local bin_path bin_dump_path ustreamer_dir + bin_path="/usr/local/bin/ustreamer" + bin_dump_path="/usr/local/bin/ustreamer-dump" + ustreamer_dir="${HOME}/ustreamer" + if [ -d "${ustreamer_dir}" ]; then + echo -en "Uninstalling ustreamer ...\r" + if [ -x "${bin_path}" ] && [ -x "${bin_dump_path}" ]; then + sudo rm -f "${bin_path}" "${bin_dump_path}" + fi + sudo rm -rf "${ustreamer_dir}" + echo -e "Uninstalling ustreamer ... [OK]\r" + fi +} + +function uninstall_rtspsimple { + local bin_path rtspsimple_dir + bin_path="/usr/local/bin/rtsp-simple-server" + rtspsimple_dir="${HOME}/rtsp-simple-server" + if [ -d "${rtspsimple_dir}" ]; then + echo -en "Uninstalling 'rtsp-simple-server' ...\r" + if [ -x "${bin_path}" ]; then + sudo rm -f "${bin_path}" + fi + sudo rm -rf "${rtspsimple_dir}" + echo -e "Uninstalling 'rtsp-simple-server' ... [OK]\r" + fi +} + +function uninstall_v4l2rtsp { + local bin_path v4l2rtsp_dir + bin_path="/usr/local/bin/v4l2rtspserver" + v4l2rtsp_dir="${HOME}/v4l2rtspserver" + if [ -d "${v4l2rtsp_dir}" ]; then + echo -en "Uninstalling 'v4l2rtspserver' ...\r" + if [ -x "${bin_path}" ]; then + sudo rm -f "${bin_path}" + fi + sudo rm -rf "${v4l2rtsp_dir}" + echo -e "Uninstalling 'v4l2rtspserver' ... [OK]\r" + fi +} + +function remove_raspicam_fix { + echo -en "Removing Raspicam Fix ...\r" + sudo sed -i '/bcm2835/d' /etc/modules + echo -e "Removing Raspicam Fix ... [OK]" +} + +#### MAIN +install_cleanup_trap +welcome_msg +ask_uninstall + +exit 0 \ No newline at end of file diff --git a/webcamd b/webcamd index 8df0365..03f1c9b 100755 --- a/webcamd +++ b/webcamd @@ -7,6 +7,8 @@ #### https://github.com/mainsail-crew/crowsnest #### #### This File is distributed under GPLv3 +#### +#### Version 2 ### Disable shellcheck Errors # shellcheck disable=SC2012,SC2206 @@ -139,9 +141,9 @@ function initial_check { log_msg "INFO: Checking Dependencys" check_dep "logger" check_dep "crudini" - check_dep "mjpg_streamer" check_dep "ustreamer" check_dep "v4l2rtspserver" + # check_dep "rtsp-simple-server" # Stay for later use. if [ -z "$(check_cfg "${WEBCAMD_CFG}")" ]; then if [ "$(log_level)" != "quiet" ]; then print_cfg @@ -246,11 +248,7 @@ function construct_streamer { log_msg "Try to start configured Cams / Services..." for (( i=0; i<"${#cams[@]}"; i++ )); do stream_server="$(get_param "cam ${cams[$i]}" streamer 2> /dev/null)" - if [ "${stream_server}" == "mjpg" ]; then - run_mjpg "${cams[$i]}" & - sleep 8 & sleep_pid="$!" - wait "${sleep_pid}" - elif [ "${stream_server}" == "ustreamer" ]; then + if [ "${stream_server}" == "ustreamer" ]; then run_ustreamer "${cams[$i]}" & sleep 8 & sleep_pid="$!" wait "${sleep_pid}" @@ -265,47 +263,6 @@ function construct_streamer { log_msg "... Done!" } -function run_mjpg { - local cam_section mjpg_bin device port resolution fps custom - local raspicam split_res output input wwwroot - cam_section="${1}" - mjpg_bin="$(whereis mjpg_streamer | awk '{print $2}')" - # shellcheck disable=2046 - ld_so="$(dirname $(readlink -qe $(whereis mjpg_streamer)))" - device="$(get_param "cam ${cam_section}" device)" - port=$(get_param "cam ${cam_section}" port) - resolution=$(get_param "cam ${cam_section}" resolution) - fps=$(get_param "cam ${cam_section}" max_fps) - wwwroot="$(dirname $(readlink -qe $(whereis webcamd)))/mjpg-www" - custom="$(get_param "cam ${cam_section}" custom_flags 2> /dev/null)" - check_section "${cam_section}" - raspicam="$(v4l2-ctl --list-devices | grep -A1 -e 'mmal' | \ - awk 'NR==2 {print $1}')" - output="${ld_so}/output_http.so -l 127.0.0.1 -p ${port} -n -w ${wwwroot}" - #construct input raspicam/usb cam - if [ "${device}" == "${raspicam}" ]; then - split_res="$(echo "${resolution}" | \ - awk -F 'x' '{print "-x "$1 " -y "$2}')" - input="${ld_so}/input_raspicam.so ${split_res} -fps ${fps}" - else - input="${ld_so}/input_uvc.so -d ${device} -r ${resolution} -f ${fps}" - fi - log_msg "Starting mjpeg-streamer with Device ${device} ..." - # Custom Flag Handling - if [ -n "${custom}" ]; then - echo "Parameters: -i "${input} ${custom}" -o "${output}"" | \ - log_output "mjpg_streamer [cam ${cam_section}]" - "${mjpg_bin}" -i "${input} ${custom}" -o "${output}" 2>&1 | \ - log_output "mjpg_streamer [cam ${cam_section}]" - else - echo -e "Parameters: -i "${input}" -o "${output}" -n -w ${wwwroot}" | \ - log_output "mjpg_streamer [cam ${cam_section}]" - "${mjpg_bin}" -i "${input}" -o "${output} -n -w ${wwwroot}" 2>&1 | \ - log_output "mjpg_streamer [cam ${cam_section}]" - fi - log_msg "ERROR: Start of mjpg_streamer [cam ${cam_section}] failed!" -} - function run_ustreamer { local cam_section ustreamer_bin device port resolution fps custom local raspicam start_param wwwroot @@ -331,7 +288,7 @@ function run_ustreamer { start_param=( -d "${device}" -r "${resolution}" -f "${fps}" --host 127.0.0.1 -p "${port}" --allow-origin=\* - --device-timeout=2 --encoder=omx --static "${wwwroot}" + --device-timeout=2 --static "${wwwroot}" ) fi # Custom Flag Handling