Merge branch 'migrate-s6-scripts' of https://github.com/felipecrs/frigate into auto-candidate

This commit is contained in:
Felipe Santos 2023-01-18 10:31:58 -03:00
commit 33c3a7cebe
48 changed files with 156 additions and 80 deletions

View File

@ -192,22 +192,10 @@ RUN ldconfig
EXPOSE 5000 EXPOSE 5000
EXPOSE 1935 EXPOSE 1935
EXPOSE 8554 EXPOSE 8554
EXPOSE 8555 EXPOSE 8555/tcp 8555/udp
# Fails if cont-init.d fails
ENV S6_BEHAVIOUR_IF_STAGE2_FAILS=2
# Wait indefinitely for cont-init.d to finish before starting services
ENV S6_CMD_WAIT_FOR_SERVICES=1
ENV S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0
# Give services (including Frigate) 30 seconds to stop before killing them
# But this is not working currently because of:
# https://github.com/just-containers/s6-overlay/issues/503
ENV S6_SERVICES_GRACETIME=30000
# Configure logging to prepend timestamps, log to stdout, keep 0 archives and rotate on 10MB # Configure logging to prepend timestamps, log to stdout, keep 0 archives and rotate on 10MB
ENV S6_LOGGING_SCRIPT="T 1 n0 s10000000 T" ENV S6_LOGGING_SCRIPT="T 1 n0 s10000000 T"
# TODO: remove after a new version of s6-overlay is released. See:
# https://github.com/just-containers/s6-overlay/issues/460#issuecomment-1327127006
ENV S6_SERVICES_READYTIME=50
ENTRYPOINT ["/init"] ENTRYPOINT ["/init"]
CMD [] CMD []
@ -217,7 +205,7 @@ FROM deps AS devcontainer
# Do not start the actual Frigate service on devcontainer as it will be started by VSCode # Do not start the actual Frigate service on devcontainer as it will be started by VSCode
# But start a fake service for simulating the logs # But start a fake service for simulating the logs
COPY docker/fake_frigate_run /etc/services.d/frigate/run COPY docker/fake_frigate_run /etc/s6-overlay/s6-rc.d/frigate/run
# Install Node 16 # Install Node 16
RUN apt-get update \ RUN apt-get update \

View File

@ -0,0 +1 @@
frigate

View File

@ -0,0 +1 @@
frigate-pipeline

View File

@ -0,0 +1 @@
longrun

View File

@ -0,0 +1,30 @@
#!/command/with-contenv bash
# shellcheck shell=bash
# Take down the S6 supervision tree when the service exits
set -o errexit -o nounset -o pipefail
declare exit_code_container
exit_code_container=$(cat /run/s6-linux-init-container-results/exitcode)
readonly exit_code_container
readonly exit_code_service="${1}"
readonly exit_code_signal="${2}"
readonly service="Frigate"
echo "Service ${service} exited with code ${exit_code_service} (by signal ${exit_code_signal})" >&2
if [[ "${exit_code_service}" -eq 256 ]]; then
if [[ "${exit_code_container}" -eq 0 ]]; then
echo $((128 + exit_code_signal)) > /run/s6-linux-init-container-results/exitcode
fi
elif [[ "${exit_code_service}" -ne 0 ]]; then
if [[ "${exit_code_container}" -eq 0 ]]; then
echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode
fi
else
# Exit code 0 is expected when Frigate is restarted by the user. In this case,
# we create a signal for the go2rtc finish script to tolerate the restart.
touch /dev/shm/restarting-frigate
fi
exec /run/s6/basedir/bin/halt

View File

@ -0,0 +1 @@
frigate-log

View File

@ -4,6 +4,9 @@
set -o errexit -o nounset -o pipefail set -o errexit -o nounset -o pipefail
# Tell S6-Overlay not to restart this service
s6-svc -O .
cd /opt/frigate cd /opt/frigate
# Replace the bash process with the Frigate process, redirecting stderr to stdout # Replace the bash process with the Frigate process, redirecting stderr to stdout

View File

@ -0,0 +1 @@
longrun

