Du screencast sous GNU/Linux partie 4

Le script screencaster.sh final qui semble fonctionner sur toute Buntu et dérivée, pour peu que l’on se conforme aux notes :

#!/bin/bash
#
# screencaster.sh - script to make screencasts on Linux 
#
# For information about using this script:
# http://okiebuntu.homelinux.com/blog/?p=175
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE.  See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program.  If not, see <http://www.gnu.org/licenses/>.
# Nécessite libavcodec-extra-52
# Il faut peut-être ffmpeg depuis le dépôt Medibuntu. Il faudra aussi ajouter un peu de code pour faire en sorte que la taille et l'offset soit divisible par deux
# parec a besoin d'un monitor pour fonctionner : trouver un input avec pactl list | egrep -A2 '^(\*\*\* )?Source #'
# On peut arrêter l'enregistrement en configurant un raccourci clavier et en utilisant xdotool : xdotool search --onlyvisible --classname "gnome-terminal" key "Return"
#

# Config
monitor="alsa_output.pci-0000_00_1b.0.analog-stereo.monitor"
echo "set-source-mute ${monitor} false" | pacmd >/dev/null
threads=2
volume=0.25

# list of programs we depend on
progs="xdpyinfo grep head sed ffmpeg pacat parec sox libavcodec-extra-52"

# check for programs we depend on
result=0
for prog in $progs
do
  type -p $prog > /dev/null
  if (( $? != 0 )); then
    echo "Error: Cannot find required program '$prog'"
    result=1
  fi
done
if (( $result != 0 )); then
  exit 1
fi

screenSize="$(xwininfo -root | grep 'geometry' | awk '{print $2;}')" # default if we cant detect it
screenOffset="0,0" # default to top-left corner
frameRate="24" # default frame rate
baseName="`date +%Y%m%d`-`date +%H%M%S`-screencast" # default base filename for capture

# attempt to detect the dimension of the screen for the default
dimensions=`xdpyinfo | grep 'dimensions:' | head -1 | \
  sed -e 's/^.* \([0-9]\+x[0-9]\+\) pixels.*$/\1/'`
if [[ "$dimensions" =~ [0-9]+x[0-9]+ ]]; then
  screenSize=$dimensions
fi

# collect command line settings
while getopts 'hs:o:t:r:p:w' param ; do
  case $param in
    s)
      screenSize="$OPTARG"
      ;;
    o)
      screenOffset="$OPTARG"
      ;;
    t)
      timeToRecord="$OPTARG"
      ;;
    w)
      INFO=$(xwininfo)
      WIN_GEO=$(echo $INFO | grep -oEe 'geometry [0-9]+x[0-9]+' | grep -oEe '[0-9]+x[0-9]+')
      WIN_XY=$(echo $INFO | grep -oEe 'Corners:\s+\+[0-9]+\+[0-9]+' | grep -oEe '[0-9]+\+[0-9]+' | sed -e 's/\+/,/' )
      screenOffset="$WIN_XY"
      screenSize="$WIN_GEO"
      ;;
    r)
      frameRate="$OPTARG"
      ;;
    *)
      echo ""
      echo "$0 - records screencast"
      echo ""
      echo "$0 [options] [base-filename]"
      echo ""
      echo "options:"
      echo "    -h            show brief help"
      echo "    -s <size>     screensize to record as <width>x<height>"
      echo "    -o <offset>   offset off recording area as <xoffset>,<yoffset>"
      echo "    -t <time>     time to record (in seconds)"
      echo "    -w        window to record"
      echo "    -r        framerate (FPS)"
      echo ""
      exit 0
      ;;
  esac
done

shift $(( $OPTIND - 1 ))

# determine basename of files
if [ -n "$1" ] ; then
  baseName="$1"
fi

echo ""
echo "Size = $screenSize"
echo "Offset = $screenOffset"
echo "Rate = $frameRate"
echo "Filename = $baseName"

# get ready to start recording
echo ""
if [ -n "$timeToRecord" ]; then
  echo "Preparing to capture for $timeToRecord seconds."
else
  echo "Preparing to capture."
  echo "Press ENTER when finished capturing."
fi
sleep 3
echo ""

# start playing silence to make sure there is always audio flowing
pacat /dev/zero &
pidSilence=$!

