From 95c1dca13f794eb2de521b84186b3fd6e7efa3f3 Mon Sep 17 00:00:00 2001
From: Stephan Wendel <me@stephanwe.de>
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 <me@stephanwe.de>

Signed-off-by: Stephan Wendel <me@stephanwe.de>
---
 .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 3669789..e03ad65 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 b86f977..25baf21 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 772d16f..0000000
--- 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 <me@stephanwe.de>
-#### 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 0000000..1eeb9ef
--- /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 <me@stephanwe.de>
+#### 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 9c6ae02..0000000
--- a/bin/rtsp-simple-server/version
+++ /dev/null
@@ -1 +0,0 @@
-v0.20.2
diff --git a/crowsnest b/crowsnest
index 95d6bc3..1454fa0 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 3074515..4ebf455 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 0000000..885557d
--- /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 <me@stephanwe.de>
+#### 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 5019294..60acb80 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 <nameornumber>] if all needed configuration sections are present
 # call check_section <nameornumber> 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 cc659a0..c653110 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 02615c6..2d3831e 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 <nameornumber> 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 <nameornumber> 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 <nameornumber> ex.: detect_mjpeg foobar
-# returns 1 = true / 0 = false ( numbers are strings! not int!)
+## Determine if cam has MJPEG Hardware encoder
+## call detect_mjpeg <nameornumber> 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 e499580..ab3ba2c 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 7cbdbf2..43a38ce 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 "<prefix>"'
@@ -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 ebfb99e..90eedb0 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 3e9ec13..0000000
--- 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 <me@stephanwe.de>
-#### 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 c573917..aa0140e 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 b5e9cd8..0cea2bc 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 <device>
-    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 e48dad4..5464faf 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 b134a90..f535c75 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 6d6f446..0000000
--- 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 <me@stephanwe.de>
-#### 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 1d9141e..0000000
--- 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 2>/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 dfec22d..512b328 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://<ip>:<rtsp_port>/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 0216c49..5f55da8 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 14972b4..50d60e4 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 970e812..973376f 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