View File

@ -0,0 +1 @@
go2rtc

View File

@ -0,0 +1 @@
go2rtc-pipeline

View File

@ -0,0 +1 @@
longrun

View File

@ -0,0 +1,32 @@
#!/command/with-contenv bash
# shellcheck shell=bash
# Take down the S6 supervision tree when the service exits
set -o errexit -o nounset -o pipefail
declare exit_code_container
exit_code_container=$(cat /run/s6-linux-init-container-results/exitcode)
readonly exit_code_container
readonly exit_code_service="${1}"
readonly exit_code_signal="${2}"
readonly service="go2rtc"
echo "Service ${service} exited with code ${exit_code_service} (by signal ${exit_code_signal})" >&2
if [[ "${exit_code_service}" -eq 256 ]]; then
if [[ "${exit_code_container}" -eq 0 ]]; then
echo $((128 + exit_code_signal)) > /run/s6-linux-init-container-results/exitcode
fi
elif [[ "${exit_code_service}" -ne 0 ]]; then
if [[ "${exit_code_container}" -eq 0 ]]; then
echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode
fi
else
# go2rtc is not supposed to exit, so even when it exits with 0 we make the
# container with 1. We only tolerate it when Frigate is restarting.
if [[ "${exit_code_container}" -eq 0 && ! -f /dev/shm/restarting-frigate ]]; then
echo "1" > /run/s6-linux-init-container-results/exitcode
fi
fi
exec /run/s6/basedir/bin/halt

View File

@ -0,0 +1 @@
go2rtc-log

View File

