#!/bin/bash

# WARNING: This is a terribly dirty and messy shellscript, written over a
# couple of late nights. There was alcohol …
# You probably need to install all the gstreamer-plugins (at least -ugly
# and -ffmpeg) as well as gstreamer-tools to get this to work. I wanted to
# make mp4 files with x264, I didn't bother with free codecs.
#
# 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.
#
# You also get to choose to record from the whole screen or just a specified
# window. It has been tested on Fedora 18, Ubuntu 13.04 and CrunchBang Waldorf
# (and thus should work on Debian Wheezy as well).
#
# 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 will 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.0075" | bc | cut -d "." -f 1 )

# Set file name.
FILENAME="screencast-$(date +%F-%H-%M-%S).mp4"

# Determine if we have ffenc_aac or avenc_aac available
AACENC="ffenc_aac"
if gst-inspect-1.0 --exists avenc_aac; then 
  AACENC="avenc_aac"
fi

# Enable inputs as suitable
if [ ${PLAYMON} != "none" ]; then
  MONITORARG="pulsesrc device=${PLAYMON} slave-method=0 provide-clock=false \
   ! audiorate ! audioconvert ! ${AACENC} bitrate=256000 ! queue2 ! mux."
fi
if [ ${MIC} != "none" ]; then
  MICARG="pulsesrc device=${MIC} slave-method=0 provide-clock=false \
   ! audiorate ! audioconvert ! ${AACENC} bitrate=256000 ! queue2 ! mux."
fi

# Launch gstreamer
gst-launch-1.0 -q -e ximagesrc xid="${WID}" do-timestamp=1 use-damage=0 \
 ! video/x-raw,framerate=30/1 ! videoscale method=0 \
 ! video/x-raw,width=${WIDTH},height=${HEIGHT} ! videoconvert \
 ! x264enc speed-preset=veryfast bitrate=${BITRATE} ! queue2 \
 ! mp4mux name="mux" \
 ! filesink location="${HOME}/${FILENAME}" ${MONITORARG} ${MICARG}

echo "Recording done, file is ${FILENAME}"
