A few months ago, I wrote a post on how to do a picture-in-picture timelapse recording when dealing with a dual monitor setup where each monitor has its own separate X display.
Long story short, after a harddrive failure forcing me to reconfigure my linux setup, I went away from the dual X screen setup, to a single X display spanning the two montiors.
This means that a screen dump using
I'll keep this post short with only the script and a
demo recording (a timelapse made while writing this post).
For an explanation of the
Putting together the various pieces mentioned so far, this is the final script.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | #!/bin/bash # Setup: #################### # Automatic setup detection using xrandr xrandrOutput= `xrandr --query` leftGeometry=` echo "$xrandrOutput" | grep -P "\sconnected" \ | grep -oP '\d+x\d+\+0\+\d+' ` rightGeometry=` echo "$xrandrOutput" | grep -P "\sconnected" \ | grep -oP '\d+x\d+\+\d{2,}\+\d+' ` primaryGeomtry=` echo "$xrandrOutput" | grep -P "\sconnected primary" \ | grep -oP '\d+x\d+\+\d+\+\d+' ` if [[ "$primaryGeomtry" == "$leftGeometry" ]] ; then mainMonitor=left elif [[ "$primaryGeomtry" == "$rightGeometry" ]] ; then mainMonitor=right else echo "Failed to detect main monitor" fi leftMonitor= ${leftGeometry%%+*} rightMonitor= ${rightGeometry%%+*} pipSize=340x340 pipOffset=+30+20 # Implicit variables leftMonitorWidth= ${leftMonitor%x*} echo "leftMonitor: " $leftMonitor echo "rightMonitor: " $rightMonitor echo "pipSize: " $pipSize echo "pipOffset: " $pipOffset echo "mainMonitor: " $mainMonitor ######################## if [[ ! "$mainMonitor" == "left" ]] && \ [[ ! "$mainMonitor" == "right" ]] ; then echo "Bad mainMonitor variable" exit fi if [ ! $# - eq 2 ] ; then echo "Usage: ./recordscreen delay outputfolder" exit fi if [ ! -d $outputFolder ] ; then echo "Output folder does not exist" exit fi gsettings set org.gnome.desktop.sound event-sounds false # $1:output function captureScreenDump { xwd -root -out $1 } # $1:input-file $2:output-file function prepareThumbnail { if [[ "$mainMonitor" == "left" ]] ; then geometry= ${rightMonitor} + ${leftMonitorWidth} +0 else geometry= ${leftMonitor} +0+0 fi convert $1 -crop $geometry -thumbnail $pipSize \ -bordercolor "#881111aa" -border 2 \ \( +clone -background black -shadow 100x3+2+2 \) \ +swap -background none -layers merge +repage $2 } # $1:captured-image $2:pip-thumbnail $3:output-frame function prepareFinalFrame { geometry= if [[ "$mainMonitor" == "left" ]] ; then geometry= ${leftMonitor} +0+0 else geometry= ${rightMonitor} + ${leftMonitorWidth} +0 fi convert -crop $geometry ${1} ${1} .tmp.xwd convert -composite ${1} .tmp.xwd $2 -gravity SouthEast \ -geometry $pipOffset $3 rm ${1} .tmp.xwd } # $1:counter $2:folderOuput function doFrameCapture { # Filenames for capture and right screen outfile= `printf '%.5d' $1`-`date +"%Y-%m-%d-%s"` capture= ${2} /capture/ ${outfile} pip= ${2} /pip/ ${outfile} # Capture both screens at the same time captureScreenDump $capture .xwd prepareThumbnail $capture .xwd $pip .png # Create final frame from left frame and thumbnail of right frame outfileFinal= ${2} /frames/ `printf '%.5d' $1` prepareFinalFrame ${capture} .xwd ${pip} .png ${outfileFinal} .png # Cleanup: rm -f $capture .xwd $pip .png } function finalize() { rm -f $outputFolder /{capture,pip}/* rmdir $outputFolder /{capture,pip} gsettings set org.gnome.desktop.sound event-sounds true exit } trap finalize SIGINT SIGTERM ################### PROGRAM CODE STARTS ################### delay= $1 outputFolder= $2 curr=0 if [ -e $outputFolder /frames ] ; then lastFrame= `ls -1 $outputFolder/frames/ | tail -n 1` curr= `echo ${lastFrame%.*} | sed 's/^0*//'` while true ; do read -p "Recording in progress (currently $curr frames) Do you wish to continue at frame " $((curr+1)) "? [y/n] " yn case $yn in [Yy]* ) break ;; [Nn]* ) exit ;; * ) echo "Please answer yes or no." ;; esac done fi if [ ! -e $outputFolder /capture ] ; then mkdir $outputFolder /capture ; fi if [ ! -e $outputFolder /pip ] ; then mkdir $outputFolder /pip ; fi if [ ! -e $outputFolder /frames ] ; then mkdir $outputFolder /frames ; fi while sleep $delay ; do ((curr++)) (doFrameCapture $curr $outputFolder &) done #################### ----------------- #################### |
If the above script for some reason skips a frame, this will cause problems when creating a video from them. A quick fix is to create a symlink to the previous file, for any missing frame.
1 2 3 4 5 6 7 8 9 10 11 12 13 | #!/bin/bash lastFrame= `ls -1 frames/ | tail -n 1` nframes= `echo ${lastFrame%.*} | sed 's/^0*//'` for i in $( seq 1 1 $nframes ) do curr= `printf '%.5d.png' $i` prev= `printf '%.5d.png' $((i-1))` if [ ! -e frames/ $curr ] ; then echo "$prev -> $curr" ln -s $prev frames/ $curr fi done |
A
1 2 | ffmpeg -r 15 -i frames/%05d.png -c: v \ libx264 -r 30 -pix_fmt yuv420p timelapsevideo.mp4 |
While I wrote this post, I had the screen recording script running, and this is the produced video: