+#!/bin/bash
+
+# WARNING: This is a terribly dirty and messy shellscript, written over a
+# couple of late nights. There was alcohol …
+#
+# Further tweaks and porting to free codecs done one early Saturday morning
+# in May. There was no coffee … and very little experience with vp8
+#
+# So this script allows you to create screencasts on Linux, with optional
+# sound inputs (both Microphone and system sounds). It stores system sounds
+# and microphone in separate audio streams.
+#
+# It dumps the recording in your $HOME directory with a filename like
+# screencast-YYYY-MM-DD-HH-MM-SS.mp4
+#
+# Written by Einar Jørgen Haraldseid (http://einar.slaskete.net)
+# License: http://sam.zoy.org/wtfpl/COPYING
+
+# Get device names and pretty names for enumerating playback sinks:
+PLAYSINKLIST=$(pacmd list-sinks | \
+ grep -e "name: " -e "device.description = " | cut -d " " -f "2-" | \
+ sed -e "s/name: \|= //g" -e "s/<\|>\|\x22//g")
+
+# Display playback monitor chooser
+PLAYMON=$(echo "${PLAYSINKLIST}
+none
+Don't capture system sounds" | \
+ zenity --list --title "Choose Output Device" \
+ --text "Choose a sound device to capture system sound from:" \
+ --column "device" --column "Name" --print-column=1 \
+ --hide-column=1 2>/dev/null)
+
+# Catch cancel
+if [ -z ${PLAYMON} ]; then
+ echo "No choice made on output device, assuming cancel."
+ exit 1
+fi
+
+if [ ${PLAYMON} != "none" ]; then
+ # Unmute monitor of the playback sink (if set):
+ PLAYMON="${PLAYMON}.monitor"
+ pacmd set-source-mute ${PLAYMON} false >/dev/null
+ echo "Recording system sounds from ${PLAYMON}"
+else
+ echo "Not recording system sounds."
+fi
+
+# Get device names and pretty names for microphones:
+MICLIST=$(pacmd list-sources | \
+ grep -e "name: " -e "device.description = " | \
+ grep -v -i "monitor" | cut -d " " -f "2-" | \
+ sed -e "s/name: \|= //g" -e "s/<\|>\|\x22//g")
+
+# Display device chooser
+MIC=$(echo "${MICLIST}
+none
+Don't use a microphone" | \
+ zenity --list --title "Choose Microphone" \
+ --text "Choose a microphone to capture voice from:" \
+ --column "device" --column "Name" --print-column=1 \
+ --hide-column=1 2>/dev/null)
+
+if [ -z ${MIC} ]; then
+ echo "No choice made on microphone, assuming cancel."
+ exit 1
+fi
+
+if [ ${MIC} != "none" ]; then
+ echo "Recording voice from ${MIC}"
+else
+ echo "Not recording voice."
+fi
+
+# Get target window for recording:
+TARGET=$(echo "root
+Whole screen
+window
+Specific window" | \
+ zenity --list --title "Choose recording mode" \
+ --text "Do you want to record the whole screen,\
+ or record a specific window?" --column "target" \
+ --column "Mode" --print-column=1 --hide-column=1 2>/dev/null)
+
+if [ -z ${TARGET} ]; then
+ echo "No choice for recording target, assuming cancel."
+ exit 1
+fi
+
+if [ ${TARGET} = "root" ]; then
+ echo "Root window chosen."
+ XWININFO=$(xwininfo -root)
+else
+ echo "Custom window chosen."
+ XWININFO=$(xwininfo)
+fi
+
+# Get Window ID and dimensions, make sure X and Y dimensions are
+# divisible by two, or else the encoder might fail
+WID=$(echo "${XWININFO}" | grep "Window id:" | awk '{print $4}')
+WIDTH=$(echo "${XWININFO}" | grep "Width: " | \
+ cut -d ":" -f 2 | awk '{print $1+$1%2}')
+HEIGHT=$(echo "${XWININFO}" | grep "Height: " | \
+ cut -d ":" -f 2 | awk '{print $1+$1%2}')
+
+# Calculate a suitable bitrate based on window dimensions
+BITRATE=$(echo "${WIDTH} * ${HEIGHT} * 0.85" | bc | cut -d "." -f 1 )
+
+# Set file name.
+FILENAME="screencast-$(date +%F-%H-%M-%S).webm"
+
+# Enable inputs as suitable
+if [ ${PLAYMON} != "none" ]; then
+ MONITORARG="pulsesrc device=${PLAYMON} slave-method=0 provide-clock=false \
+ ! audiorate ! audioconvert ! vorbisenc ! queue2 ! mux."
+fi
+if [ ${MIC} != "none" ]; then
+ MICARG="pulsesrc device=${MIC} slave-method=0 provide-clock=false \
+ ! audiorate ! audioconvert ! vorbisenc ! queue2 ! mux."
+fi
+
+# Launch gstreamer
+gst-launch-1.0 -q -e ximagesrc xid="${WID}" do-timestamp=1 use-damage=0 \
+ ! video/x-raw,framerate=20/1 ! videoscale method=0 \
+ ! video/x-raw,width=${WIDTH},height=${HEIGHT} ! videoconvert \
+ ! vp8enc end-usage=vbr cpu-used=16 target-bitrate=${BITRATE} \
+ deadline=100 static-threshold=1000 min-quantizer=0 max-quantizer=63 ! queue2 \
+ ! webmmux name="mux" \
+ ! filesink location="${HOME}/${FILENAME}" ${MONITORARG} ${MICARG}
+
+echo "Recording done, file is ${FILENAME}"