Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Gjum/7351b5fda8f6990a4cd9 to your computer and use it in GitHub Desktop.
Save Gjum/7351b5fda8f6990a4cd9 to your computer and use it in GitHub Desktop.

this repo contains two analogous script prototypes for screencasting to livecoding.tv

  • ffmpeg implementation - full-featured and works quite well
  • gstreamer implementetion - work in progress
#!/bin/bash
THIS_NAME=`basename $0`
USAGE="USAGE:
$THIS_NAME [ a_configuration [ once ] ]
when called with no arguments the stream runs the default configuration, automatically
restarting after any exceptional event (device error , dropped connection , etc)
the optional \"a_configuration\" selects a particular configuration and is one of:
[ screen , screen+text , screen+cam , cam+text , all , break ]
the optional second argument 'once' disables automatic restarts
NOTE: STREAM_KEY must be defined either in this script or in the environment
NOTE: all configurations include audio - set CAPTURE_AUDIO to 0 to disable"
# the entries under the following headings are intended for per-user configuration:
# * user a/v params (STREAM_KEY must be defined)
# * user image params
# * user text params
# * user text configuration
# * user a/v configuration
# * user logging configuration
#
# the entries under the following headings are general and suitable for most cases:
# * general a/v params
# * general text params
# * general logging params
# * general a/v configuration
#
# when one of the configurations displaying text is chosen
# the first line of $TEXT_FILE will be rendered
# user a/v params
[ ! -z "$STREAM_KEY" ] || STREAM_KEY="" # your private stream key (or define STREAM_KEY in env)
SCREEN_W=1280 # input screen width (e.g. desktop width )
SCREEN_H=800 # input screen height (e.g. desktop height)
SCREEN_N=":0.0" # display/screen number to capture (usually :0.0)
CAM_LG_W=640 # input screen width (e.g. desktop width )
CAM_LG_H=480 # input screen height (e.g. desktop height)
CAM_SM_W=160 # input screen width (e.g. desktop width )
CAM_SM_H=120 # input screen height (e.g. desktop height)
CAM_DEV=/dev/video42 # video device to grab (first is /dev/video0)
STREAM_W=1280 # input screen width (e.g. desktop width )
STREAM_H=800 # input screen height (e.g. desktop height)
FPS=12 # target output FPS
GOP="$(($FPS*4))" # i-frame interval
CBR="1200k" # constant output bitrate (should be between 800k - 1300k)
CAPTURE_AUDIO=1 # set to 1 to capture audio - 0 to disable audio
AUDIO_CHANNELS=2 # number of channels
AUDIO_SAMPLERATE=22050 # audio samplerate (22050 is plenty for voice)
AUDIO_BITRATE="128k" # audio bitrate (64k per channel is plenty for voice)
ALSA_DEVICE="hw:0" # ALSA plug device (usually hw:0)
THREADS=0 # 0 for auto - max 6
QUALITY="ultrafast" # one of the many FFMPEG presets
EXIT_CMD="play-error-sound.sh"
# user image params
[ ! -z "$STREAM_IMG" ] || STREAM_IMG="" # fullscreen interstitial image (or define STREAM_IMG in env)
[ ! -z "$LOGO_IMG" ] || LOGO_IMG="" # small overlay image (or define LOGO_IMG in env)
# user text params
TEXT_FILE=/run/user/`id -u`/av-caster-text
[ ! -z "$STREAM_TEXT" ] || STREAM_TEXT="" # initial overlay text (or define STREAM_TEXT in env)
FONT_FILE=/usr/share/fonts/truetype/tlwg/Purisa.ttf
FONT_SIZE=48
TEXT_BORDER_D=4
TEXT_SHADOW_W=8
TEXT_SHADOW_H=8
BLINK_TEXT_PERIOD=300 # repeat interval in seconds
TEXT_MARQUEE_SPEED=6 # ~= n characters per second
TEXT_COLOR='[email protected]'
TEXT_BORDER_COLOR='[email protected]'
TEXT_BG_COLOR='[email protected]'
# general a/v params
SCREEN_RES=$SCREEN_W'x'$SCREEN_H # screen capture input resolution
CAM_HI_RES=$CAM_LG_W'x'$CAM_LG_H # webcam input/output high resolution (fullscreen)
CAM_LO_RES=$CAM_SM_W'x'$CAM_SM_H # webcam input/output low resolution (overlay)
STREAM_RES=$STREAM_W'x'$STREAM_H # mix output resolution
SCREENCAP_INPUT="-f x11grab -s $SCREEN_RES -r $FPS -i $SCREEN_N"
WEBCAM_INPUT_LG="-f video4linux2 -s $CAM_HI_RES -i $CAM_DEV"
WEBCAM_INPUT_SM="-f video4linux2 -s $CAM_LO_RES -i $CAM_DEV"
STATIC_INPUT_LG="-f image2 -loop 1 -r $FPS -i $STREAM_IMG"
STATIC_INPUT_SM="-f image2 -loop 1 -r $FPS -i $LOGO_IMG" # unused
ALSA_INPUT=" -f alsa -i $ALSA_DEVICE" # unused
PULSE_INPUT=" -f pulse -name $THIS_NAME -sample_rate $AUDIO_SAMPLERATE
-channels $AUDIO_CHANNELS -i default" # unused
JACK_INPUT=" -f jack -channels $AUDIO_CHANNELS -i $THIS_NAME"
OVERLAY_TL_POS="0: 0" # unused
OVERLAY_BR_POS="main_w-overlay_w: main_h-overlay_h"
X264_OUTPUT="-vcodec libx264 -pix_fmt yuv420p -preset $QUALITY -s $STREAM_RES
-g $GOP -vb $CBR -maxrate $CBR -bufsize $CBR"
AAC_OUTPUT="-acodec aac -ar $AUDIO_SAMPLERATE -ab $AUDIO_BITRATE -strict experimental"
THREADS="-threads $THREADS"
RTMP_URL="rtmp://usmedia3.livecoding.tv:1935/livecodingtv/$STREAM_KEY"
DUMP_FILE=./livecoding.mp4
FILE_OUTPUT="-f flv $DUMP_FILE"
LIVE_OUTPUT="-f flv $RTMP_URL"
# general text params
FONT='fontfile='$FONT_FILE': fontsize='$FONT_SIZE': fontcolor='$TEXT_COLOR': shadowx='$TEXT_SHADOW_W' : shadowy='$TEXT_SHADOW_H
TEXT_BG='box=1: boxcolor='$TEXT_BG_COLOR # unused
TEXT_BORDER='borderw='$TEXT_BORDER_D': bordercolor='$TEXT_BORDER_COLOR
[ ! -z "$TEXT_FILE" ] && [ -f $TEXT_FILE ] && STREAM_TEXT=`cat $TEXT_FILE`
BLINK_TEXT_DURATION=$((${#STREAM_TEXT}/$TEXT_MARQUEE_SPEED))
BLINK_TEXT=': enable=lt(mod(t\,'$BLINK_TEXT_PERIOD')\,'$BLINK_TEXT_DURATION')' # unused
STATIC_TEXT='text='$STREAM_TEXT # unused
TEXT_X_CENTER_POS='x=(main_w-text_w)/2'
TEXT_Y_TOP_POS='y=0' # unused
TEXT_Y_BOTTOM_POS='y=main_h-(line_h*1.5)'
TEXT_X_MARQUEE_POS='x=main_w-((('$SCREEN_W'+text_w)/'$BLINK_TEXT_DURATION')*mod(t\,'$BLINK_TEXT_DURATION'))'$BLINK_TEXT
FILE_TEXT="textfile=$TEXT_FILE: reload=1"
# general logging params
LOGGING_NONE="-loglevel quiet"
LOGGING_ERRORS="-loglevel error"
LOGGING_VERBOSE=""
# user a/v configuration
OVERLAY_INPUT=$WEBCAM_INPUT_SM # one of WEBCAM_INPUT_SM , STATIC_INPUT_SM
OVERLAY_POS=$OVERLAY_BR_POS # one of OVERLAY_TL_POS , OVERLAY_BR_POS
AUDIO_INPUT=$JACK_INPUT # one of ALSA_INPUT , PULSE_INPUT , JACK_INPUT
VIDEO_OUTPUT=$X264_OUTPUT # only X264_OUTPUT is defined (others are possible)
AUDIO_OUTPUT=$AAC_OUTPUT # only AAC_OUTPUT is defined (others are possible)
STREAM_OUTPUT=$LIVE_OUTPUT # one of FILE_OUTPUT , LIVE_OUTPUT
# general a/v configuration
[ ! -z "$TEXT_FILE" ] && [ ! -f $TEXT_FILE ] && echo "$STREAM_TEXT" > $TEXT_FILE
(($CAPTURE_AUDIO)) || (AUDIO_INPUT="" ; AUDIO_OUTPUT="")
# user text configuration
TEXT=": $FILE_TEXT"
# TEXT_POS=": $TEXT_X_CENTER_POS: $TEXT_Y_BOTTOM_POS"
TEXT_POS=": $TEXT_X_MARQUEE_POS: $TEXT_Y_BOTTOM_POS"
TEXT_DECORATIONS=": $TEXT_BORDER"
DRAWTEXT_PARAMS="$FONT $TEXT $TEXT_POS $TEXT_DECORATIONS"
# user logging configuration
LOGGING=$LOGGING_NONE # console output (one of LOGGING_NONE , LOGGING_ERRORS , LOGGING_VERBOSE)
screenOnly()
{
printf "\nlaunching screenOnly configuration\n\n"
ffmpeg $SCREENCAP_INPUT \
$AUDIO_INPUT \
$VIDEO_OUTPUT \
$AUDIO_OUTPUT \
$THREADS \
$LOGGING \
$STREAM_OUTPUT
QUIT=$?
echo "QUIT=$QUIT"
}
screenPlusText()
{
printf "\nlaunching screenPlusText configuration\n\n"
ffmpeg $SCREENCAP_INPUT \
-filter_complex drawtext="$DRAWTEXT_PARAMS" \
$AUDIO_INPUT \
$VIDEO_OUTPUT \
$AUDIO_OUTPUT \
$THREADS \
$LOGGING \
$STREAM_OUTPUT
QUIT=$?
}
screenPlusCam()
{
printf "\nlaunching screenPlusCam configuration\n\n"
avconv $SCREENCAP_INPUT \
$OVERLAY_INPUT \
-filter_complex overlay="$OVERLAY_POS" \
$AUDIO_INPUT \
$VIDEO_OUTPUT \
$AUDIO_OUTPUT \
$THREADS \
$LOGGING \
$STREAM_OUTPUT
QUIT=$?
}
camPlusText()
{
printf "\nlaunching camPlusText configuration\n\n"
ffmpeg $WEBCAM_INPUT_LG \
-filter_complex drawtext="$DRAWTEXT_PARAMS" \
$AUDIO_INPUT \
$VIDEO_OUTPUT \
$AUDIO_OUTPUT \
$THREADS \
$LOGGING \
$STREAM_OUTPUT
QUIT=$?
}
screenPlusCamPlusText()
{
printf "\nlaunching screenPlusCamPlusText configuration\n\n"
ffmpeg $SCREENCAP_INPUT \
$OVERLAY_INPUT \
-filter_complex "overlay='$OVERLAY_POS', drawtext='$DRAWTEXT_PARAMS'" \
$AUDIO_INPUT \
$VIDEO_OUTPUT \
$AUDIO_OUTPUT \
$THREADS \
$LOGGING \
$STREAM_OUTPUT
QUIT=$?
}
interstitial()
{
printf "\nlaunching interstitial configuration\n\n"
ffmpeg $STATIC_INPUT_LG \
$AUDIO_INPUT \
$VIDEO_OUTPUT \
$AUDIO_OUTPUT \
$THREADS \
$LOGGING \
$STREAM_OUTPUT
QUIT=$?
}
launch()
{
printf "\nstream started at `date`\n\n$QUIT_MSG" ;
$SELECTED_CONFIGURATION
printf "\nstream ended at `date`\n\n" ;
}
# swicth on configuration
SELECTED_CONFIGURATION="screenPlusCamPlusText"
[ "$1" == "screen" ] && SELECTED_CONFIGURATION="screenOnly"
[ "$1" == "screen+text" ] && SELECTED_CONFIGURATION="screenPlusText"
[ "$1" == "screen+cam" ] && SELECTED_CONFIGURATION="screenPlusCam"
[ "$1" == "cam+text" ] && SELECTED_CONFIGURATION="camPlusText"
[ "$1" == "all" ] && SELECTED_CONFIGURATION="screenPlusCamPlusText"
[ "$1" == "break" ] && SELECTED_CONFIGURATION="interstitial"
# sanity checks
if [ -z "$STREAM_KEY" ] ; then echo "STREAM_KEY undefined" ; exit ; fi ;
if [ -z "$STREAM_IMG" ] && [ "$SELECTED_CONFIGURATION" == "interstitial" ]
then echo "STREAM_IMG undefined" ; exit ; fi ;
# launch configuration once
QUIT_MSG="press <q> to exit"
if [ "$2" == "once" ] ; then launch ; exit ; fi ;
# launch configuration indefinitely
QUIT_MSG="press <q> to restart the stream - press <CTRL-c> to exit"
# while ! (($QUIT)) ; do sleep 1 ; launch ; $EXIT_CMD ; done ;
# TODO: ffmpeg exits with 0 on server kick - need some way to trap this
while ((1)) ; do sleep 1 ; launch ; $EXIT_CMD ; done ;
#!/bin/bash
# NOTE: this script is not yet working properly
# screencap works well as do videotestsrc and audiotestsrc
# but using alsa , pulse , or jack audio cause the audio to be intermittent
# e.g. recording "test 1 2 3 4 5 6 7 8 9" results like "test 3 6 8 9"
# configuration
WIDTH=1280
HEIGHT=800
FPS=12
VIDEO_BITRATE=1200
SAMPLERATE=44100
AUDIO_BITRATE=128
N_CHANNELS=2
# constants
VIDEO_TEST_SRC='videotestsrc pattern=0 is-live=true'
AUDIO_TEST_SRC='audiotestsrc is-live=true'
# SCREENCAP_SRC="ximagesrc endx=$(($WIDTH-1)) endy=$(($HEIGHT-1)) use-damage=false show-pointer=true"
# TIME_SRC='timeoverlay halignment=left valignment=top text="t:" shaded-background=true'
PULSE_SRC='pulsesrc'
H264_ENCODER="x264enc bitrate=$VIDEO_BITRATE bframes=0"
LAME_ENCODER="lamemp3enc bitrate=$AUDIO_BITRATE"
# VIDEO_TEST_CAPS="video/x-raw, format=(string)BGRA, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=$FPS/1, width=$WIDTH, height=$HEIGHT"
# AUDIO_TEST_CAPS="audio/x-raw, format=(string)S16LE, endianness=(int)1234, signed=(boolean)true, width=(int)16, depth=(int)16, rate=(int)$SAMPLERATE, channels=(int)$N_CHANNELS"
# PULSE_CAPS=" audio/x-raw, format=(string)S16LE, rate=(int)$SAMPLERATE, channels=(int)$N_CHANNELS, layout=(string)interleaved"
VIDEO_TEST_CAPS="video/x-raw, format=(string)BGRA, framerate=(fraction)$FPS/1, width=(int)$WIDTH, height=(int)$HEIGHT"
AUDIO_TEST_CAPS="audio/x-raw, format=(string)S16LE, rate=(int)$SAMPLERATE, channels=(int)$N_CHANNELS"
SCREENCAP_CAPS=" video/x-raw, framerate=(fraction)$FPS/1, width=(int)$WIDTH, height=(int)$HEIGHT, pixel-aspect-ratio=(fraction)1/1"
PULSE_CAPS=" audio/x-raw, format=(string)S16LE, rate=(int)$SAMPLERATE, channels=(int)$N_CHANNELS"
H264_ENC_CAPS=' video/x-h264, level=(string)4.1, profile=main'
FLV_MUXER='flvmux streamable=true name=mux'
OUTPUT_FILE=./deleteme.flv
FILE_OUTPUT="filesink location=$OUTPUT_FILE"
DEBUG_LOGGING='--gst-debug-level=2'
VERBOSE_LOGGING='--verbose'
# input selections
VIDEO_SRC=$VIDEO_TEST_SRC
VIDEO_CAPS=$VIDEO_TEST_CAPS
# OVERLAY_SRC=$TIME_SRC # NOTE: put OVERLAY_SRC between VIDEO_SRC and VIDEO_CAPS
VIDEO_ENC_CAPS=$H264_ENC_CAPS
VIDEO_ENCODER=$H264_ENCODER
# AUDIO_SRC=$AUDIO_TEST_SRC
AUDIO_SRC=$PULSE_SRC
# AUDIO_CAPS=$AUDIO_TEST_CAPS
AUDIO_CAPS=$PULSE_CAPS
AUDIO_ENCODER=$LAME_ENCODER
MUXER=$FLV_MUXER
OUTPUT_STREAM=$FILE_OUTPUT
LOGGING="$DEBUG_LOGGING $VERBOSE_LOGGING"
gst-launch-1.0 $LOGGING $VIDEO_SRC ! \
$VIDEO_CAPS ! \
queue ! \
videoconvert ! \
$VIDEO_ENCODER ! \
h264parse ! \
$VIDEO_ENC_CAPS ! \
queue ! \
mux. \
$AUDIO_SRC ! \
$AUDIO_CAPS ! \
queue ! \
queue ! \
$AUDIO_ENCODER ! \
mpegaudioparse ! \
queue ! \
queue ! \
queue ! \
mux. \
$MUXER ! \
queue ! \
$OUTPUT_STREAM
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment