From 95c1dca13f794eb2de521b84186b3fd6e7efa3f3 Mon Sep 17 00:00:00 2001 From: Stephan Wendel Date: Sat, 11 Mar 2023 18:57:19 +0100 Subject: [PATCH] feat!: adds camera-streamer to crowsnest This introduces camera-streamer as streamer option via `mode: multi` camera-streamer is a feature packed stream service. It is capable to deliver mjpg/snapshots/webrtc and rtsp Limited to raspberry pi sbc's for now. This should also resolv Feature request #51 Feature request #37 Fixes #83 Closes #85 Fixes #89 BREAKING CHANGES: Dropping support for Debian Buster based images and kernels older than 5.15y Dropping RTSP support due aler9/simple-rtsp-server Dropping usage of ffmpeg No support anymore for Raspicam V1 (EOL) Signed-off-by: Stephan Wendel Signed-off-by: Stephan Wendel --- .gitignore | 4 + Makefile | 10 +- bin/Makefile | 76 --------- bin/build.sh | 221 ++++++++++++++++++++++++++ bin/rtsp-simple-server/version | 1 - crowsnest | 32 ++-- custompios/crowsnest/config | 9 +- libs/camera-streamer.sh | 117 ++++++++++++++ libs/configparser.sh | 32 ++-- libs/core.sh | 44 +++--- libs/hwhandler.sh | 81 +++++----- libs/init_stream.sh | 18 ++- libs/logging.sh | 42 ++--- libs/messages.sh | 11 +- libs/rtspsimple.sh | 80 ---------- libs/ustreamer.sh | 25 +-- libs/v4l2_control.sh | 29 +--- libs/versioncontrol.sh | 42 ++--- libs/watchdog.sh | 6 +- resources/bcm2835-v4l2.conf | 12 -- resources/crowsnest-rtsp.yml | 280 --------------------------------- resources/crowsnest.conf | 9 +- tools/configure.sh | 43 +---- tools/install.sh | 100 ++++++------ tools/uninstall.sh | 18 +-- 25 files changed, 578 insertions(+), 764 deletions(-) delete mode 100644 bin/Makefile create mode 100755 bin/build.sh delete mode 100644 bin/rtsp-simple-server/version create mode 100755 libs/camera-streamer.sh delete mode 100755 libs/rtspsimple.sh delete mode 100644 resources/bcm2835-v4l2.conf delete mode 100644 resources/crowsnest-rtsp.yml diff --git a/.gitignore b/.gitignore index 3669789b..e03ad658 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,10 @@ test* # tmp file workaround lost* +# ignore bin paths +bin/ustreamer +bin/camera-streamer + # Ignore rtsp-simple-server binary bin/rtsp-simple-server/rtsp* bin/rtsp-simple-server/*.yml diff --git a/Makefile b/Makefile index b86f977e..25baf215 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ #### This File is distributed under GPLv3 #### -.PHONY: build buildclean config help install unsinstall +.PHONY: build buildclean config help install unsinstall update # Setup USER = $(shell whoami) @@ -31,6 +31,7 @@ help: @echo " build builds binaries" @echo " buildclean cleans binaries (for recompile)" @echo " clean Removes Installer config" + @echo " update Pulls latest updates from repository" @echo "" install: @@ -40,10 +41,10 @@ uninstall: @bash -c 'tools/uninstall.sh' build: - $(MAKE) -C $(BIN_FOLDER) + bash -c 'bin/build.sh --build' buildclean: - $(MAKE) -C $(BIN_FOLDER) clean + bash -c 'bin/build.sh --clean' clean: @if [ -f tools/.config ]; then rm -f tools/.config; fi @@ -52,6 +53,9 @@ clean: config: @bash -c 'tools/configure.sh' +update: + @git fetch && git pull + report: @if [ -f ~/report.txt ]; then rm -f ~/report.txt; fi @bash -c 'tools/dev-helper.sh -a >> ~/report.txt' diff --git a/bin/Makefile b/bin/Makefile deleted file mode 100644 index 772d16f9..00000000 --- a/bin/Makefile +++ /dev/null @@ -1,76 +0,0 @@ -#### crowsnest - A webcam Service for multiple Cams and Stream Services. -#### -#### Written by Stephan Wendel aka KwadFan -#### Copyright 2021 -#### https://github.com/mainsail-crew/crowsnest -#### -#### This File is distributed under GPLv3 -#### -#### This Makefile is intended to streamline the build of depending binaries. - -#### DO NOT MODIFY AT ALL! #### - -# Setup -.PHONY: all clean ustreamer rtsp webrtc update - -# Paths -USTREAMER_PATH = ustreamer -USTREAMER_REPO = https://github.com/pikvm/ustreamer.git -USTREAMER_OMX_BRANCH = 61ab2a8 -ARCH = $(shell uname -m) -RTSP_PATH = rtsp-simple-server -RTSP_ARCH = $(shell uname -m | cut -c '-5' | sed 's/x86_6/amd64/;s/aarch/arm64v8/') -RTSP_VERSION = $(shell cat $(RTSP_PATH)/version) -DL_RTSP = https://github.com/aler9/rtsp-simple-server/releases/download/$(RTSP_VERSION)/ -RTSP_ARCHIVE = rtsp-simple-server_$(RTSP_VERSION)_linux_$(RTSP_ARCH).tar.gz - -# Custom Flags -MAKEFLAGS += -j$(shell nproc) - -# OpenMAX IL Support -OMX_SUPPORT = $(shell [ -d /opt/vc/include ] && echo 1 || echo 0) - -# Ustreamer cloned? -USTREAMER_EXIST = $(shell [ -d ustreamer ] > /dev/null && echo 1 || echo 0) - -all: -ifeq ($(USTREAMER_EXIST), 0) - $(info INFO: ustreamer not found, cloning repository.) - $(shell git clone $(USTREAMER_REPO) ustreamer) -else - $(info INFO: ustreamer found.) -endif - $(MAKE) ustreamer-bin - $(MAKE) rtsp - -# Build ustreamer -ustreamer-bin: -ifeq ($(OMX_SUPPORT), 1) - $(info Compiling ustreamer with OMX Support.) - $(info Changening to commit '$(USTREAMER_OMX_BRANCH)' ) - $(shell cd ustreamer; git reset -q --hard $(USTREAMER_OMX_BRANCH) \ - ; cd ..) - WITH_OMX=1 $(MAKE) -C $(USTREAMER_PATH) -else - $(info Compiling ustreamer without OMX Support.) - $(MAKE) -C $(USTREAMER_PATH) -endif - -# Download rtsp-simple-server -rtsp: - $(info Download $(RTSP_ARCHIVE) from $(DL_RTSP)) - $(shell curl -JLo $(RTSP_PATH)/$(RTSP_ARCHIVE) $(DL_RTSP)$(RTSP_ARCHIVE)) - $(shell tar -C $(RTSP_PATH) -xf $(RTSP_PATH)/$(RTSP_ARCHIVE)) - $(shell rm -f $(RTSP_PATH)/$(RTSP_ARCHIVE)) - $(info Finished.) -# Dirty Hack needed to prevent "make: Nothing to be done for 'rtsp'." message - @echo > /dev/null - -clean: - $(MAKE) -C $(USTREAMER_PATH) clean - $(info Clean rtsp-simple-server ...) - $(shell rm -rf $(RTSP_PATH)/rtsp*) - -update: - $(MAKE) clean - $(MAKE) all diff --git a/bin/build.sh b/bin/build.sh new file mode 100755 index 00000000..1eeb9ef6 --- /dev/null +++ b/bin/build.sh @@ -0,0 +1,221 @@ +#!/usr/bin/env bash + +#### crowsnest - A webcam Service for multiple Cams and Stream Services. +#### +#### Written by Stephan Wendel aka KwadFan +#### Copyright 2021 - till today +#### https://github.com/mainsail-crew/crowsnest +#### +#### This File is distributed under GPLv3 +#### + +# shellcheck enable=require-variable-braces + +### Disable SC2317 due Trap usage +# shellcheck disable=SC2317 + +# Exit on errors +set -Ee + +# Debug +# set -x + +# Global vars +# Base Path +BASE_CN_BIN_PATH="$(dirname "$(readlink -f "${0}")")" + +# Clone Flags +CLONE_FLAGS=(--depth=1 --single-branch) + +# Ustreamer repo +USTREAMER_PATH="ustreamer" +if [[ -z "${CROWSNEST_USTREAMER_REPO_SHIP}" ]]; then + CROWSNEST_USTREAMER_REPO_SHIP="https://github.com/pikvm/ustreamer.git" +fi +if [[ -z "${CROWSNEST_USTREAMER_REPO_BRANCH}" ]]; then + CROWSNEST_USTREAMER_REPO_BRANCH="master" +fi + +# Camera-streamer repo +CSTREAMER_PATH="camera-streamer" +if [[ -z "${CROWSNEST_CAMERA_STREAMER_REPO_SHIP}" ]]; then + CROWSNEST_CAMERA_STREAMER_REPO_SHIP="https://github.com/ayufan-research/camera-streamer.git" +fi +if [[ -z "${CROWSNEST_CAMERA_STREAMER_REPO_BRANCH}" ]]; then + CROWSNEST_CAMERA_STREAMER_REPO_BRANCH="master" +fi + + +# Paths of repos +ALL_PATHS=( + "${BASE_CN_BIN_PATH}"/"${USTREAMER_PATH}" + "${BASE_CN_BIN_PATH}"/"${CSTREAMER_PATH}" +) + +# Helper messages +show_help() { + printf "Usage %s [options]\n" "$(basename "${0}")" + printf "\t-h or --help\t\tShows this help message\n" + printf "\t-b or --build\t\tBuild Apps\n" + printf "\t-c or --clean\t\tClean Apps\n" + printf "\t-d or --delete\t\tDelete cloned Apps\n" + printf "\t-r or --reclone\t\tClone Apps again\n\n" +} + +## Helper funcs +### Check if device is Raspberry Pi +is_raspberry_pi() { + if [[ -f /proc/device-tree/model ]] && + grep -q "Raspberry" /proc/device-tree/model; then + echo "1" + else + echo "0" + fi +} + +### Get avail mem +get_avail_mem() { + grep "MemTotal" /proc/meminfo | awk '{print $2}' +} + +## MAIN funcs +### Delete repo folder +delete_apps() { + for path in "${ALL_PATHS[@]}"; do + if [[ ! -d "${path}" ]]; then + printf "'%s' does not exist! Delete skipped ...\n" "${path}" + fi + if [[ -d "${path}" ]]; then + printf "Deleting '%s' ... \n" "${path}" + rm -rf "${path}" + fi + done +} + +### Clone ustreamer +clone_ustreamer() { + if [[ -d "${BASE_CN_BIN_PATH}"/"${USTREAMER_PATH}" ]]; then + printf "%s already exist ... [SKIPPED]\n" "${USTREAMER_PATH}" + return + fi + git clone "${CROWSNEST_USTREAMER_REPO_SHIP}" \ + -b "${CROWSNEST_USTREAMER_REPO_BRANCH}" \ + "${BASE_CN_BIN_PATH}"/"${USTREAMER_PATH}" \ + "${CLONE_FLAGS[@]}" +} + +### Clone camera-streamer +clone_cstreamer() { + ## Special handling because only supported on Raspberry Pi + [[ -n "${CROWSNEST_UNATTENDED}" ]] || CROWSNEST_UNATTENDED="0" + if [[ "$(is_raspberry_pi)" = "0" ]] && [[ "${CROWSNEST_UNATTENDED}" = "0" ]]; then + printf "WARN: Cloning camera-streamer skipped! Device is not supported!" + return + fi + if [[ -d "${BASE_CN_BIN_PATH}"/"${CSTREAMER_PATH}" ]]; then + printf "%s already exist ... [SKIPPED]\n" "${CSTREAMER_PATH}" + return + fi + git clone "${CROWSNEST_CAMERA_STREAMER_REPO_SHIP}" \ + -b "${CROWSNEST_CAMERA_STREAMER_REPO_BRANCH}" \ + "${BASE_CN_BIN_PATH}"/"${CSTREAMER_PATH}" \ + "${CLONE_FLAGS[@]}" --recursive +} + +### Clone Apps +clone_apps() { + local apps + apps="ustreamer cstreamer" + for app in ${apps}; do + clone_"${app}" + done +} + +### Run 'make clean' in cloned folders +clean_apps() { + for app in "${ALL_PATHS[@]}"; do + printf "\nRunning 'make clean' in %s ... \n" "${app}" + pushd "${app}" &> /dev/null || exit 1 + make clean + popd &> /dev/null || exit 1 + done + printf "\nRunning 'make clean' ... [DONE]\n" +} + +build_apps() { + ## Determine Ramsize and export MAKEFLAG + if [[ "$(get_avail_mem)" -le 524288 ]]; then + USE_PROCS=-j1 + fi + if [[ "$(get_avail_mem)" -le 1048576 ]]; then + USE_PROCS=-j2 + fi + if [[ "$(get_avail_mem)" -gt 1048576 ]]; then + USE_PROCS=-j4 + fi + for path in "${ALL_PATHS[@]}"; do + if [[ ! -d "${path}" ]]; then + printf "'%s' does not exist! Build skipped ... [WARN]\n" "${path}" + fi + if [[ -d "${path}" ]]; then + printf "Build '%s' using ${USE_PROCS##-j} Cores ... \n" "${path##*/}" + pushd "${path}" &> /dev/null || exit 1 + make "${USE_PROCS}" + popd &> /dev/null || exit 1 + printf "Build '%s' ... [SUCCESS]\n" "${path##*/}" + fi + done +} + +## MAIN FUNC +main() { + ## Error exit if no args given, show help + if [[ $# -eq "0" ]]; then + printf "ERROR: No options given ...\n" + show_help + exit 1 + fi + ## Error exit if too many args given + if [[ $# -gt "1" ]]; then + printf "ERROR: Too many options given ...\n" + show_help + exit 1 + fi + ## Get opts + while true; do + case "${1}" in + -b|--build) + build_apps + break + ;; + -c|--clean) + clean_apps + break + ;; + -d|--delete) + delete_apps + break + ;; + -h|--help) + show_help + break + ;; + -r|--reclone) + delete_apps + clone_apps + break + ;; + *) + printf "Unknown option: %s" "${1}" + show_help + break + ;; + esac + done +} + +#### MAIN +main "${@}" +exit 0 + +#### EOF diff --git a/bin/rtsp-simple-server/version b/bin/rtsp-simple-server/version deleted file mode 100644 index 9c6ae028..00000000 --- a/bin/rtsp-simple-server/version +++ /dev/null @@ -1 +0,0 @@ -v0.20.2 diff --git a/crowsnest b/crowsnest index 95d6bc31..1454fa0f 100755 --- a/crowsnest +++ b/crowsnest @@ -20,18 +20,18 @@ set -Ee BASE_CN_PATH="$(dirname "$(readlink -f "${0}")")" ## Import Librarys -# shellcheck source-path=SCRIPTDIR/libs/ -source "${BASE_CN_PATH}/libs/configparser.sh" -source "${BASE_CN_PATH}/libs/core.sh" -source "${BASE_CN_PATH}/libs/hwhandler.sh" -source "${BASE_CN_PATH}/libs/init_stream.sh" -source "${BASE_CN_PATH}/libs/logging.sh" -source "${BASE_CN_PATH}/libs/messages.sh" -source "${BASE_CN_PATH}/libs/rtspsimple.sh" -source "${BASE_CN_PATH}/libs/ustreamer.sh" -source "${BASE_CN_PATH}/libs/v4l2_control.sh" -source "${BASE_CN_PATH}/libs/versioncontrol.sh" -source "${BASE_CN_PATH}/libs/watchdog.sh" +# shellcheck source-path=SCRIPTDIR/../libs/ +. "${BASE_CN_PATH}/libs/camera-streamer.sh" +. "${BASE_CN_PATH}/libs/configparser.sh" +. "${BASE_CN_PATH}/libs/core.sh" +. "${BASE_CN_PATH}/libs/hwhandler.sh" +. "${BASE_CN_PATH}/libs/init_stream.sh" +. "${BASE_CN_PATH}/libs/logging.sh" +. "${BASE_CN_PATH}/libs/messages.sh" +. "${BASE_CN_PATH}/libs/ustreamer.sh" +. "${BASE_CN_PATH}/libs/v4l2_control.sh" +. "${BASE_CN_PATH}/libs/versioncontrol.sh" +. "${BASE_CN_PATH}/libs/watchdog.sh" #### MAIN ## Args given? @@ -41,7 +41,7 @@ if [ "$#" -eq 0 ]; then fi ## Parse Args -while getopts ":vhc:" arg; do +while getopts ":vhc:d" arg; do case "${arg}" in v ) echo -e "\ncrowsnest Version: $(self_version)\n" @@ -55,6 +55,9 @@ while getopts ":vhc:" arg; do check_cfg "${OPTARG}" export CROWSNEST_CFG="${OPTARG}" ;; + d ) + set -x + ;; \?) wrong_args_msg exit 1 @@ -64,10 +67,7 @@ done init_logging initial_check -v4l2_control -blockyfix construct_streamer -brokenfocus ## Loop and Watchdog ## In this case watchdog acts more like a "cable defect detector" diff --git a/custompios/crowsnest/config b/custompios/crowsnest/config index 3074515d..4ebf455b 100644 --- a/custompios/crowsnest/config +++ b/custompios/crowsnest/config @@ -10,15 +10,14 @@ # shellcheck disable=all # crowsnest repo -[[ -n "$CROWSNEST_REPO_SHIP" ]] || CROWSNEST_REPO_SHIP=https://github.com/mainsail-crew/crowsnest.git -[[ -n "$CROWSNEST_REPO_BRANCH" ]] || CROWSNEST_REPO_BRANCH=master +[[ -n "$CROWSNEST_REPO_SHIP" ]] || CROWSNEST_REPO_SHIP="https://github.com/mainsail-crew/crowsnest.git" +[[ -n "$CROWSNEST_REPO_BRANCH" ]] || CROWSNEST_REPO_BRANCH="master" # crowsnest setup [[ -n "$CROWSNEST_DEFAULT_CONF" ]] || CROWSNEST_DEFAULT_CONF="resources/crowsnest.conf" [[ -n "$CROWSNEST_CONFIG_PATH" ]] || CROWSNEST_CONFIG_PATH="/home/${BASE_USER}/printer_data/config" [[ -n "$CROWSNEST_LOG_PATH" ]] || CROWSNEST_LOG_PATH="/home/${BASE_USER}/printer_data/logs" [[ -n "$CROWSNEST_ENV_PATH" ]] || CROWSNEST_ENV_PATH="/home/${BASE_USER}/printer_data/systemd" -[[ -n "$CROWSNEST_RASPICAMFIX" ]] || CROWSNEST_RASPICAMFIX="1" [[ -n "$CROWSNEST_ADD_CROWSNEST_MOONRAKER" ]] || CROWSNEST_ADD_CROWSNEST_MOONRAKER="1" [[ -n "$CROWSNEST_MOONRAKER_CONF_PATH" ]] || CROWSNEST_MOONRAKER_CONF_PATH="/home/${BASE_USER}/printer_data/config/moonraker.conf" @@ -27,6 +26,10 @@ [[ -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" +# camera-streamer +[[ -n "$CROWSNEST_CAMERA_STREAMER_REPO_SHIP" ]] || CROWSNEST_CAMERA_STREAMER_REPO_SHIP="https://github.com/ayufan/camera-streamer.git" +[[ -n "$CROWSNEST_CAMERA_STREAMER_REPO_BRANCH" ]] || CROWSNEST_CAMERA_STREAMER_REPO_BRANCH="master" + ########################################################################### ### DO NOT EDIT BELOW THIS LINE, UNLESS YOU KNOW EXACTLY WHAT HAPPENDS! ### ########################################################################### diff --git a/libs/camera-streamer.sh b/libs/camera-streamer.sh new file mode 100755 index 00000000..885557d6 --- /dev/null +++ b/libs/camera-streamer.sh @@ -0,0 +1,117 @@ +#!/bin/bash + +#### camera-streamer library + +#### crowsnest - A webcam Service for multiple Cams and Stream Services. +#### +#### Written by Stephan Wendel aka KwadFan +#### Copyright 2021 - 2022 +#### https://github.com/mainsail-crew/crowsnest +#### +#### This File is distributed under GPLv3 +#### + +# shellcheck enable=require-variable-braces + +# Exit upon Errors +set -Ee + +function run_multi() { + local cams + cams="${1}" + for instance in ${cams} ; do + run_ayucamstream "${instance}" & + done +} + +function run_ayucamstream() { + local cam_sec ust_bin dev pt res rtsp rtsp_pt fps cstm start_param + local v4l2ctl + cam_sec="${1}" + ust_bin="${BASE_CN_PATH}/bin/camera-streamer/camera-streamer" + dev="$(get_param "cam ${cam_sec}" device)" + pt=$(get_param "cam ${cam_sec}" port) + res=$(get_param "cam ${cam_sec}" resolution) + fps=$(get_param "cam ${cam_sec}" max_fps) + rtsp=$(get_param "cam ${cam_sec}" enable_rtsp) + rtsp_pt=$(get_param "cam ${cam_sec}" rtsp_port) + cstm="$(get_param "cam ${cam_sec}" custom_flags 2> /dev/null)" + ## construct start parameter + # set http port + # + start_param=( --http-port="${pt}" ) + + # Set device + start_param+=( --camera-path="${dev}" ) + + # Detect libcamera device and add start param accordingly + if [[ "${dev}" =~ "/base/soc" ]]; then + start_param+=( --camera-type=libcamera ) + start_param+=( --camera-format=YUYV ) + fi + + if [[ "${dev}" =~ "/dev/video" ]] || + [[ "${dev}" =~ "/dev/v4l/" ]]; then + start_param+=( --camera-type=v4l2 ) + fi + + # Use MJPEG Hardware encoder if possible + if [ "$(detect_mjpeg "${cam_sec}")" = "1" ] && + [[ ! "${dev}" =~ "/base/soc" ]]; then + start_param+=( --camera-format=MJPG ) + fi + + # Set resolution + get_height_val() { + (sed 's/#.*//' | cut -d'x' -f2) <<< "${res}" + } + get_width_val() { + (sed 's/#.*//' | cut -d'x' -f1) <<< "${res}" + } + + # Set snapshot heigth to 1080p by default + start_param+=( --camera-snapshot.height=1080 ) + + start_param+=( --camera-width="$(get_width_val)" ) + start_param+=( --camera-height="$(get_height_val)" ) + + # Set FPS + start_param+=( --camera-fps="${fps}" ) + + # Enable rtsp, if set true + if [[ -n "${rtsp}" ]] && [[ "${rtsp}" == "true" ]]; then + # ensure a port is set + start_param+=( --rtsp-port="${rtsp_pt:-8554}" ) + fi + + # Enable camera-auto_reconnect by default + start_param+=( --camera-auto_reconnect=1 ) + + # Custom Flag Handling (append to defaults) + if [[ -n "${cstm}" ]]; then + start_param+=( "${cstm}" ) + fi + + # v4l2 option handling + v4l2ctl="$(get_param "cam ${cam_sec}" v4l2ctl)" + if [ -n "${v4l2ctl}" ]; then + IFS="," read -ra opt < <(echo "${v4l2ctl}" | tr -d " "); unset IFS + log_msg "V4L2 Control: Handling done by camera-streamer ..." + log_msg "V4L2 Control: Trying to set: ${v4l2ctl}" + # loop through options + for param in "${opt[@]}"; do + start_param+=( --camera-options="${param}" ) + done + fi + + + # Log start_param + log_msg "Starting camera-streamer with Device ${dev} ..." + echo "Parameters: ${start_param[*]}" | \ + log_output "camera-streamer [cam ${cam_sec}]" + # Start camera-streamer + echo "${start_param[*]}" | xargs "${ust_bin}" 2>&1 | \ + log_output "camera-streamer [cam ${cam_sec}]" + # Should not be seen else failed. + log_msg "ERROR: Start of camera-streamer [cam ${cam_sec}] failed!" +} diff --git a/libs/configparser.sh b/libs/configparser.sh index 50192946..60acb80d 100755 --- a/libs/configparser.sh +++ b/libs/configparser.sh @@ -26,6 +26,7 @@ function get_param { param="${2}" crudini --get "${cfg}" "${section}" "${param}" 2> /dev/null | \ sed 's/\#.*//;s/[[:space:]]*$//' + return } # Check for existing file @@ -34,6 +35,8 @@ function check_cfg { if [ ! -r "${1}" ]; then log_msg "ERROR: No Configuration File found. Exiting!" exit 1 + else + return 0 fi } @@ -46,12 +49,14 @@ function configured_cams { cams+=("${i}") done echo "${cams[@]}" + return } # Checks [cam ] if all needed configuration sections are present # call check_section ex.: check_section foobar function check_section { - local section exist param must_exist missing + local section exist param + local -a must_exist missing section="cam ${1}" # Ignore missing custom flags exist="$(crudini --existing=param --get "${CROWSNEST_CFG}" "${section}" \ @@ -67,15 +72,22 @@ function check_section { fi done must_exist=(mode port device resolution max_fps) - missing="$(echo "${param[@]}" "${must_exist[@]}" | \ - tr ' ' '\n' | sort | uniq -u)" - for i in "${missing[@]}"; do - if [ -n "${i}" ]; then - log_msg "ERROR: Parameter ${missing} not found in \ - Section [${section}]. Start skipped!" - else - log_msg "INFO: Configuration of Section [${section}] looks good. \ - Continue..." + missing=() + for i in "${must_exist[@]}"; do + if [[ -z "$(get_param "${section}" "${i}")" ]]; then + missing+=("${i}") fi done + + if [[ "${#missing[@]}" != "0" ]]; then + for param in "${missing[@]}"; do + log_msg "ERROR: Parameter ${param} not found in Section [${section}]." + done + log_msg "ERROR: Please check your configuration!" + exit 1 + fi + if [[ "${#missing[@]}" == "0" ]]; then + log_msg "INFO: Configuration of Section [${section}] looks good. Continue ..." + fi + return } diff --git a/libs/core.sh b/libs/core.sh index cc659a0a..c6531109 100755 --- a/libs/core.sh +++ b/libs/core.sh @@ -66,7 +66,7 @@ function shutdown { function check_dep { local dep dep="$(whereis "${1}" | awk '{print $2}')" - if [ -z "${dep}" ]; then + if [[ -z "${dep}" ]]; then log_msg "Dependency: '${1}' not found. Exiting!" exit 1 else @@ -75,30 +75,25 @@ function check_dep { } function check_apps { - local paths - paths=( - bin/ustreamer/ustreamer - bin/rtsp-simple-server/rtsp-simple-server - ) - for chk in "${paths[@]}"; do - if [ -x "${BASE_CN_PATH}/${chk}" ]; then - log_msg "Dependency: '$(echo "${chk}" | cut -d '/' -f3)' found in ${chk}." + local cstreamer ustreamer + ustreamer="bin/ustreamer/ustreamer" + cstreamer="bin/camera-streamer/camera-streamer" + + if [[ -x "${BASE_CN_PATH}/${ustreamer}" ]]; then + log_msg "Dependency: '${ustreamer##*/}' found in ${ustreamer}." + else + log_msg "Dependency: '${ustreamer##*/}' not found. Exiting!" + exit 1 + fi + + ## Avoid dependency check if non rpi sbc + if [[ "$(is_raspberry_pi)" = "1" ]]; then + if [[ -x "${BASE_CN_PATH}/${cstreamer}" ]]; then + log_msg "Dependency: '${cstreamer##*/}' found in ${cstreamer}." else - log_msg "Dependency: '$(echo "${chk}" | cut -d '/' -f3)' not found. Exiting!" + log_msg "Dependency: '${cstreamer##*/}' not found. Exiting!" exit 1 fi - done -} - -# checks availability of OpenMax IL feature on host and in apps. -# 0 = false / 1 = true -function check_omx { - if [ -d "/opt/vc/include" ] && - [ ! "$(ffmpeg -hide_banner -buildconf | grep -c 'omx')" = "0" ] && - [ "$("${BASE_CN_PATH}"/bin/ustreamer/ustreamer --features | grep -c '\+ WITH_OMX')" = "1" ]; then - echo "1" - else - echo "0" fi } @@ -110,9 +105,7 @@ function initial_check { log_msg "INFO: Checking Dependencys" check_dep "crudini" check_dep "find" - check_dep "logger" check_dep "xargs" - check_dep "ffmpeg" check_apps versioncontrol # print cfg if ! "${CROWSNEST_LOG_LEVEL}": quiet @@ -121,8 +114,7 @@ function initial_check { print_cfg fi fi - # in systemd show always config file - logger -t crowsnest -f "${CROWSNEST_CFG}" log_msg "INFO: Detect available Devices" print_cams + return } diff --git a/libs/hwhandler.sh b/libs/hwhandler.sh index 02615c60..2d3831e4 100755 --- a/libs/hwhandler.sh +++ b/libs/hwhandler.sh @@ -23,7 +23,7 @@ function detect_avail_cams { count="$(echo "${avail}" | wc -l)" if [[ -d "/dev/v4l/by-id/" ]] && [[ -n "${avail}" ]]; then - log_msg "INFO: Found ${count} available camera(s)" + log_msg "INFO: Found ${count} available v4l2 (UVC) camera(s)" echo "${avail}" | while read -r v4l; do realpath=$(readlink -e "${v4l}") log_msg "${v4l} -> ${realpath}" @@ -37,74 +37,69 @@ function detect_avail_cams { fi } -function detect_avail_csi { - local avail count realpath - avail="$(find /dev/v4l/by-path/ -iname "*csi*index0" 2> /dev/null)" - count="$(echo "${avail}" | wc -l)" - if [[ -d "/dev/v4l/by-path/" ]] && - [[ -n "${avail}" ]]; then - log_msg "INFO: Found ${count} available csi device(s)" - echo "${avail}" | while read -r csi; do - realpath=$(readlink -e "${csi}") - log_msg "${csi} -> ${realpath}" - done - else - log_msg "INFO: No usable CSI Devices found." - fi -} - -# Used for "verbose" and "debug" logging in logging.sh +## Used for "verbose" and "debug" logging in logging.sh function list_cam_formats { - local device formats + local device prefix device="${1}" - formats="$(v4l2-ctl -d "${device}" --list-formats-ext | sed '1,3d')" + prefix="$(date +'[%D %T]') crowsnest:" log_msg "Supported Formats:" - echo "${formats}" | while read -r i; do - log_msg "\t\t${i}" - done + while read -r i; do + printf "%s\t\t%s\n" "${prefix}" "${i}" >> "${CROWSNEST_LOG_PATH}" + done < <(v4l2-ctl -d "${device}" --list-formats-ext | sed '1,3d') } function list_cam_v4l2ctrls { - local device ctrls + local device prefix device="${1}" - ctrls="$(v4l2-ctl -d "${device}" --list-ctrls-menus)" + prefix="$(date +'[%D %T]') crowsnest:" log_msg "Supported Controls:" - echo "${ctrls}" | while read -r i; do - log_msg "\t\t${i}" - done + while read -r i; do + printf "%s\t\t%s\n" "${prefix}" "${i}" >> "${CROWSNEST_LOG_PATH}" + done < <(v4l2-ctl -d "${device}" --list-ctrls-menus) } -# Determine connected "raspicam" device -function detect_raspicam { +## Determine connected libcamera (CSI) device +function detect_libcamera { local avail if [[ -f /proc/device-tree/model ]] && grep -q "Raspberry" /proc/device-tree/model; then - avail="$(vcgencmd get_camera | awk -F '=' '{ print $3 }' | cut -d',' -f1)" - else - avail="0" + vcgencmd get_camera | grep -c "libcamera interfaces=1" || true fi - echo "${avail}" } -function dev_is_raspicam { - v4l2-ctl --list-devices | grep -A1 -e 'mmal' | \ - awk 'NR==2 {print $1}' +## Spit /base/soc path for libcamera device +function get_libcamera_path { + if [[ -f /proc/device-tree/model ]] && + [[ -x "$(command -v libcamera-hello)" ]]; then + libcamera-hello --list-cameras | sed '1,2d' \ + | grep "\(/base/*\)" | cut -d"(" -f2 | tr -d '$)' + fi } -# Determine if cam has H.264 Hardware encoder -# call detect_h264 ex.: detect_h264 foobar -# returns 1 = true / 0 = false ( numbers are strings! not int!) +## Determine if cam has H.264 Hardware encoder +## call detect_h264 ex.: detect_h264 foobar +## returns 1 = true / 0 = false ( numbers are strings! not int!) function detect_h264 { local dev dev="$(get_param "cam ${1}" device)" v4l2-ctl -d "${dev}" --list-formats-ext | grep -c "[hH]264" } -# Determine if cam has MJPEG Hardware encoder -# call detect_mjpeg ex.: detect_mjpeg foobar -# returns 1 = true / 0 = false ( numbers are strings! not int!) +## Determine if cam has MJPEG Hardware encoder +## call detect_mjpeg ex.: detect_mjpeg foobar +## returns 1 = true / 0 = false ( numbers are strings! not int!) function detect_mjpeg { local dev dev="$(get_param "cam ${1}" device)" v4l2-ctl -d "${dev}" --list-formats-ext | grep -c "Motion-JPEG, compressed" } + +## Check if device is raspberry sbc +is_raspberry_pi() { + if [[ -f /proc/device-tree/model ]] && + grep -q "Raspberry" /proc/device-tree/model; then + echo "1" + else + echo "0" + fi +} diff --git a/libs/init_stream.sh b/libs/init_stream.sh index e4995809..ab3ba2c9 100755 --- a/libs/init_stream.sh +++ b/libs/init_stream.sh @@ -26,12 +26,18 @@ function construct_streamer { mode="$(get_param "cam ${cams}" mode)" check_section "${cams}" case ${mode} in + [mM]ulti) + if [[ "$(is_raspberry_pi)" = "1" ]]; then + MULTI_INSTANCES+=( "${cams}" ) + else + log_msg "WARN: Mode 'multi' is not supported on your device!" + log_msg "WARN: Falling back to Mode 'mjpg'" + MJPG_INSTANCES+=( "${cams}" ) + fi + ;; mjpg | mjpeg) MJPG_INSTANCES+=( "${cams}" ) ;; - rtsp) - RTSP_INSTANCES+=( "${cams}" ) - ;; ?|*) unknown_mode_msg MJPG_INSTANCES+=( "${cams}" ) @@ -39,12 +45,12 @@ function construct_streamer { ;; esac done + if [ "${#MULTI_INSTANCES[@]}" != "0" ]; then + run_multi "${MULTI_INSTANCES[*]}" + fi if [ "${#MJPG_INSTANCES[@]}" != "0" ]; then run_mjpg "${MJPG_INSTANCES[*]}" fi - if [ "${#RTSP_INSTANCES[@]}" != "0" ]; then - run_rtsp "${RTSP_INSTANCES[*]}" - fi sleep 2 & sleep_pid="$!" ; wait "${sleep_pid}" log_msg " ... Done!" } diff --git a/libs/logging.sh b/libs/logging.sh index 7cbdbf21..43a38cec 100755 --- a/libs/logging.sh +++ b/libs/logging.sh @@ -61,8 +61,8 @@ function log_msg { local msg prefix msg="${1}" prefix="$(date +'[%D %T]') crowsnest:" - echo -e "${prefix} ${msg}" | tr -s ' ' | tee -a "${CROWSNEST_LOG_PATH}" 2>&1 - echo -e "${msg}" | logger -t crowsnest + printf "%s %s\n" "${prefix}" "${msg}" >> "${CROWSNEST_LOG_PATH}" + printf "%s\n" "${msg}" } #call '| log_output ""' @@ -73,49 +73,36 @@ function log_output { if [[ "${CROWSNEST_LOG_LEVEL}" = "debug" ]]; then log_msg "${prefix}: ${line}" fi - if [[ -n "${line}" ]]; then - # needed to prettify ustreamers output - echo "${line//^--/ustreamer}" | logger -t crowsnest - fi done } function print_cfg { local prefix - prefix="\t\t" + prefix="$(date +'[%D %T]') crowsnest:" log_msg "INFO: Print Configfile: '${CROWSNEST_CFG}'" (sed '/^#.*/d;/./,$!d' | cut -d'#' -f1) < "${CROWSNEST_CFG}" | \ while read -r line; do - log_msg "${prefix}${line}" + printf "%s\t\t%s\n" "${prefix}" "${line}" >> "${CROWSNEST_LOG_PATH}" + printf "\t\t%s\n" "${line}" done } function print_cams { - local csi raspicam total v4l + local total v4l v4l="$(find /dev/v4l/by-id/ -iname "*index0" 2> /dev/null | wc -l)" - csi="$(find /dev/v4l/by-path/ -iname "*csi*index0" 2> /dev/null | wc -l)" - total="$((v4l+$(detect_raspicam)+csi))" - if [[ "${total}" -eq 0 ]]; then + total="$((v4l+($(detect_libcamera))))" + if [ "${total}" -eq 0 ]; then log_msg "ERROR: No usable Devices Found. Stopping $(basename "${0}")." exit 1 else log_msg "INFO: Found ${total} total available Device(s)" fi - if [[ "$(detect_raspicam)" -ne 0 ]]; then - raspicam="$(v4l2-ctl --list-devices | grep -A1 -e 'mmal' | \ - awk 'NR==2 {print $1}')" - log_msg "Detected 'Raspicam' Device -> ${raspicam}" - if [[ ! "${CROWSNEST_LOG_LEVEL}" = "quiet" ]]; then - list_cam_formats "${raspicam}" - list_cam_v4l2ctrls "${raspicam}" - fi + if [[ "$(detect_libcamera)" -ne 0 ]]; then + log_msg "Detected 'libcamera' device -> $(get_libcamera_path)" fi if [[ -d "/dev/v4l/by-id/" ]]; then detect_avail_cams fi - if [[ -d "/dev/v4l/by-path" ]]; then - detect_avail_csi - fi } function print_host { @@ -156,12 +143,3 @@ function print_host { log_msg "Host Info: Diskspace (avail. / total): ${disksize}" fi } - -function debug_msg { - local prefix - prefix="Develop -- DEBUG:" - while read -r msg; do - log_msg "${prefix} ${msg}" - echo -e "${msg}" | logger -t crowsnest - done <<< "${1}" -} diff --git a/libs/messages.sh b/libs/messages.sh index ebfb99e4..90eedb0c 100755 --- a/libs/messages.sh +++ b/libs/messages.sh @@ -39,7 +39,7 @@ function help_msg { function deprecated_msg_1 { log_msg "Parameter 'streamer' is deprecated!" - log_msg "Please use mode: [ mjpg | rtsp ]" + log_msg "Please use mode: [ mjpg | multi ]" log_msg "ERROR: Please update your crowsnest.conf! Stopped." } @@ -48,15 +48,6 @@ function unknown_mode_msg { log_msg "WARN: Using 'mode: mjpg' as fallback!" } -function provides_omx_msg { - if [ "$(check_omx)" -eq 1 ]; then - log_msg "INFO: System provides OpenMAX IL features." - else - log_msg "WARN: System does not provide OpenMAX IL features." - fi -} - - ## v4l2_control lib function detected_broken_dev_msg { log_msg "WARN: Detected 'brokenfocus' device." diff --git a/libs/rtspsimple.sh b/libs/rtspsimple.sh deleted file mode 100755 index 3e9ec13a..00000000 --- a/libs/rtspsimple.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash - -#### ustreamer library - -#### crowsnest - A webcam Service for multiple Cams and Stream Services. -#### -#### Written by Stephan Wendel aka KwadFan -#### Copyright 2021 -#### https://github.com/mainsail-crew/crowsnest -#### -#### This File is distributed under GPLv3 -#### - -# shellcheck enable=require-variable-braces - -# Exit upon Errors -set -Ee - -run_rtsp() { - local cams - cams="${1}" - if [[ -z "$(pidof rtsp-simple-server)" ]]; then - run_rtsp_srv & - fi - for instance in ${cams} ; do - run_ffmpeg "${instance}" & - done -} - - -run_ffmpeg() { - local cam_section ffmpeg_bin start_param - cam_section="${1}" - ffmpeg_bin="$(whereis ffmpeg | awk '{print $2}')" - dev="$(get_param "cam ${cam_section}" device)" - # Construct start_param - start_param=( -nostdin -hide_banner -f video4linux2 ) - if [[ "$(detect_h264 "${cam_section}")" = "1" ]]; then - start_param+=( -input_format h264 -pix_fmt h264 ) - else - start_param+=( -input_format yuyv422 ) - fi - start_param+=( - -video_size "$(get_param "cam ${cam_section}" resolution)" - -framerate "$(get_param "cam ${cam_section}" max_fps)" - -i "${dev}" - ) - if [[ "$(detect_h264 "${cam_section}")" -eq 0 ]] && - [[ "$(check_omx)" -eq 1 ]]; then - start_param+=( -c:v h264_omx -b:v 8M ) - else - start_param+=( -c:v copy ) - fi - start_param+=(-f rtsp -rtsp_transport tcp rtsp://localhost:8554/"${cam_section}" ) - # Log start_param - log_msg "Starting ffmpeg (rtsp stream source) with Device ${dev} ..." - echo "Parameters: ${start_param[*]}" | \ - log_output "ffmpeg (rtsp stream source) [cam ${cam_section}]" - # Start ffmpeg - echo "${start_param[*]}" | xargs "${ffmpeg_bin}" 2>&1 | \ - log_output "ffmpeg (rtsp stream source) [cam ${cam_section}]" - # Should not be seen else failed. - log_msg "ERROR: Start of ffmpeg (rtsp stream source) [cam ${cam_section}] failed!" -} - -run_rtsp_srv() { - local rtsp_bin config - rtsp_bin="${BASE_CN_PATH}/bin/rtsp-simple-server/rtsp-simple-server" - config="${BASE_CN_PATH}/resources/crowsnest-rtsp.yml" - log_msg "Starting rtsp-simple-server with config ${config} ..." - echo "Config file: ${config}" | \ - log_output "rtsp-simple-server [INFO]" - # Start rtsp-simple-server - # Have to use this dirty bash hack to get output to logfile. - "${rtsp_bin}" "${config}" &> >(log_output "rtsp-simple-server") - # Should not be seen else failed. - log_msg "ERROR: Start of rtsp-simple failed!" - echo "Config file: ${config}" | \ - log_output "rtsp-simple-server [ERROR]" -} diff --git a/libs/ustreamer.sh b/libs/ustreamer.sh index c5739178..aa0140ef 100755 --- a/libs/ustreamer.sh +++ b/libs/ustreamer.sh @@ -18,10 +18,13 @@ set -Ee run_mjpg() { local cams + v4l2_control cams="${1}" for instance in ${cams} ; do run_ustreamer "${instance}" & done + brokenfocus + return } run_ustreamer() { @@ -29,9 +32,9 @@ run_ustreamer() { cam_sec="${1}" ust_bin="${BASE_CN_PATH}/bin/ustreamer/ustreamer" dev="$(get_param "cam ${cam_sec}" device)" - pt=$(get_param "cam ${cam_sec}" port) - res=$(get_param "cam ${cam_sec}" resolution) - fps=$(get_param "cam ${cam_sec}" max_fps) + pt="$(get_param "cam ${cam_sec}" port)" + res="$(get_param "cam ${cam_sec}" resolution)" + fps="$(get_param "cam ${cam_sec}" max_fps)" cstm="$(get_param "cam ${cam_sec}" custom_flags 2> /dev/null)" noprx="$(get_param "crowsnest" no_proxy 2> /dev/null)" # construct start parameter @@ -41,17 +44,15 @@ run_ustreamer() { else start_param=( --host 127.0.0.1 -p "${pt}" ) fi - #Raspicam Workaround - if [[ "${dev}" = "$(dev_is_raspicam)" ]]; then - start_param+=( -m MJPEG --device-timeout=5 --buffers=3 ) - else - start_param+=( -d "${dev}" --device-timeout=2 ) - # Use MJPEG Hardware encoder if possible - if [ "$(detect_mjpeg "${cam_sec}")" = "1" ]; then - start_param+=( -m MJPEG --encoder=HW ) - fi + + # Use MJPEG Hardware encoder if possible + if [ "$(detect_mjpeg "${cam_sec}")" = "1" ]; then + start_param+=( -m MJPEG --encoder=HW ) fi + + # set max framerate start_param+=( -r "${res}" -f "${fps}" ) + # webroot & allow crossdomain requests start_param+=( --allow-origin=\* --static "${BASE_CN_PATH}/ustreamer-www" ) # Custom Flag Handling (append to defaults) diff --git a/libs/v4l2_control.sh b/libs/v4l2_control.sh index b5e9cd87..0cea2bca 100755 --- a/libs/v4l2_control.sh +++ b/libs/v4l2_control.sh @@ -36,7 +36,7 @@ function v4l2_control { v4c_log_msg "Device: [cam ${cam}]" v4c_log_msg "Options: ${v4l2ctl}" # Split options to array - IFS=',' read -ra opt < <(echo "${v4l2ctl}"); unset IFS + IFS="," read -ra opt < <(echo "${v4l2ctl}" | tr -d " "); unset IFS # loop through options for param in "${opt[@]}"; do # parameter available for device @@ -136,30 +136,3 @@ function brokenfocus { main } - -# This function is to set bitrate on raspicams. -# If raspicams set to variable bitrate, they tend to show -# a "block-like" view after reboots -# To prevent that blockyfix should apply constant bitrate befor start of ustreamer -# See https://github.com/mainsail-crew/crowsnest/issues/33 -function blockyfix { - local dev v4l2ctl - - # call set_bitrate - function set_bitrate { - v4l2-ctl -d "${1}" -c video_bitrate_mode=1 2> /dev/null - v4l2-ctl -d "${1}" -c video_bitrate=15000000 2> /dev/null - } - - for cam in $(configured_cams); do - dev="$(get_param "cam ${cam}" device)" - v4l2ctl="$(get_param "cam ${cam}" v4l2ctl)" - if [ "${dev}" = "$(dev_is_raspicam)" ]; then - if [ -z "${v4l2ctl}" ] || - [ "$(grep -c "video_bitrate" <<< "${v4l2ctl}")" == "0" ]; then - set_bitrate "${dev}" - blockyfix_msg_1 - fi - fi - done -} diff --git a/libs/versioncontrol.sh b/libs/versioncontrol.sh index e48dad45..5464fafd 100644 --- a/libs/versioncontrol.sh +++ b/libs/versioncontrol.sh @@ -18,15 +18,15 @@ # Exit upon Errors set -Ee -function versioncontrol { +versioncontrol() { - function vc_log_msg { + vc_log_msg() { log_msg "Version Control: ${1}" } - function get_ustreamer_version { + get_ustreamer_version() { local cur_ver avail_ver - pushd "${BASE_CN_PATH}"/bin/ustreamer || exit 1 + pushd "${BASE_CN_PATH}"/bin/ustreamer &> /dev/null || exit 1 avail_ver="$(git describe --tags --always)" cur_ver="v$("${PWD}"/ustreamer -v)" if [[ "${cur_ver}" == "${avail_ver}" ]]; then @@ -35,24 +35,28 @@ function versioncontrol { if [[ "${cur_ver}" != "${avail_ver}" ]]; then vc_log_msg "ustreamer new version available: ${avail_ver} (${cur_ver})." fi - popd || exit 1 + popd &> /dev/null || exit 1 } - function get_rtsp_version { + + # Camera Streamer has no version Output yet + get_ayucamstream_version() { local cur_ver avail_ver - pushd "${BASE_CN_PATH}"/bin/rtsp-simple-server || exit 1 - avail_ver="$(cat version)" - cur_ver="$("${PWD}"/rtsp-simple-server --version)" - if [[ "${cur_ver}" == "${avail_ver}" ]]; then - vc_log_msg "rtsp-simple-server is up to date. (${cur_ver})" - fi - if [ "${cur_ver}" != "${avail_ver}" ]; then - vc_log_msg "rtsp-simple-server new version available: ${avail_ver} (${cur_ver})." - fi - popd || exit 1 + if [[ "$(is_raspberry_pi)" = "1" ]]; then + pushd "${BASE_CN_PATH}"/bin/camera-streamer &> /dev/null || exit 1 + avail_ver="($(git describe --tags --always))" + cur_ver="$("${PWD}"/camera-streamer --version | tr -d " ")" + if [ "${cur_ver}" == "${avail_ver}" ]; then + vc_log_msg "camera-streamer is up to date. (${cur_ver})" + fi + if [ "${cur_ver}" != "${avail_ver}" ]; then + vc_log_msg "camera-streamer new version available: ${avail_ver} (${cur_ver})." + fi + popd &> /dev/null || exit 1 + fi } - function get_ffmpeg_version { + get_ffmpeg_version() { local cur_ver avail_ver avail_ver="$(dpkg-query -W ffmpeg | awk -F':' '{print $2}')" cur_ver="$(ffmpeg -version | awk 'NR==1 {print $3}')" @@ -68,7 +72,9 @@ function versioncontrol { function main { if [[ "${CROWSNEST_LOG_LEVEL}" != "quiet" ]]; then get_ustreamer_version - get_rtsp_version + if [[ "$(is_raspberry_pi)" = "1" ]]; then + get_ayucamstream_version + fi get_ffmpeg_version fi } diff --git a/libs/watchdog.sh b/libs/watchdog.sh index b134a903..f535c75c 100755 --- a/libs/watchdog.sh +++ b/libs/watchdog.sh @@ -64,10 +64,12 @@ function crowsnest_watchdog { for i in $(get_conf_devices); do cc="$(crudini --get "${CROWSNEST_CFG}" "cam ${i}" "device" \ | awk '{print $1}')" - if [ "$(available "${cc}")" -ne 0 ] && [ "$(is_lost "${cc}")" -ne 0 ]; then + if [[ ! "${cc}" =~ "/base/soc" ]] && + [[ "$(available "${cc}")" -ne 0 ]] && [[ "$(is_lost "${cc}")" -ne 0 ]]; then log_msg "WATCHDOG: Lost Device: '${cc}'" lost_dev "${cc}" - elif [ "$(is_lost "${cc}")" -eq 0 ] && [ "$(available "${cc}")" -eq 0 ]; then + elif [[ ! "${cc}" =~ "/base/soc" ]] && + [[ "$(is_lost "${cc}")" -eq 0 ]] && [[ "$(available "${cc}")" -eq 0 ]]; then log_msg "WATCHDOG: Device '${cc}' returned." returned_dev "${cc}" fi diff --git a/resources/bcm2835-v4l2.conf b/resources/bcm2835-v4l2.conf deleted file mode 100644 index 6d6f446c..00000000 --- a/resources/bcm2835-v4l2.conf +++ /dev/null @@ -1,12 +0,0 @@ -#### crowsnest - A webcam Service for multiple Cams and Stream Services. -#### -#### Written by Stephan Wendel aka KwadFan -#### Copyright 2021 -#### https://github.com/mainsail-crew/crowsnest -#### -#### This File is distributed under GPLv3 -#### - -# See https://github.com/pikvm/ustreamer#raspberry-pi-camera-example - -options bcm2835-v4l2 max_video_width=2592 max_video_height=1944 diff --git a/resources/crowsnest-rtsp.yml b/resources/crowsnest-rtsp.yml deleted file mode 100644 index 1d9141ea..00000000 --- a/resources/crowsnest-rtsp.yml +++ /dev/null @@ -1,280 +0,0 @@ -############################################### -# General parameters - -# Sets the verbosity of the program; available values are "error", "warn", "info", "debug". -logLevel: info -# Destinations of log messages; available values are "stdout", "file" and "syslog". -logDestinations: [stdout] -# If "file" is in logDestinations, this is the file which will receive the logs. -logFile: rtsp-simple-server.log - -# Timeout of read operations. -readTimeout: 10s -# Timeout of write operations. -writeTimeout: 10s -# Number of read buffers. -# A higher number allows a wider throughput, a lower number allows to save RAM. -readBufferCount: 512 - -# HTTP URL to perform external authentication. -# Every time a user wants to authenticate, the server calls this URL -# with the POST method and a body containing: -# { -# "ip": "ip", -# "user": "user", -# "password": "password", -# "path": "path", -# "action": "read|publish" -# "query": "url's raw query" -# } -# If the response code is 20x, authentication is accepted, otherwise -# it is discarded. -externalAuthenticationURL: - -# Enable the HTTP API. -api: no -# Address of the API listener. -apiAddress: 127.0.0.1:9997 - -# Enable Prometheus-compatible metrics. -metrics: no -# Address of the metrics listener. -metricsAddress: 127.0.0.1:9998 - -# Enable pprof-compatible endpoint to monitor performances. -pprof: no -# Address of the pprof listener. -pprofAddress: 127.0.0.1:9999 - -# Command to run when a client connects to the server. -# This is terminated with SIGINT when a client disconnects from the server. -# The following environment variables are available: -# * RTSP_PORT: server port -runOnConnect: -# Restart the command if it exits suddenly. -runOnConnectRestart: no - -############################################### -# RTSP parameters - -# Disable support for the RTSP protocol. -rtspDisable: no -# List of enabled RTSP transport protocols. -# UDP is the most performant, but doesn't work when there's a NAT/firewall between -# server and clients, and doesn't support encryption. -# UDP-multicast allows to save bandwidth when clients are all in the same LAN. -# TCP is the most versatile, and does support encryption. -# The handshake is always performed with TCP. -protocols: [udp, multicast, tcp] -# Encrypt handshake and TCP streams with TLS (RTSPS). -# Available values are "no", "strict", "optional". -encryption: "no" -# Address of the TCP/RTSP listener. This is needed only when encryption is "no" or "optional". -rtspAddress: :8554 -# Address of the TCP/TLS/RTSPS listener. This is needed only when encryption is "strict" or "optional". -rtspsAddress: :8322 -# Address of the UDP/RTP listener. This is needed only when "udp" is in protocols. -rtpAddress: :8000 -# Address of the UDP/RTCP listener. This is needed only when "udp" is in protocols. -rtcpAddress: :8001 -# IP range of all UDP-multicast listeners. This is needed only when "multicast" is in protocols. -multicastIPRange: 224.1.0.0/16 -# Port of all UDP-multicast/RTP listeners. This is needed only when "multicast" is in protocols. -multicastRTPPort: 8002 -# Port of all UDP-multicast/RTCP listeners. This is needed only when "multicast" is in protocols. -multicastRTCPPort: 8003 -# Path to the server key. This is needed only when encryption is "strict" or "optional". -# This can be generated with: -# openssl genrsa -out server.key 2048 -# openssl req -new -x509 -sha256 -key server.key -out server.crt -days 3650 -serverKey: server.key -# Path to the server certificate. This is needed only when encryption is "strict" or "optional". -serverCert: server.crt -# Authentication methods. -authMethods: [basic, digest] - -############################################### -# RTMP parameters - -# Disable support for the RTMP protocol. -rtmpDisable: no -# Address of the RTMP listener. -rtmpAddress: :1935 - -############################################### -# HLS parameters - -# Disable support for the HLS protocol. -hlsDisable: no -# Address of the HLS listener. -hlsAddress: :8888 -# By default, HLS is generated only when requested by a user. -# This option allows to generate it always, avoiding the delay between request and generation. -hlsAlwaysRemux: no -# Variant of the HLS protocol to use. Available options are: -# * mpegts - uses MPEG-TS segments, for maximum compatibility. -# * fmp4 - uses fragmented MP4 segments, more efficient. -# * lowLatency - uses Low-Latency HLS. -hlsVariant: mpegts -# Number of HLS segments to keep on the server. -# Segments allow to seek through the stream. -# Their number doesn't influence latency. -hlsSegmentCount: 7 -# Minimum duration of each segment. -# A player usually puts 3 segments in a buffer before reproducing the stream. -# The final segment duration is also influenced by the interval between IDR frames, -# since the server changes the duration in order to include at least one IDR frame -# in each segment. -hlsSegmentDuration: 1s -# Minimum duration of each part. -# A player usually puts 3 parts in a buffer before reproducing the stream. -# Parts are used in Low-Latency HLS in place of segments. -# Part duration is influenced by the distance between video/audio samples -# and is adjusted in order to produce segments with a similar duration. -hlsPartDuration: 200ms -# Maximum size of each segment. -# This prevents RAM exhaustion. -hlsSegmentMaxSize: 50M -# Value of the Access-Control-Allow-Origin header provided in every HTTP response. -# This allows to play the HLS stream from an external website. -hlsAllowOrigin: "*" -# Enable TLS/HTTPS on the HLS server. -# This is required for Low-Latency HLS. -hlsEncryption: no -# Path to the server key. This is needed only when encryption is yes. -# This can be generated with: -# openssl genrsa -out server.key 2048 -# openssl req -new -x509 -sha256 -key server.key -out server.crt -days 3650 -hlsServerKey: server.key -# Path to the server certificate. -hlsServerCert: server.crt - -############################################### -# Path parameters - -# These settings are path-dependent, and the map key is the name of the path. -# It's possible to use regular expressions by using a tilde as prefix. -# For example, "~^(test1|test2)$" will match both "test1" and "test2". -# For example, "~^prefix" will match all paths that start with "prefix". -# The settings under the path "all" are applied to all paths that do not match -# another entry. -paths: - all: - # Source of the stream. This can be: - # * publisher -> the stream is published by a RTSP or RTMP client - # * rtsp://existing-url -> the stream is pulled from another RTSP server / camera - # * rtsps://existing-url -> the stream is pulled from another RTSP server / camera with RTSPS - # * rtmp://existing-url -> the stream is pulled from another RTMP server - # * http://existing-url/stream.m3u8 -> the stream is pulled from another HLS server - # * https://existing-url/stream.m3u8 -> the stream is pulled from another HLS server with HTTPS - # * redirect -> the stream is provided by another path or server - source: publisher - - # If the source is an RTSP or RTSPS URL, this is the protocol that will be used to - # pull the stream. available values are "automatic", "udp", "multicast", "tcp". - sourceProtocol: automatic - - # Tf the source is an RTSP or RTSPS URL, this allows to support sources that - # don't provide server ports or use random server ports. This is a security issue - # and must be used only when interacting with sources that require it. - sourceAnyPortEnable: no - - # If the source is a RTSPS or HTTPS URL, and the source certificate is self-signed - # or invalid, you can provide the fingerprint of the certificate in order to - # validate it anyway. It can be obtained by running: - # openssl s_client -connect source_ip:source_port /dev/null | sed -n '/BEGIN/,/END/p' > server.crt - # openssl x509 -in server.crt -noout -fingerprint -sha256 | cut -d "=" -f2 | tr -d ':' - sourceFingerprint: - - # If the source is an RTSP or RTMP URL, it will be pulled only when at least - # one reader is connected, saving bandwidth. - sourceOnDemand: no - # If sourceOnDemand is "yes", readers will be put on hold until the source is - # ready or until this amount of time has passed. - sourceOnDemandStartTimeout: 10s - # If sourceOnDemand is "yes", the source will be closed when there are no - # readers connected and this amount of time has passed. - sourceOnDemandCloseAfter: 10s - - # If the source is "redirect", this is the RTSP URL which clients will be - # redirected to. - sourceRedirect: - - # If the source is "publisher" and a client is publishing, do not allow another - # client to disconnect the former and publish in its place. - disablePublisherOverride: no - - # If the source is "publisher" and no one is publishing, redirect readers to this - # path. It can be can be a relative path (i.e. /otherstream) or an absolute RTSP URL. - fallback: - - # Username required to publish. - # SHA256-hashed values can be inserted with the "sha256:" prefix. - publishUser: - # Password required to publish. - # SHA256-hashed values can be inserted with the "sha256:" prefix. - publishPass: - # IPs or networks (x.x.x.x/24) allowed to publish. - publishIPs: [] - - # Username required to read. - # SHA256-hashed values can be inserted with the "sha256:" prefix. - readUser: - # password required to read. - # SHA256-hashed values can be inserted with the "sha256:" prefix. - readPass: - # IPs or networks (x.x.x.x/24) allowed to read. - readIPs: [] - - # Command to run when this path is initialized. - # This can be used to publish a stream and keep it always opened. - # This is terminated with SIGINT when the program closes. - # The following environment variables are available: - # * RTSP_PATH: path name - # * RTSP_PORT: server port - # * G1, G2, ...: regular expression groups, if path name is - # a regular expression. - runOnInit: - # Restart the command if it exits suddenly. - runOnInitRestart: no - - # Command to run when this path is requested. - # This can be used to publish a stream on demand. - # This is terminated with SIGINT when the path is not requested anymore. - # The following environment variables are available: - # * RTSP_PATH: path name - # * RTSP_PORT: server port - # * G1, G2, ...: regular expression groups, if path name is - # a regular expression. - runOnDemand: - # Restart the command if it exits suddenly. - runOnDemandRestart: no - # Readers will be put on hold until the runOnDemand command starts publishing - # or until this amount of time has passed. - runOnDemandStartTimeout: 10s - # The command will be closed when there are no - # readers connected and this amount of time has passed. - runOnDemandCloseAfter: 10s - - # Command to run when the stream is ready to be read, whether it is - # published by a client or pulled from a server / camera. - # This is terminated with SIGINT when the stream is not ready anymore. - # The following environment variables are available: - # * RTSP_PATH: path name - # * RTSP_PORT: server port - # * G1, G2, ...: regular expression groups, if path name is - # a regular expression. - runOnReady: - # Restart the command if it exits suddenly. - runOnReadyRestart: no - - # Command to run when a clients starts reading. - # This is terminated with SIGINT when a client stops reading. - # The following environment variables are available: - # * RTSP_PATH: path name - # * RTSP_PORT: server port - # * G1, G2, ...: regular expression groups, if path name is - # a regular expression. - runOnRead: - # Restart the command if it exits suddenly. - runOnReadRestart: no diff --git a/resources/crowsnest.conf b/resources/crowsnest.conf index dfec22db..512b328e 100644 --- a/resources/crowsnest.conf +++ b/resources/crowsnest.conf @@ -18,6 +18,9 @@ #### Port 8083 equals /webcam4/?action=[stream/snapshot] ##### #### ##### ##################################################################### +#### RTSP Stream URL: ( if enabled and supported ) ##### +#### rtsp://:/stream.h264 ##### +##################################################################### [crowsnest] @@ -26,8 +29,10 @@ log_level: verbose # Valid Options are quiet/verbose/debug delete_log: false # Deletes log on every restart, if set to true [cam 1] -mode: mjpg # mjpg/rtsp -port: 8080 # Port +mode: mjpg # mjpg/multi - Multi uses webrtc, mjpg and snapshots at the same time +enable_rtsp: false # If multi is used, this enables also usage of an rtsp server +rtsp_port: 8554 # Set different ports for each device! +port: 8080 # HTTP/MJPG Stream/Snapshot Port device: /dev/video0 # See Log for available ... resolution: 640x480 # widthxheight format max_fps: 15 # If Hardware Supports this it will be forced, otherwise ignored/coerced. diff --git a/tools/configure.sh b/tools/configure.sh index 0216c491..5f55da8b 100755 --- a/tools/configure.sh +++ b/tools/configure.sh @@ -24,6 +24,8 @@ CN_CONFIG_ENVPATH="${CN_CONFIG_ROOTPATH}/systemd" CN_MOONRAKER_CONFIG_PATH="${CN_CONFIG_CONFIGPATH}/moonraker.conf" CN_USTREAMER_REPO="https://github.com/pikvm/ustreamer.git" CN_USTREAMER_BRANCH="master" +CN_CAMERA_STREAMER_REPO="https://github.com/ayufan-research/camera-streamer.git" +CN_CAMERA_STREAMER_BRANCH="master" ### Messages header_msg() { @@ -75,16 +77,6 @@ env_path_msg() { echo -e "\tDefault: \e[32m${CN_CONFIG_ENVPATH}\e[0m\n" } -apply_raspicamfix_msg() { - header_msg - echo -e "Should the Raspicam Fix be applied?\n" - echo -e "\t\e[34mNOTE:\e[0m\n\tThis should be only applied if you are" - echo -e "\tusing a Raspberry Pi! This will force Raspicams" - echo -e "\tusing the device path '/dev/video0'\n" - echo -e "Available are:\n Yes [y or Y]\n No [n or N]\n Hit ENTER for auto\n" - echo -e "In 'auto' mode Installer try to detect device and applies fix if SBC is a Pi!\n" -} - add_moonraker_entry_msg() { header_msg echo -e "Should the update_manager entry added to your moonraker.conf?\n" @@ -152,6 +144,8 @@ create_config_header() { echo -e "BASE_USER=\"${CN_CONFIG_USER}\""; echo -e "CROWSNEST_USTREAMER_REPO_SHIP=\"${CN_USTREAMER_REPO}\""; echo -e "CROWSNEST_USTREAMER_REPO_BRANCH=\"${CN_USTREAMER_BRANCH}\"" + echo -e "CROWSNEST_CAMERA_STREAMER_REPO_SHIP=\"${CN_CAMERA_STREAMER_REPO}\""; + echo -e "CROWSNEST_CAMERA_STREAMER_REPO_BRANCH=\"${CN_CAMERA_STREAMER_BRANCH}\"" } >> "${CN_CONFIG_CONFIGFILE}" } @@ -204,29 +198,6 @@ specify_env_path() { fi } -apply_raspicamfix() { - local reply - apply_raspicamfix_msg - read -erp "Enable Raspicamfix?: " reply - if [[ -z "${reply}" ]]; then - echo -e "CROWSNEST_RASPICAMFIX=\"auto\"" >> \ - "${CN_CONFIG_CONFIGFILE}" - return 0 - fi - while true; do - case "${reply}" in - [yY]*) - echo -e "CROWSNEST_RASPICAMFIX=\"1\"" >> "${CN_CONFIG_CONFIGFILE}" - break - ;; - [nN]*) - echo -e "CROWSNEST_RASPICAMFIX=\"0\"" >> "${CN_CONFIG_CONFIGFILE}" - break - ;; - esac - done -} - add_moonraker_entry() { local reply add_moonraker_entry_msg @@ -265,11 +236,9 @@ main() { specify_log_path # Step 6: Specify env path. specify_env_path - # Step 7: Raspicam fix - apply_raspicamfix - # Step 8: Moonraker entry + # Step 7: Moonraker entry add_moonraker_entry - # Step 9: Display finished message + # Step 8: Display finished message goodbye_msg } diff --git a/tools/install.sh b/tools/install.sh index 14972b46..50d60e45 100755 --- a/tools/install.sh +++ b/tools/install.sh @@ -22,7 +22,7 @@ set -Ee # Global Vars TITLE="\e[31mcrowsnest\e[0m - A webcam daemon for multiple Cams and stream services." -[[ -n "${BASE_USER}" ]] || BASE_USER="$(logname 2> /dev/null || echo "${PWD}" | cut -d'/' -f3)" +[[ -n "${BASE_USER}" ]] || BASE_USER="" [[ -n "${CROWSNEST_UNATTENDED}" ]] || CROWSNEST_UNATTENDED="0" [[ -n "${CROWSNEST_DEFAULT_CONF}" ]] || CROWSNEST_DEFAULT_CONF="resources/crowsnest.conf" @@ -37,11 +37,19 @@ if [[ "${DEBIAN_FRONTEND}" != "noninteractive" ]]; then fi ### Check non-root -if [[ ${UID} != '0' ]]; then - echo -e "\n\tYOU NEED TO RUN INSTALLER AS ROOT!" +if [[ -z "${BASE_USER}" ]] && [[ -z "${SUDO_USER}" ]]; then + echo -e "\n\tYou need to run this script with sudo priviledges!" echo -e "\tPlease try '\e[32msudo make install\e[0m'\n\nExiting..." exit 1 fi +## Determine BASE_USER +if [[ -z "${BASE_USER}" ]] && [[ "${SUDO_USER}" == "root" ]]; then + printf "\n\tPlease do NOT run this script as root!\n" + printf "\tLogin in as regular user and run with '\e[32msudo make install\e[0m'\n\n" + exit 1 +else + BASE_USER="${SUDO_USER}" +fi ### Global functions @@ -123,7 +131,8 @@ import_config() { CROWSNEST_ENV_PATH="/home/${BASE_USER}/printer_data/systemd" CROWSNEST_USTREAMER_REPO_SHIP="https://github.com/pikvm/ustreamer.git" CROWSNEST_USTREAMER_REPO_BRANCH="master" - + CROWSNEST_CAMERA_STREAMER_REPO_SHIP="https://github.com/ayufan/camera-streamer.git" + CROWSNEST_CAMERA_STREAMER_REPO_BRANCH="master" fi } @@ -138,7 +147,7 @@ create_filestructure() { ### Detect legacy webcamd. detect_existing_webcamd() { local remove - if [ -x "/usr/local/bin/webcamd" ] && [ -d "${HOME}/mjpg-streamer" ]; then + if [ -x "/usr/local/bin/webcamd" ] && [ -d "/home/${BASE_USER}/mjpg-streamer" ]; then detect_msg read -erp "Do you want to remove existing 'webcamd'? (y/N) " -i "N" remove case "${remove}" in @@ -207,8 +216,9 @@ install_packages() { PKGLIST="git crudini bsdutils findutils v4l-utils curl" ### Ustreamer Dependencies PKGLIST="${PKGLIST} build-essential libevent-dev libjpeg-dev libbsd-dev" - ### simple-rtsp-server Dependencies - PKGLIST="${PKGLIST} libxcomposite1 libxtst6 ffmpeg" + ### Camera-Streamer Dependencies + PKGLIST="${PKGLIST} cmake libavformat-dev libavutil-dev libavcodec-dev libcamera-dev" + PKGLIST="${PKGLIST} liblivemedia-dev pkg-config xxd build-essential cmake libssl-dev" echo -e "Running apt update first ..." ### Run apt update @@ -341,24 +351,38 @@ clone_ustreamer() { fi sudo -u "${BASE_USER}" \ git clone "${CROWSNEST_USTREAMER_REPO_SHIP}" \ - -b "${CROWSNEST_USTREAMER_REPO_BRANCH}" bin/ustreamer - ## Buster workaround - ## ustreamer support omx only till version 4.13 - ## so stick to that version + -b "${CROWSNEST_USTREAMER_REPO_BRANCH}" \ + --depth=1 --single-branch bin/ustreamer if [[ "$(get_os_version buster)" != "0" ]]; then - pushd bin/ustreamer &> /dev/null || exit 1 - git reset --hard 61ab2a8 - popd &> /dev/null || exit 1 + printf "NOTE: Crowsnest has dropped support for OMX in ustreamer ... \n" + fi +} + +clone_cstreamer() { + ## remove bin/ustreamer if exist + if [[ -d bin/camera-streamer ]]; then + rm -rf bin/camera-streamer fi + sudo -u "${BASE_USER}" \ + git clone "${CROWSNEST_CAMERA_STREAMER_REPO_SHIP}" --recursive \ + -b "${CROWSNEST_CAMERA_STREAMER_REPO_BRANCH}" \ + --depth=1 --single-branch bin/camera-streamer } build_apps() { echo -e "Build dependend Stream Apps ..." echo -e "Cloning ustreamer repository ..." clone_ustreamer - pushd bin > /dev/null - sudo -u "${BASE_USER}" make all - popd > /dev/null + ## Detect Image build for Raspberrys + if [[ "$(is_raspberry_pi)" = "1" ]] || + [[ -f "/etc/rpi-issue" ]]; then + echo -e "Cloning camera-streamer repository ..." + clone_cstreamer + fi + if [[ "$(is_raspberry_pi)" = "0" ]]; then + echo -e "Install of camera-streamer skipped, only supported on Raspberry Pi's! ... " + fi + sudo -u "${BASE_USER}" bin/build.sh --build } is_raspberry_pi() { @@ -370,33 +394,11 @@ is_raspberry_pi() { fi } -install_raspicam_fix() { - if [[ "${CROWSNEST_RASPICAMFIX}" == "auto" ]]; then - if [[ "$(is_raspberry_pi)" = "1" ]]; then - echo -e "Device is a Raspberry Pi" - CROWSNEST_RASPICAMFIX="1" - fi - if [[ "$(is_raspberry_pi)" = "0" ]]; then - echo -e "Device is \e[31mNOT\e[0m a Raspberry Pi ... [${CN_SK}]" - CROWSNEST_RASPICAMFIX="0" - fi - fi - # This is also used for unattended Install - # Needs special handling if targeted Image is not for Raspberry Pi's! - if [[ "${CROWSNEST_RASPICAMFIX}" == "1" ]] && - [[ -f /boot/config.txt ]]; then - echo -en "Applying Raspicam Fix ... \r" - bash -c 'echo "bcm2835-v4l2" >> /etc/modules' - cp resources/bcm2835-v4l2.conf /etc/modprobe.d/ - echo -e "Applying Raspicam Fix ... [${CN_OK}]" - fi -} - -enable_legacy_cam() { +set_gpu_mem() { local cfg local -a model cfg="/boot/config.txt" - model=(pi3 pi4) + model=(pi3 pi4 cm4) if [[ -f "${cfg}" ]] && [[ "$(is_raspberry_pi)" = "1" ]]; then # Helper func @@ -404,10 +406,11 @@ enable_legacy_cam() { crudini --get "${cfg}" "${1}" gpu_mem 2> /dev/null } - echo -en "Enable legacy camera stack ... \r" - sed -i "s/camera_auto_detect=1/#camera_auto_detect=1/" "${cfg}" + echo -en "Set gpu_mem ... \r" if [[ "$(grep -c "start_x" "${cfg}")" = "0" ]]; then crudini --set --inplace "${cfg}" all start_x 1 &> /dev/null + sed -i 's/^#start_x/start_x/g' "${cfg}" + sed -i 's/^start_x=0/start_x=1/g' "${cfg}" fi for d in "${model[@]}"; do @@ -418,7 +421,7 @@ enable_legacy_cam() { if [[ "$(get_val pi0)" -lt "129" ]]; then sudo crudini --set --inplace "${cfg}" pi0 gpu_mem 160 &> /dev/null fi - echo -e "Enable legacy camera stack ... [${CN_OK}]" + echo -e "Set gpu_mem ... [${CN_OK}]" fi ## crudini workaround ## used version of crudini puts spaces between values and parameters @@ -536,7 +539,7 @@ main() { ## Step 7: Enable Legacy Camera Stack if [[ "$(get_os_version bullseye)" != "0" ]] && [[ -f "/boot/config.txt" ]]; then - enable_legacy_cam + set_gpu_mem fi ### buntu workaround @@ -562,15 +565,12 @@ main() { ## Step 10: Install logrotate file install_logrotate - ## Step 11: Install raspicamfix - install_raspicam_fix - - ## Step 12: Add moonraker update_manager entry + ## Step 11: Add moonraker update_manager entry if [[ "${CROWSNEST_ADD_CROWSNEST_MOONRAKER}" = "1" ]]; then add_update_entry fi - ## Step 13: Ask for reboot + ## Step 12: Ask for reboot ## Skip if UNATTENDED goodbye_msg if [[ "${CROWSNEST_UNATTENDED}" = "0" ]]; then diff --git a/tools/uninstall.sh b/tools/uninstall.sh index 970e8123..973376fa 100755 --- a/tools/uninstall.sh +++ b/tools/uninstall.sh @@ -43,7 +43,7 @@ welcome_msg() { echo -e "\t\e[34mAhoi!\e[0m" echo -e "\tTo sad that you want to uninstall crowsnest :(" echo -e "\tThis will take a while ... " - echo -e "\tPlease reboot after installation has finished.\n" + echo -e "\tPlease reboot after uninstallation has finished.\n" sleep 1 } @@ -96,7 +96,6 @@ ask_uninstall() { y|Y|yes|Yes|YES) source_env_file uninstall_crowsnest - remove_raspicam_fix remove_logrotate ask_remove_config goodbye_msg @@ -174,21 +173,6 @@ ask_remove_config() { return 0 } -remove_raspicam_fix() { - if [[ -f /etc/modprobe.d/bcm2835-v4l2.conf ]] && - [[ -f /proc/device-tree/model ]] && - grep -q "Raspberry" /proc/device-tree/model ; then - echo -en "Removing Raspicam Fix ...\r" - sudo sed -i '/bcm2835/d' /etc/modules - sudo rm -f /etc/modprobe.d/bcm2835-v4l2.conf - echo -e "Removing Raspicam Fix ... [${CN_OK}]" - else - echo -e "Removing Raspicam Fix ... [${CN_SK}]" - echo -e "\tThis is not a Raspberry Pi" - echo -e "\tor Raspicamfix not installed ... \n" - fi -} - function remove_logrotate { echo -en "Removing Logrotate Rule ...\r" sudo rm -f /etc/logrotate.d/crowsnest