222 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			222 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/bin/sh
 | |
| 
 | |
| ########
 | |
| # Copyright (c) 2018-2019 Thomas Frohwein <11335318+rfht@users.noreply.github.com>
 | |
| #
 | |
| # Permission to use, copy, modify, and distribute this software for any
 | |
| # purpose with or without fee is hereby granted, provided that the above
 | |
| # copyright notice and this permission notice appear in all copies.
 | |
| #
 | |
| # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | |
| # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | |
| # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | |
| # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | |
| # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | |
| # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | |
| # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | |
| ########
 | |
| 
 | |
| ############
 | |
| # TODO:
 | |
| ############
 | |
| # - ADD OPTION TO SAVE MIC TO SEPARATE FILE (solene request)
 | |
| # - add mention of $DISPLAY variable for the recording?
 | |
| # - AFAIK '-preset ultrafast' is specific to libx264 and needs to be disabled
 | |
| #   for use of other codecs
 | |
| # - get default framerate from xrandr? same for resolution - default to desktop
 | |
| #   resolution?
 | |
| # - mention need to stop recording with Ctrl-C??
 | |
| # - add highpass=f=200,lowpass=f=3000
 | |
| # - document default resolution (if no window name provided) of 1920x1080
 | |
| # - document that if -n is not given, will default to root window
 | |
| # - document windowname (-n) needs to be in "" if multiple words
 | |
| # - document that window needs to be visible/on top
 | |
| # - link for finding twitch servers:
 | |
| #   http://bashtech.net/twitch/ingest.php
 | |
| # - does -s option need to be in "" ? -> should not be needed
 | |
| # - document that compositor has negative effect on smoothness
 | |
| # - framerate 29 seems to be better than 30 in regads to Twitch stream health
 | |
| # - should be either resolution (-r) (+ offset (-o)), window name (-n), or fullscreen (-fullscreen)
 | |
| #   -> should ideally default to geometry with default of 1280x720+0+0
 | |
| # - document '-m' turns on recording from mic
 | |
| # - '-m' currently uses hardcoded snd/0
 | |
| # - fix '-fullscreen' parameter (not working correctly)
 | |
| # - may not need as many 'thread_queue_size options, but definitely for the -f sndio inputs
 | |
| # - Cryptark crashes/hangs on this Ryzen 7 2700
 | |
| # - add '-s $OUTRES' ??
 | |
| # - -m and -noaudio should be mutually exclusive
 | |
| # - add man page
 | |
| ###########
 | |
| 
 | |
| ###########
 | |
| # LESSONS LEARNED
 | |
| ###########
 | |
| # - audio offset needs to be applied to the audio in the second ffmpeg,
 | |
| #   right of the pipe. This clearly worked as opposed to left of the pipe
 | |
| #   with Rogue Legacy recording at 900p 60fps.
 | |
| 
 | |
| USAGE="Usage: `basename $0` [-m] [-d mic_device] [-a audiooffset] [-n window_name] [-c codec] [-b bitrate] [-r resolution] [-o offset] [-fullscreen] [-s <scale_x>:<scale_y>] [-f framerate] [-v volume_adjustment] [-vmic mic_volume] [-vmon monitor_volume] [-t threads ] [-noaudio] [-crf crf] <rtmp url>"
 | |
| 
 | |
| # Parse arguments based on http://www.shelldorado.com/goodcoding/cmdargs.html
 | |
| 
 | |
| audiooffset=0.0
 | |
| bitrate=3500
 | |
| bufsize=
 | |
| container=flv
 | |
| filename=
 | |
| framerate=30
 | |
| fullscreen=0
 | |
| gop=
 | |
| heightline=
 | |
| heightval=
 | |
| hilopass=",lowpass=3000,highpass=200,afftdn"
 | |
| mic=0
 | |
| mic_device=snd/0
 | |
| noaudio=0
 | |
| offset=
 | |
| resolution=1280x720
 | |
| scaleres=
 | |
| threads=0	# -t 0 is the default and uses as many threads as available/cores
 | |
| videocodec=libx264
 | |
| volume=1.0
 | |
| volume_mic=1.0
 | |
| volume_mon=1.0
 | |
| windowname=
 | |
| widthline=
 | |
| widthval=
 | |
| wininfoargs=
 | |
| xline=
 | |
| xval=0
 | |
| yline=
 | |
| yval=0
 | |
| 
 | |
| # FIXME: set up getopt(1) use
 | |
| #args=`getopt abo: $*`
 | |
| #if [ $? -ne 0 ]
 | |
| #then
 | |
| 	#echo 'Usage: ...'
 | |
| 	#exit 2
 | |
| #fi
 | |
| #set -- $args
 | |
| #while [ $# -ne 0 ]
 | |
| #do
 | |
| 	#case "$1"
 | |
| 	#in
 | |
| 		#-a|-b)
 | |
| 			#flag="$1"; shift;;
 | |
| 		#-o)
 | |
| 			#oarg="$2"; shift; shift;;
 | |
| 		#--)
 | |
| 			#shift; break;;
 | |
| 	#esac
 | |
| #done
 | |
| 
 | |
| if [[ $# -eq 0 ]];then
 | |
| 	echo $USAGE; exit 0
 | |
| fi
 | |
| 
 | |
| while [[ $# -gt 0 ]]
 | |
| do
 | |
| 	case "$1" in
 | |
| 		-a) audiooffset="$2"; shift;;
 | |
| 		-b) bitrate="$2"; shift;;
 | |
| 		-c) videocodec="$2"; shift;;
 | |
| 		-container) container="$2"; shift;;
 | |