@ -1,10 +1,13 @@
#!/command/with-contenv bash #!/command/with-contenv bash
# shellcheck shell=bash # shellcheck shell=bash
# Prepare the go2rtc config # Start the go2rtc service
set -o errexit -o nounset -o pipefail set -o errexit -o nounset -o pipefail
function get_ip_and_port() { # Tell S6-Overlay not to restart this service
s6-svc -O .
function get_ip_and_port_from_supervisor() {
local ip_address local ip_address
# Example: 192.168.1.10/24 # Example: 192.168.1.10/24
local ip_regex='^([0-9]{1,3}\.{3}[0-9]{1,3})/[0-9]{1,2}$' local ip_regex='^([0-9]{1,3}\.{3}[0-9]{1,3})/[0-9]{1,2}$'
@ -41,9 +44,17 @@ function get_ip_and_port() {
export FRIGATE_GO2RTC_WEBRTC_CANDIDATE_INTERNAL="${ip_address}:${webrtc_port}" export FRIGATE_GO2RTC_WEBRTC_CANDIDATE_INTERNAL="${ip_address}:${webrtc_port}"
} }
echo "[INFO] Preparing go2rtc config..." >&2
if [[ -n "${SUPERVISOR_TOKEN:-}" ]]; then if [[ -n "${SUPERVISOR_TOKEN:-}" ]]; then
# Running as a Home Assistant add-on, infer the IP address and port # Running as a Home Assistant add-on, infer the IP address and port
get_ip_and_port get_ip_and_port_from_supervisor
fi fi
python3 /usr/local/go2rtc/create_config.py raw_config=$(python3 /usr/local/go2rtc/create_config.py)
echo "[INFO] Starting go2rtc..." >&2
# Replace the bash process with the go2rtc process, redirecting stderr to stdout
exec 2>&1
exec go2rtc -config="${raw_config}"

View File

@ -0,0 +1 @@
longrun

View File

@ -0,0 +1 @@
oneshot

View File

@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/log-prepare/run

View File

@ -0,0 +1 @@
nginx

View File

@ -0,0 +1 @@
nginx-pipeline

View File

@ -0,0 +1 @@
longrun

View File

@ -0,0 +1,28 @@
#!/command/with-contenv bash
# shellcheck shell=bash
# Take down the S6 supervision tree when the service fails
set -o errexit -o nounset -o pipefail
declare exit_code_container
exit_code_container=$(cat /run/s6-linux-init-container-results/exitcode)
readonly exit_code_container
readonly exit_code_service="${1}"
readonly exit_code_signal="${2}"
readonly service="NGINX"
echo "Service ${service} exited with code ${exit_code_service} (by signal ${exit_code_signal})" >&2
if [[ "${exit_code_service}" -eq 256 ]]; then
if [[ "${exit_code_container}" -eq 0 ]]; then
echo $((128 + exit_code_signal)) > /run/s6-linux-init-container-results/exitcode
fi
if [[ "${exit_code_signal}" -eq 15 ]]; then
exec /run/s6/basedir/bin/halt
fi
elif [[ "${exit_code_service}" -ne 0 ]]; then
if [[ "${exit_code_container}" -eq 0 ]]; then
echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode
fi
exec /run/s6/basedir/bin/halt
fi

View File

@ -0,0 +1 @@
nginx-log

View File

@ -0,0 +1 @@
longrun

View File

@ -1,16 +0,0 @@
#!/command/with-contenv bash
# shellcheck shell=bash
# Take down the S6 supervision tree when the service exits
set -o errexit -o nounset -o pipefail
# Prepare exit code
if [[ "${1}" -eq 256 ]]; then
exit_code="$((128 + ${2}))"
else
exit_code="${1}"
fi
# Make the container exit with the same exit code as the service
echo "${exit_code}" > /run/s6-linux-init-container-results/exitcode
exec /run/s6/basedir/bin/halt

View File

@ -1,8 +0,0 @@
#!/command/with-contenv bash
# shellcheck shell=bash
# Take down the S6 supervision tree when the service fails, or restart it
# otherwise
if [[ "${1}" -ne 0 && "${1}" -ne 256 ]]; then
exec /run/s6/basedir/bin/halt
fi

View File

@ -1,7 +0,0 @@
#!/command/with-contenv bash
# shellcheck shell=bash
# Start the go2rtc service
# Replace the bash process with the go2rtc process, redirecting stderr to stdout
exec 2>&1
exec go2rtc -config=/dev/shm/go2rtc.yaml

View File

@ -1,8 +0,0 @@
#!/command/with-contenv bash
# shellcheck shell=bash
# Take down the S6 supervision tree when the service fails, or restart it
# otherwise
if [[ "${1}" -ne 0 && "${1}" -ne 256 ]]; then
exec /run/s6/basedir/bin/halt
fi

View File

@ -5,6 +5,7 @@ import os
import yaml import yaml
BTBN_PATH = "/usr/lib/btbn-ffmpeg"
config_file = os.environ.get("CONFIG_FILE", "/config/config.yml") config_file = os.environ.get("CONFIG_FILE", "/config/config.yml")
# Check if we can use .yaml instead of .yml # Check if we can use .yaml instead of .yml
@ -20,21 +21,34 @@ if config_file.endswith((".yaml", ".yml")):
elif config_file.endswith(".json"): elif config_file.endswith(".json"):
config = json.loads(raw_config) config = json.loads(raw_config)
go2rtc_config: dict[str, any] = config["go2rtc"] go2rtc_config: dict[str, any] = config.get("go2rtc", {})
if not go2rtc_config.get("log", {}).get("format"): # we want to ensure that logs are easy to read
if go2rtc_config.get("log") is None:
go2rtc_config["log"] = {"format": "text"} go2rtc_config["log"] = {"format": "text"}
elif go2rtc_config["log"].get("format") is None:
go2rtc_config["log"]["format"] = "text"
if not go2rtc_config.get("webrtc", {}).get("candidates", []): if not go2rtc_config.get("webrtc", {}).get("candidates", []):
default_candidates = [] default_candidates = []
# Use FRIGATE_GO2RTC_WEBRTC_CANDIDATE_INTERNAL as candidate if set # use internal candidate if it was discovered when running through the add-on
internal_candidate = os.environ.get("FRIGATE_GO2RTC_WEBRTC_CANDIDATE_INTERNAL", None) internal_candidate = os.environ.get("FRIGATE_GO2RTC_WEBRTC_CANDIDATE_INTERNAL", None)
if internal_candidate is not None: if internal_candidate is not None:
default_candidates.append(internal_candidate) default_candidates.append(internal_candidate)
# should set default stun server so webrtc can work
default_candidates.append("stun:8555") default_candidates.append("stun:8555")
go2rtc_config["webrtc"] = {"candidates": default_candidates} go2rtc_config["webrtc"] = {"candidates": default_candidates}
# Write YAML config to /dev/shm/go2rtc.yaml # need to replace ffmpeg command when using ffmpeg4
with open("/dev/shm/go2rtc.yaml", "w") as f: if not os.path.exists(BTBN_PATH):
yaml.dump(go2rtc_config, f) if go2rtc_config.get("ffmpeg") is None:
go2rtc_config["ffmpeg"] = {
"rtsp": "-fflags nobuffer -flags low_delay -stimeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_transport tcp -i {input}"
}
elif go2rtc_config["ffmpeg"].get("rtsp") is None:
go2rtc_config["ffmpeg"][
"rtsp"
] = "-fflags nobuffer -flags low_delay -stimeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_transport tcp -i {input}"
print(json.dumps(go2rtc_config))

View File

@ -7,12 +7,6 @@ It is recommended to update your configuration to enable hardware accelerated de
### Raspberry Pi 3/4 ### Raspberry Pi 3/4
:::caution
There is currently a bug in ffmpeg that causes hwaccel to not work for the RPi kernel 5.15.61 and above. For more information see https://github.com/blakeblackshear/frigate/issues/3780
:::
Ensure you increase the allocated RAM for your GPU to at least 128 (raspi-config > Performance Options > GPU Memory). Ensure you increase the allocated RAM for your GPU to at least 128 (raspi-config > Performance Options > GPU Memory).
**NOTICE**: If you are using the addon, you may need to turn off `Protection mode` for hardware acceleration. **NOTICE**: If you are using the addon, you may need to turn off `Protection mode` for hardware acceleration.

View File

@ -769,7 +769,10 @@ def config_save():
logging.error(f"Error restarting Frigate: {e}") logging.error(f"Error restarting Frigate: {e}")
return "Config successfully saved, unable to restart Frigate", 200 return "Config successfully saved, unable to restart Frigate", 200
return "Config successfully saved, restarting...", 200 return (
"Config successfully saved, restarting (this can take up to one minute)...",
200,
)
else: else:
return "Config successfully saved.", 200 return "Config successfully saved.", 200

View File

@ -628,13 +628,8 @@ def clipped(obj, frame_shape):
def restart_frigate(): def restart_frigate():
proc = psutil.Process(1) # S6 overlay is configured to exit once the Frigate process exits
# if this is running via s6, sigterm pid 1 os.kill(os.getpid(), signal.SIGTERM)
if proc.name() == "s6-svscan":
proc.terminate()
# otherwise, just try and exit frigate
else:
os.kill(os.getpid(), signal.SIGTERM)
class EventsPerSecond: class EventsPerSecond:

View File

@ -78,7 +78,7 @@ export default function AppBar() {
{showDialogWait ? ( {showDialogWait ? (
<Prompt <Prompt
title="Restart in progress" title="Restart in progress"
text="Please wait a few seconds for the restart to complete before reloading the page." text="This can take up to one minute, please wait before reloading the page."
/> />
) : null} ) : null}
</Fragment> </Fragment>

View File

@ -112,7 +112,7 @@ export default function Camera({ camera }) {
player = ( player = (
<Fragment> <Fragment>
<div className="max-w-5xl"> <div className="max-w-5xl">
<MsePlayer camera={camera} /> <MsePlayer camera={cameraConfig.live.stream_name} />
</div> </div>
</Fragment> </Fragment>
); );
@ -129,7 +129,7 @@ export default function Camera({ camera }) {
player = ( player = (
<Fragment> <Fragment>
<div className="max-w-5xl"> <div className="max-w-5xl">
<WebRtcPlayer camera={camera} /> <WebRtcPlayer camera={cameraConfig.live.stream_name} />
</div> </div>
</Fragment> </Fragment>
); );