Merge branch 'master' of ssh://git.slaskete.net:/srv/git/einar-bin
[einar-bin] / screencast.sh
1 #!/bin/bash
2
3 # WARNING: This is a terribly dirty and messy shellscript, written over a
4 # couple of late nights. There was alcohol …
5 # You probably need to install all the gstreamer-plugins (at least -ugly
6 # and -ffmpeg) as well as gstreamer-tools to get this to work. I wanted to
7 # make mp4 files with x264, I didn't bother with free codecs.
8 #
9 # So this script allows you to create screencasts on Linux, with optional
10 # sound inputs (both Microphone and system sounds). It stores system sounds
11 # and microphone in separate audio streams.
12 #
13 # You also get to choose to record from the whole screen or just a specified
14 # window. It has been tested on Fedora 18, Ubuntu 13.04 and CrunchBang Waldorf
15 # (and thus should work on Debian Wheezy as well).
16 #
17 # If you're using GStreamer 1.0, please jump to the bottom of the script
18 # and comment out the gst-launch-0.10 pipeline and uncomment the 1.0 pipeline.
19 #
20 # It dumps the recording in your $HOME directory with a filename like
21 # screencast-YYYY-MM-DD-HH-MM-SS.mp4
22 #
23 # Written by Einar Jørgen Haraldseid (http://einar.slaskete.net)
24 # License: http://sam.zoy.org/wtfpl/COPYING
25
26 # Get device names and pretty names for enumerating playback sinks:
27 PLAYSINKLIST=$(pacmd list-sinks | \
28 grep -e "name: " -e "device.description = " | cut -d " " -f "2-" | \
29 sed -e "s/name: \|= //g" -e "s/<\|>\|\x22//g")
30
31 # Display playback monitor chooser
32 PLAYMON=$(echo "${PLAYSINKLIST}
33 none
34 Don't capture system sounds" | \
35 zenity --list --title "Choose Output Device" \
36 --text "Choose a sound device to capture system sound from:" \
37 --column "device" --column "Name" --print-column=1 \
38 --hide-column=1 2>/dev/null)
39
40 # Catch cancel
41 if [ -z ${PLAYMON} ]; then
42 echo "No choice made on output device, assuming cancel."
43 exit 1
44 fi
45
46 if [ ${PLAYMON} != "none" ]; then
47 # Unmute monitor of the playback sink (if set):
48 PLAYMON="${PLAYMON}.monitor"
49 pacmd set-source-mute ${PLAYMON} false >/dev/null
50 echo "Recording system sounds from ${PLAYMON}"
51 else
52 echo "Not recording system sounds."
53 fi
54
55 # Get device names and pretty names for microphones:
56 MICLIST=$(pacmd list-sources | \
57 grep -e "name: " -e "device.description = " | \
58 grep -v -i "monitor" | cut -d " " -f "2-" | \
59 sed -e "s/name: \|= //g" -e "s/<\|>\|\x22//g")
60
61 # Display device chooser
62 MIC=$(echo "${MICLIST}
63 none
64 Don't use a microphone" | \
65 zenity --list --title "Choose Microphone" \
66 --text "Choose a microphone to capture voice from:" \
67 --column "device" --column "Name" --print-column=1 \
68 --hide-column=1 2>/dev/null)
69
70 if [ -z ${MIC} ]; then
71 echo "No choice made on microphone, assuming cancel."
72 exit 1
73 fi
74
75 if [ ${MIC} != "none" ]; then
76 echo "Recording voice from ${MIC}"
77 else
78 echo "Not recording voice."
79 fi
80
81 # Get target window for recording:
82 TARGET=$(echo "root
83 Whole screen
84 window
85 Specific window" | \
86 zenity --list --title "Choose recording mode" \
87 --text "Do you want to record the whole screen,\
88 or record a specific window?" --column "target" \
89 --column "Mode" --print-column=1 --hide-column=1 2>/dev/null)
90
91 if [ -z ${TARGET} ]; then
92 echo "No choice for recording target, assuming cancel."
93 exit 1
94 fi
95
96 if [ ${TARGET} = "root" ]; then
97 echo "Root window chosen."
98 XWININFO=$(xwininfo -root)
99 else
100 echo "Custom window chosen."
101 XWININFO=$(xwininfo)
102 fi
103
104 # Get Window ID and dimensions, make sure X and Y dimensions are
105 # divisible by two, or else the encoder will fail
106 WID=$(echo "${XWININFO}" | grep "Window id:" | awk '{print $4}')
107 WIDTH=$(echo "${XWININFO}" | grep "Width: " | \
108 cut -d ":" -f 2 | awk '{print $1+$1%2}')
109 HEIGHT=$(echo "${XWININFO}" | grep "Height: " | \
110 cut -d ":" -f 2 | awk '{print $1+$1%2}')
111
112 # Calculate a suitable bitrate based on window dimensions
113 BITRATE=$(echo "${WIDTH} * ${HEIGHT} * 0.0075" | bc | cut -d "." -f 1 )
114
115 # Set file name.
116 FILENAME="screencast-$(date +%F-%H-%M-%S).mp4"
117
118 # Enable inputs as suitable
119 if [ ${PLAYMON} != "none" ]; then
120 MONITORARG="pulsesrc device=${PLAYMON} slave-method=0 provide-clock=false \
121 ! audiorate ! audioconvert ! ffenc_aac bitrate=256000 ! queue2 ! mux."
122 fi
123 if [ ${MIC} != "none" ]; then
124 MICARG="pulsesrc device=${MIC} slave-method=0 provide-clock=false \
125 ! audiorate ! audioconvert ! ffenc_aac bitrate=256000 ! queue2 ! mux."
126 fi
127
128 # Launch gstreamer (Using gstreamer 0.10)
129 gst-launch-0.10 -q -e ximagesrc xid="${WID}" do-timestamp=1 use-damage=0 \
130 ! video/x-raw-rgb,framerate=30/1 ! ffmpegcolorspace ! videoscale method=0 \
131 ! video/x-raw-yuv,width=${WIDTH},height=${HEIGHT} \
132 ! x264enc speed-preset=veryfast bitrate=${BITRATE} ! queue2 \
133 ! mp4mux name="mux" \
134 ! filesink location="${HOME}/${FILENAME}" ${MONITORARG} ${MICARG}
135
136 # Launch gstreamer (Using gstreamer 1.0)
137 #gst-launch-1.0 -q -e ximagesrc xid="${WID}" do-timestamp=1 use-damage=0 \
138 # ! video/x-raw,framerate=30/1 ! videoscale method=0 \
139 # ! video/x-raw,width=${WIDTH},height=${HEIGHT} ! videoconvert \
140 # ! x264enc speed-preset=veryfast bitrate=${BITRATE} ! queue2 \
141 # ! filesink location="${HOME}/${FILENAME}" ${MONITORARG} ${MICARG}
142
143 echo "Recording done, file is ${FILENAME}"