| 		-crf) crf="$2"; shift;;
 | |
| 		-d) mic_device="$2"; shift;;
 | |
| 		-f) framerate="$2"; shift;;
 | |
| 		-fullscreen) fullscreen=1;;
 | |
| 		-h) echo $USAGE; exit 0;;
 | |
| 		-hl) hilopass="";;
 | |
| 		-m) mic=1;;
 | |
| 		-n) windowname="$2"; shift;;
 | |
| 		-noaudio) noaudio=1;;
 | |
| 		-o) offset="$2"; shift;;
 | |
| 		-v) volume="$2"; shift;;
 | |
| 		-r) resolution="$2"; shift;;
 | |
| 		-s) scaleres="$2"; shift;;
 | |
| 		-t) threads="$2"; shift;;
 | |
| 		-vmic) volume_mic="$2"; shift;;
 | |
| 		-vmon) volume_mon="$2"; shift;;
 | |
| 		-) filename="$1"; break;;
 | |
| 		-?*) echo $USAGE; exit 0;;
 | |
| 		*) filename="$1"; break;;
 | |
| 	esac
 | |
| 	shift
 | |
| done
 | |
| 
 | |
| if [[ -z "$filename" ]];then
 | |
| 	echo $USAGE; exit 0
 | |
| fi
 | |
| 
 | |
| bufsize=`expr $bitrate \* 2`
 | |
| gop=`expr $framerate \* 2`
 | |
| 
 | |
| if [[ -n "$scaleres" ]];then
 | |
| 	scaleres="scale=${scaleres},"
 | |
| fi
 | |
| 
 | |
| # if -n was used, overwrite resolution with window parameters
 | |
| if [[ -n "$windowname" ]];then
 | |
| 	xline=`xwininfo -name "$windowname" | grep "Absolute upper-left X"`
 | |
| 	yline=`xwininfo -name "$windowname" | grep "Absolute upper-left Y"`
 | |
| 	widthline=`xwininfo -name "$windowname" | grep "Width:"`
 | |
| 	heightline=`xwininfo -name "$windowname" | grep "Height:"`
 | |
| 	xval=`echo "$xline" | cut -f 7 -d " "`
 | |
| 	yval=`echo "$yline" | cut -f 7 -d " "`
 | |
| 	# width and height need to be multiples of 2
 | |
| 	widthval=`echo "$widthline" | cut -f 4 -d " "`
 | |
| 	if [[ `expr $widthval % 2` -eq 1 ]]; then
 | |
| 		widthval=`expr $widthval + 1`
 | |
| 	fi
 | |
| 	heightval=`echo "$heightline" | cut -f 4 -d " "`
 | |
| 	if [[ `expr $heightval % 2` -eq 1 ]]; then
 | |
| 		heightval=`expr $heightval + 1`
 | |
| 	fi
 | |
| 	resolution="${widthval}x${heightval}"
 | |
| 	offset="+${xval},${yval}"
 | |
| fi
 | |
| 
 | |
| echo "Press Ctrl+C to stop recording\n" >& 2
 | |
| 
 | |
| BASE="\
 | |
| -hide_banner \
 | |
| -loglevel error \
 | |
| -thread_queue_size 512 \
 | |
| -threads $threads"
 | |
| 
 | |
| VIDEO="-video_size $resolution \
 | |
| -thread_queue_size 512 \
 | |
| -f x11grab \
 | |
| -i $DISPLAY$offset \
 | |
| -r $framerate \
 | |
| -c:v $videocodec \
 | |
| -vb ${bitrate}k \
 | |
| -minrate ${bitrate}k \
 | |
| -maxrate ${bitrate}k \
 | |
| -bufsize ${bufsize}k \
 | |
| -preset ultrafast \
 | |
| -vf "${scaleres}format=yuv420p" \
 | |
| -g $gop \
 | |
| -keyint_min $framerate"
 | |
| 
 | |
| AUDIOMERGE="volume=$volume_mic,aformat=channel_layouts=stereo$hilopass[l];[1]volume=$volume_mon,aformat=channel_layouts=stereo[m];[l][m]amix=inputs=2[a]"
 | |
| 
 | |
| # if no mic (= no -m), only record from snd/0.mon
 | |
| #	and the only filter is aresample=async=1
 | |
| 
 | |
| if [ $noaudio -lt 1 -a $mic -lt 1 ]; then
 | |
| 	#only monitoring stream
 | |
| 	ffmpeg $BASE -f sndio -i snd/mon -c:a aac -f nut pipe:1 | \
 | |
| 	ffmpeg $BASE -f nut -itsoffset $audiooffset -i pipe:0 $VIDEO -c:a copy -f "${container}" "$filename"
 | |
| elif [ $noaudio -lt 1 ]; then
 | |
| 	#mon + mic stream
 | |
| 	ffmpeg $BASE -thread_queue_size 512 -f sndio -i "$mic_device" \
 | |
| 	-thread_queue_size 512 -f sndio -i snd/mon \
 | |
| 	-filter_complex "[0]${AUDIOMERGE}" -map '[a]' -c:a aac -f nut pipe:1 | \
 | |
| 	ffmpeg $BASE -thread_queue_size 512 -f nut -itsoffset $audiooffset -i pipe:0 $VIDEO -c:a copy -f "${container}" "$filename"
 | |
| else
 | |
| 	#no audio
 | |
| 	ffmpeg $BASE $VIDEO -f "${container}" "$filename"
 | |
| fi
 | 
