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