238 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			238 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | #!/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 "${@}" |