# starts recording video using x11grab to make mpeg2video
ffmpeg -f alsa -ac 2 -i pulse \
       -f x11grab -r "$frameRate" -s "$screenSize" -i :0.0+"$screenOffset" \
       -acodec pcm_s16le -vcodec libx264 -vpre lossless_ultrafast \
       -threads "$threads" -y "$baseName.avi" &
pidVideo=$!

#ffmpeg -y -an \
#  -s "$screenSize" -r "$frameRate" -f x11grab -i :0.0+"$screenOffset" \
#  -s "$screenSize" -r "$frameRate" -aspect 4:3 -vcodec mpeg2video -sameq \
#  -f mpeg2video "$baseName.mpeg" &
#pidVideo=$!

# starts recording raw audio from output
parec -d "$monitor" --format=s16le --rate=44100 --channels=2 "$baseName-audio.raw" &
pidAudio=$!

# starts recording raw audio from input
rec -b 32 -r 44100 "$baseName-voice.wav" &
pidMicro=$!

echo ""
echo "Video recording started with process ID $pidVideo"
echo "Audio recording started with process ID $pidAudio"
echo "Voice recording started with process ID $pidMicro"
echo ""

# wait for recording to be done, either by timer or user hitting enter
if [ -n "$timeToRecord" ]; then
  sleep "$timeToRecord"
else
  read nothing
fi

# stop recordings
echo ""
echo "Terminating recordings ..."
kill -15 $pidVideo $pidAudio 
kill -15 $pidSilence
kill -15 $pidMicro
wait

# filter and normalize the audio
echo "" 
echo "Filtering and normalizing sound ..." 
sox --norm -s -b 16 -L -r 44100 -c 2 -v "$volume" "$baseName-audio.raw" "$baseName-audio.wav"  highpass 65 lowpass 12k
sox -v "$volume" "$baseName-audio.wav" "$baseName-audio2.wav"
sox --norm -s -b 32 -L -r 44100 -c 2 -v 2.0 "$baseName-voice.wav" "$baseName-voice2.wav"  highpass 65 lowpass 12k

# Récupère le son du microphone
#echo ""
#echo "Extract audio from avi"
#ffmpeg -i "$baseName.avi" -ar 44100 -ac 2 "$baseName-2.wav"

# encode video and audio into mp4 file
echo "" 
echo "Encoding to final Youtube format..." 
sox "$baseName-audio2.wav" "$baseName-voice2.wav" -m "$baseName-final.wav"

ffmpeg -i "$baseName-final.wav" -acodec libfaac -ab 320k -y "$baseName-final.aac"

ffmpeg -i "$baseName.avi" -an -s 1280x720 -aspect 16:9 -acodec libfaac -ab 320k -vcodec libx264 -vpre fast -crf 18 -threads "$threads" -y "$baseName.mp4"

ffmpeg -isync -i "$baseName-final.aac" -i "$baseName.mp4" -s 1280x720 -aspect 16:9 -acodec libfaac -ab 320k -vcodec libx264 -vpre fast -crf 18 -threads "$threads" -y  "$baseName-final.mp4" 

#ffmpeg -isync -i "$baseName.wav" -i "$baseName.mpeg" -acodec mp2 -ab 192k -vcodec copy "$baseName.avi"

# convert to ogg - to turn on uncomment next three lines
#echo""
#echo "convert to theora"
#ffmpeg2theora "$baseName.avi" -o "$baseName.ogv"

# convert avi to flv - to turn on uncomment next three lines
#echo""
#echo "convert to theora"
# ffmpeg -i "$baseNamee.avi" -ab 56 -ar 44100 -b 200 -r 15 -s 320x240 -f flv  "$baseNamee.flv"

echo ""
echo "DONE! Final media written in file $baseName.mp4"

echo ""
exit 0

Voilà, prochaine étape : un peu de python pour donner une interface simple. À noter que sous Gnome 3, un outil de screencast est incorporé d’office, via un raccourci-clavier dont personne ne se souvient, et qui n’est pas paramétrable ; il prend tout l’écran. Ma solution permet au moins de lancer un screencast à distance, selon des paramètres (30 fps pour une vidéo en HD, c’est un must ), et surtout de choisir une fenêtre d’un simple clic.