#!/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"} ############## 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" } 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 args+=(-vaapi_device /dev/dri/renderD128) fi args+=(-i "$file_to_cast") 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_vaapi) 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 args+=(-svtav1-params "fast-decode=1:film-grain-denoise=0") 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" } function speed_up_preprocess_vp8 { local file_to_cast file_to_save file_to_cast="$1" file_to_save="$2" set -x # -bf 0 :: Disable b-frames because webrtc doesn't support h264 streams with b-frames. # -strict -2 :: Enable support for experimental codecs like opus. # -b:v 2M :: Target 2 megabit/s # -crf 10 :: Target a quality level and adjust bitrate accordingly. This should be preferred, but ideally both should be used. # Could also use -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" -map "[v]" -map "[a]" </dev/null exec ffmpeg \ -i "$file_to_cast" \ -filter:v "setpts=0.66666666*PTS" \ -filter:a "atempo=1.5" \ -c:v vp8 \ -b:v 2M \ -crf 10 \ -bf 0 \ -c:a opus \ -b:a 320k \ -ar 48000 \ -strict -2 \ "$file_to_save" } main "${@}"