Compare commits
20 Commits
master
...
legacy-ipc
Author | SHA1 | Date | |
---|---|---|---|
![]() |
077495eba6 | ||
![]() |
b83f3e0eb7 | ||
![]() |
3a8961837c | ||
![]() |
40bcc7f5f4 | ||
![]() |
c17410c073 | ||
![]() |
cc67e1e2db | ||
![]() |
f95472b413 | ||
![]() |
9ee4fc4fde | ||
![]() |
4af565b27d | ||
![]() |
75b2517c50 | ||
![]() |
b9de2f2ce5 | ||
![]() |
e505c57464 | ||
![]() |
2ebc4c68ce | ||
![]() |
8d4045f6c3 | ||
![]() |
72a45b8521 | ||
![]() |
014f310353 | ||
![]() |
c712beb699 | ||
![]() |
c857f58b40 | ||
![]() |
ae2787b3ae | ||
![]() |
e26851a600 |
14
systemd/ipcam_rtsp2hls_rkmpp@.service
Normal file
14
systemd/ipcam_rtsp2hls_rkmpp@.service
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=convert rtsp to hls for viewing live camera feeds in browser
|
||||||
|
After=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Restart=always
|
||||||
|
RestartSec=3
|
||||||
|
User=root
|
||||||
|
Group=root
|
||||||
|
EnvironmentFile=/etc/ipcam_rtsp2hls.conf.d/%i.conf
|
||||||
|
ExecStart=/home/user/homekit/tools/ipcam_rtsp2hls_rkmpp.sh --name %i --user $USER --password $PASSWORD --ip $IP --port $PORT --force-tcp $ARGS
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
@ -94,6 +94,8 @@ done
|
|||||||
[ -z "$CREDS" ] && die "You must specify credentials (--creds)."
|
[ -z "$CREDS" ] && die "You must specify credentials (--creds)."
|
||||||
validate_channel "$CHANNEL"
|
validate_channel "$CHANNEL"
|
||||||
|
|
||||||
|
mountpoint "$(dirname "$OUTDIR")" || die "$(dirname "$OUTDIR") is not a mountpint!"
|
||||||
|
|
||||||
if [ ! -d "${OUTDIR}" ]; then
|
if [ ! -d "${OUTDIR}" ]; then
|
||||||
mkdir "${OUTDIR}" || die "Failed to create ${OUTDIR}/${NAME}!"
|
mkdir "${OUTDIR}" || die "Failed to create ${OUTDIR}/${NAME}!"
|
||||||
echo "Created $OUTDIR."
|
echo "Created $OUTDIR."
|
||||||
@ -106,14 +108,10 @@ else
|
|||||||
args="$args -nostats -loglevel warning"
|
args="$args -nostats -loglevel warning"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$FORCE_TCP" = "1" ]; then
|
|
||||||
args="$args -rtsp_transport tcp"
|
|
||||||
elif [ "$FORCE_UDP" = "1" ]; then
|
|
||||||
args="$args -rtsp_transport udp"
|
|
||||||
fi
|
|
||||||
|
|
||||||
[ ! -z "$CREDS" ] && CREDS="${CREDS}@"
|
[ ! -z "$CREDS" ] && CREDS="${CREDS}@"
|
||||||
|
|
||||||
ffmpeg $args -i rtsp://${CREDS}${IP}:${PORT}/Streaming/Channels/${CHANNEL} \
|
ffmpeg -nostdin $args -rtsp_transport tcp -i rtsp://${CREDS}${IP}:${PORT}/Streaming/Channels/${CHANNEL} \
|
||||||
-c copy -f segment -strftime 1 -segment_time 00:10:00 -segment_atclocktime 1 \
|
-c copy -f segment -strftime 1 -segment_time 00:10:00 -segment_format_options movflags=+faststart \
|
||||||
|
-segment_time_delta 0.01 -segment_atclocktime 1 -reset_timestamps 1 -bufsize 2M \
|
||||||
|
-reconnect 1 -reconnect_at_eof 1 -reconnect_streamed 1 -reconnect_delay_max 2 \
|
||||||
"$OUTDIR/record_%Y-%m-%d-%H.%M.%S.${EXTENSION}"
|
"$OUTDIR/record_%Y-%m-%d-%H.%M.%S.${EXTENSION}"
|
||||||
|
4
tools/ipcam_capture_restart_all.sh
Executable file
4
tools/ipcam_capture_restart_all.sh
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
for service in $(systemctl list-units --type service --plain --no-legend | grep ipcam_capture | awk '{print $1}'); do
|
||||||
|
systemctl restart $service
|
||||||
|
done
|
102
tools/ipcam_cleanup.sh
Executable file
102
tools/ipcam_cleanup.sh
Executable file
@ -0,0 +1,102 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Function to display usage
|
||||||
|
usage() {
|
||||||
|
echo "Usage: $0 --dir <dir1> [<dir2> ...] [--min-free-space <space_in_GiB>] [--debug]" 1>&2
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to output error messages and exit
|
||||||
|
error_msg() {
|
||||||
|
echo "Error: $1" 1>&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to output debug messages
|
||||||
|
debug_msg() {
|
||||||
|
if $DEBUG_MODE; then
|
||||||
|
echo "$1"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Initialize variables
|
||||||
|
declare -a DIRS
|
||||||
|
MIN_FREE_SPACE=200 # Default minimum free space in GiB
|
||||||
|
DEBUG_MODE=false
|
||||||
|
PARSE_DIRS=false
|
||||||
|
|
||||||
|
# Parse command-line arguments
|
||||||
|
for arg in "$@"; do
|
||||||
|
if $PARSE_DIRS; then
|
||||||
|
if [[ "$arg" =~ ^-- ]]; then
|
||||||
|
PARSE_DIRS=false
|
||||||
|
else
|
||||||
|
DIRS+=("$arg")
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
case $arg in
|
||||||
|
--dir)
|
||||||
|
PARSE_DIRS=true
|
||||||
|
;;
|
||||||
|
--min-free-space)
|
||||||
|
MIN_FREE_SPACE="$2"
|
||||||
|
shift # Remove argument value
|
||||||
|
;;
|
||||||
|
--debug)
|
||||||
|
DEBUG_MODE=true
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ "$arg" != "${DIRS[-1]}" ]; then
|
||||||
|
usage
|
||||||
|
error_msg "Unknown parameter passed: $arg"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check if at least one directory is provided and if it is indeed a directory
|
||||||
|
if [ ${#DIRS[@]} -eq 0 ]; then
|
||||||
|
usage
|
||||||
|
error_msg "No directories specified."
|
||||||
|
fi
|
||||||
|
|
||||||
|
for DIR in "${DIRS[@]}"; do
|
||||||
|
if [ ! -d "$DIR" ]; then
|
||||||
|
error_msg "'$DIR' is not a directory."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check if all directories are on the same disk
|
||||||
|
PREV_DISK=""
|
||||||
|
for DIR in "${DIRS[@]}"; do
|
||||||
|
CURRENT_DISK=$(df "$DIR" | tail -n 1 | awk '{print $1}')
|
||||||
|
if [ -n "$PREV_DISK" ] && [ "$PREV_DISK" != "$CURRENT_DISK" ]; then
|
||||||
|
usage
|
||||||
|
error_msg "Directories are not on the same disk."
|
||||||
|
fi
|
||||||
|
PREV_DISK=$CURRENT_DISK
|
||||||
|
done
|
||||||
|
|
||||||
|
# Convert GiB to KiB (as df outputs in KiB)
|
||||||
|
MIN_FREE_SPACE_KiB=$((MIN_FREE_SPACE * 1024 * 1024))
|
||||||
|
|
||||||
|
# Get the free space on the disk where the directories are located
|
||||||
|
FREE_SPACE_KiB=$(df "${DIRS[0]}" | tail -n 1 | awk '{print $4}')
|
||||||
|
|
||||||
|
# Find files (not directories) in all specified directories, sort them by modification time (oldest first)
|
||||||
|
if [ $FREE_SPACE_KiB -lt $MIN_FREE_SPACE_KiB ]; then
|
||||||
|
debug_msg "Less than $MIN_FREE_SPACE GiB free, cleaning up..."
|
||||||
|
find "${DIRS[@]}" -type f -printf '%T+ %p\n' | sort | while IFS= read -r line; do
|
||||||
|
if [ $(df "${DIRS[0]}" | tail -n 1 | awk '{print $4}') -ge $MIN_FREE_SPACE_KiB ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
FILE=$(echo "$line" | cut -d ' ' -f2-)
|
||||||
|
debug_msg "Deleting $FILE"
|
||||||
|
rm -f -- "$FILE"
|
||||||
|
REMAINING_SPACE_KiB=$(df "${DIRS[0]}" | tail -n 1 | awk '{print $4}')
|
||||||
|
debug_msg "Remaining space: $((REMAINING_SPACE_KiB / 1024 / 1024)) GiB"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
debug_msg "Enough free space available."
|
||||||
|
fi
|
5
tools/ipcam_restart_rtsp2hls_rkmpp_3hr_cron.sh
Executable file
5
tools/ipcam_restart_rtsp2hls_rkmpp_3hr_cron.sh
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
for service in $(systemctl list-units --type service | grep ipcam_rtsp2hls_rkmpp | awk '{print $1}' | grep -v \.slice\$); do
|
||||||
|
systemctl restart $service
|
||||||
|
done
|
@ -120,7 +120,7 @@ else
|
|||||||
path="$CUSTOM_PATH"
|
path="$CUSTOM_PATH"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ffmpeg $args -i "rtsp://${USER}:${PASSWORD}@${IP}:${PORT}${path}" \
|
ffmpeg $args -nostdin -i "rtsp://${USER}:${PASSWORD}@${IP}:${PORT}${path}" \
|
||||||
-c:v copy -c:a copy -bufsize 1835k \
|
-c:v copy -c:a copy -bufsize 1835k \
|
||||||
-pix_fmt yuv420p \
|
-pix_fmt yuv420p \
|
||||||
-flags -global_header -hls_time 2 -hls_list_size 3 -hls_flags delete_segments \
|
-flags -global_header -hls_time 2 -hls_list_size 3 -hls_flags delete_segments \
|
||||||
|
126
tools/ipcam_rtsp2hls_rkmpp.sh
Executable file
126
tools/ipcam_rtsp2hls_rkmpp.sh
Executable file
@ -0,0 +1,126 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
PROGNAME="$0"
|
||||||
|
OUTDIR=/var/ipcamfs # should be tmpfs
|
||||||
|
PORT=554
|
||||||
|
NAME=
|
||||||
|
IP=
|
||||||
|
USER=
|
||||||
|
PASSWORD=
|
||||||
|
DEBUG=0
|
||||||
|
CHANNEL=1
|
||||||
|
FORCE_UDP=0
|
||||||
|
FORCE_TCP=0
|
||||||
|
CUSTOM_PATH=
|
||||||
|
|
||||||
|
die() {
|
||||||
|
echo >&2 "error: $@"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<EOF
|
||||||
|
usage: $PROGNAME [OPTIONS] COMMAND
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--ip camera IP
|
||||||
|
--port RTSP port (default: 554)
|
||||||
|
--name camera name (chunks will be stored under $OUTDIR/{name}/)
|
||||||
|
--user
|
||||||
|
--password
|
||||||
|
--debug
|
||||||
|
--force-tcp
|
||||||
|
--force-udp
|
||||||
|
--channel 1|2
|
||||||
|
--custom-path PATH
|
||||||
|
|
||||||
|
EOF
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_channel() {
|
||||||
|
local c="$1"
|
||||||
|
case "$c" in
|
||||||
|
1|2)
|
||||||
|
:
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
die "Invalid channel"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
[ -z "$1" ] && usage
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--ip|--port|--name|--user|--password)
|
||||||
|
_var=${1:2}
|
||||||
|
_var=${_var^^}
|
||||||
|
printf -v "$_var" '%s' "$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
|
||||||
|
--debug)
|
||||||
|
DEBUG=1
|
||||||
|
;;
|
||||||
|
|
||||||
|
--force-tcp)
|
||||||
|
FORCE_TCP=1
|
||||||
|
;;
|
||||||
|
|
||||||
|
--force-udp)
|
||||||
|
FORCE_UDP=1
|
||||||
|
;;
|
||||||
|
|
||||||
|
--channel)
|
||||||
|
CHANNEL="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
|
||||||
|
--custom-path)
|
||||||
|
CUSTOM_PATH="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
die "Unrecognized argument: $1"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
[ -z "$IP" ] && die "You must specify camera IP address (--ip)."
|
||||||
|
[ -z "$PORT" ] && die "Port can't be empty."
|
||||||
|
[ -z "$NAME" ] && die "You must specify camera name (--name)."
|
||||||
|
[ -z "$USER" ] && die "You must specify username (--user)."
|
||||||
|
[ -z "$PASSWORD" ] && die "You must specify username (--password)."
|
||||||
|
validate_channel "$CHANNEL"
|
||||||
|
|
||||||
|
if [ ! -d "${OUTDIR}/${NAME}" ]; then
|
||||||
|
mkdir "${OUTDIR}/${NAME}" || die "Failed to create ${OUTDIR}/${NAME}!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
args=
|
||||||
|
if [ "$DEBUG" = "1" ]; then
|
||||||
|
args="-v info"
|
||||||
|
else
|
||||||
|
args="-nostats -loglevel error"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$FORCE_TCP" = "1" ]; then
|
||||||
|
args="$args -rtsp_transport tcp"
|
||||||
|
elif [ "$FORCE_UDP" = "1" ]; then
|
||||||
|
args="$args -rtsp_transport udp"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$CUSTOM_PATH" ]; then
|
||||||
|
path="/Streaming/Channels/${CHANNEL}"
|
||||||
|
else
|
||||||
|
path="$CUSTOM_PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
/home/user/FFmpeg/ffmpeg $args -nostdin -i "rtsp://${USER}:${PASSWORD}@${IP}:${PORT}${path}" \
|
||||||
|
-c:v h264_rkmpp_encoder -preset ultrafast -an -vsync drop \
|
||||||
|
-flags -global_header -hls_time 2 -hls_list_size 3 -hls_flags delete_segments \
|
||||||
|
${OUTDIR}/${NAME}/live.m3u8
|
Loading…
x
Reference in New Issue
Block a user