227 lines
5.7 KiB
Bash
227 lines
5.7 KiB
Bash
#!/usr/bin/env bash
|
|
#
|
|
set -euo pipefail
|
|
IFS=$'\n\t'
|
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
|
|
: ${VIDEO_BITRATE:="1M"} # Only for encoding modes targeting bitrate
|
|
: ${AUDIO_BITRATE:="192k"}
|
|
: ${SPEED:="1"}
|
|
|
|
############## Setup #########################
|
|
|
|
function die {
|
|
local status_code="$1"
|
|
shift
|
|
(>&2 echo "${@}")
|
|
exit "$status_code"
|
|
}
|
|
|
|
function log {
|
|
(>&2 echo "${@}")
|
|
}
|
|
|
|
############## Program #########################
|
|
|
|
function main {
|
|
local cmd
|
|
cmd=$1
|
|
shift
|
|
if [ "$cmd" = "copy" ]; then
|
|
copy "${@}"
|
|
elif [ "$cmd" = "convert" ]; then
|
|
convert "${@}"
|
|
elif [ "$cmd" = "stream" ]; then
|
|
stream "${@}"
|
|
elif [ "$cmd" = "webcam" ]; then
|
|
webcam "${@}"
|
|
elif [ "$cmd" = "encode_webcam" ]; then
|
|
encode_webcam "${@}"
|
|
else
|
|
(>&2 echo "Unknown command: $cmd")
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
function copy {
|
|
local file_to_cast
|
|
file_to_cast="$3"
|
|
|
|
local USERNAME PASSWORD
|
|
USERNAME="$1"
|
|
PASSWORD="$2"
|
|
|
|
set -x
|
|
</dev/null exec ffmpeg \
|
|
-re \
|
|
-stream_loop -1 \
|
|
-i "$file_to_cast" \
|
|
-c copy \
|
|
-strict experimental \
|
|
-f rtsp \
|
|
-rtsp_transport tcp \
|
|
"rtsp://$USERNAME:$PASSWORD@172.16.16.251:8554/fetch"
|
|
}
|
|
|
|
# benchmark vulkan decode:
|
|
# ffmpeg -init_hw_device "vulkan=vk:0" -hwaccel vulkan -hwaccel_output_format vulkan -i INPUT -f null - -benchmark
|
|
function convert {
|
|
local args=()
|
|
local acceleration_type="$1" # "software" or "hardware"
|
|
local codec="$2" # "h264" or "av1"
|
|
local file_to_cast="$3"
|
|
local file_to_save="$4"
|
|
|
|
|
|
|
|
# Verify parameters
|
|
|
|
|
|
if [ "$acceleration_type" == "software" ]; then
|
|
true
|
|
elif [ "$acceleration_type" == "hardware" ]; then
|
|
true
|
|
else
|
|
die 1 "Unknown acceleration type: $acceleration_type"
|
|
fi
|
|
|
|
if [ "$codec" == "h264" ]; then
|
|
true
|
|
elif [ "$codec" == "av1" ]; then
|
|
true
|
|
else
|
|
die 1 "Unknown codec: $codec"
|
|
fi
|
|
|
|
|
|
|
|
# Build command
|
|
|
|
|
|
|
|
if [ "$acceleration_type" == "software" ]; then
|
|
true
|
|
elif [ "$acceleration_type" == "hardware" ]; then
|
|
if [ "$codec" == "h264" ]; then
|
|
args+=(-init_hw_device vulkan)
|
|
elif [ "$codec" == "av1" ]; then
|
|
args+=(-vaapi_device /dev/dri/renderD128)
|
|
fi
|
|
fi
|
|
|
|
args+=(-i "$file_to_cast")
|
|
|
|
if [ "$SPEED" != "1" ]; then
|
|
local audio_speed video_speed
|
|
video_speed=$(bc -l <<< "1/${SPEED}")
|
|
audio_speed=$(bc -l <<< "${SPEED}/1")
|
|
args+=(-filter:v "setpts=${video_speed}*PTS")
|
|
args+=(-filter:a "atempo=${audio_speed}")
|
|
fi
|
|
|
|
if [ "$codec" == "h264" ]; then
|
|
if [ "$acceleration_type" == "software" ]; then
|
|
args+=(-c:v h264)
|
|
args+=(-profile:v high)
|
|
args+=(-b:v "$VIDEO_BITRATE")
|
|
elif [ "$acceleration_type" == "hardware" ]; then
|
|
args+=(-vf 'format=nv12|vaapi,hwupload')
|
|
args+=(-c:v h264_vulkan)
|
|
args+=(-profile:v high)
|
|
args+=(-b:v "$VIDEO_BITRATE")
|
|
fi
|
|
elif [ "$codec" == "av1" ]; then
|
|
if [ "$acceleration_type" == "software" ]; then
|
|
args+=(-c:v libsvtav1)
|
|
args+=(-preset 4) # [0-13] default 10, lower = higher quality / slower encode
|
|
# args+=(-crf 20) # [0-63] default 35, lower = higher quality / larger file
|
|
# Parameters: https://gitlab.com/AOMediaCodec/SVT-AV1/-/blob/master/Docs/Parameters.md
|
|
# fast-decode [0-2] default 0 (off), higher = faster decode
|
|
# tune [0-2] default 1, Specifies whether to use PSNR or VQ as the tuning metric [0 = VQ, 1 = PSNR, 2 = SSIM]
|
|
# film-grain-denoise, setting to 0 uses the original frames instead of denoising the film grain
|
|
# rc 1 = vbr 2 = cbr
|
|
# tbr = average bitrate
|
|
args+=(-svtav1-params "fast-decode=1:film-grain-denoise=0:tbr=${VIDEO_BITRATE}:rc=1:passes=2")
|
|
elif [ "$acceleration_type" == "hardware" ]; then
|
|
# -c:v av1_amf -quality quality
|
|
args+=(-vf 'format=nv12|vaapi,hwupload')
|
|
args+=(-c:v av1_vaapi)
|
|
args+=(-b:v "$VIDEO_BITRATE")
|
|
fi
|
|
fi
|
|
|
|
|
|
|
|
# -bf 0 :: Disable b-frames because webrtc doesn't support h264 streams with b-frames.
|
|
args+=(-bf 0)
|
|
args+=(-strict -2)
|
|
args+=(-c:a opus)
|
|
args+=(-ac 2)
|
|
args+=(-b:a "$AUDIO_BITRATE")
|
|
args+=(-ar 48000)
|
|
args+=("$file_to_save")
|
|
set -x
|
|
</dev/null exec ffmpeg "${args[@]}"
|
|
}
|
|
|
|
function stream {
|
|
local args=()
|
|
local acceleration_type="$1" # "software" or "hardware"
|
|
local codec="$2" # "h264" or "av1"
|
|
|
|
local USERNAME="$3"
|
|
local PASSWORD="$4"
|
|
local file_to_cast="$5"
|
|
|
|
|
|
args+=(-re -stream_loop -1)
|
|
|
|
args+=(-f rtsp)
|
|
args+=(-rtsp_transport tcp)
|
|
args+=("rtsp://$USERNAME:$PASSWORD@172.16.16.251:8554/fetch")
|
|
}
|
|
|
|
function webcam {
|
|
# Uses on-webcam h264 encoding.
|
|
|
|
local USERNAME PASSWORD
|
|
USERNAME="$1"
|
|
PASSWORD="$2"
|
|
|
|
set -x
|
|
|
|
</dev/null exec ffmpeg \
|
|
-re \
|
|
-input_format h264 \
|
|
-video_size 1920x1080 \
|
|
-i /dev/video0 \
|
|
-c:v copy \
|
|
-an \
|
|
-f rtsp \
|
|
-rtsp_transport tcp \
|
|
"rtsp://$USERNAME:$PASSWORD@172.16.16.251:8554/fetch"
|
|
}
|
|
|
|
function encode_webcam {
|
|
# Uses hardware accelerated gpu-based encoding.
|
|
|
|
local USERNAME PASSWORD
|
|
USERNAME="$1"
|
|
PASSWORD="$2"
|
|
|
|
set -x
|
|
|
|
</dev/null exec ffmpeg \
|
|
-re \
|
|
-vaapi_device /dev/dri/renderD128 \
|
|
-i /dev/video0 \
|
|
-vf 'format=nv12,hwupload' \
|
|
-c:v h264_vaapi \
|
|
-an \
|
|
-f rtsp \
|
|
-rtsp_transport tcp \
|
|
"rtsp://$USERNAME:$PASSWORD@172.16.16.251:8554/fetch"
|
|
}
|
|
|
|
main "${@}"
|