X-Git-Url: https://git.ao2.it/experiments/gstreamer.git/blobdiff_plain/6c1422aa535441bb8f00227dec3f7812c5edf99e..d770cdb54f40ecd58f411e8d185228bac4d3c10f:/shell/gst-screencast.sh?ds=inline diff --git a/shell/gst-screencast.sh b/shell/gst-screencast.sh index 1902f49..dd4cd88 100755 --- a/shell/gst-screencast.sh +++ b/shell/gst-screencast.sh @@ -1,52 +1,142 @@ #!/bin/sh - +# # gst-screencast - screencasting of a window using GStreamer # -# Copyright (C) 2015 Antonio Ospite +# Copyright (C) 2015-2017 Antonio Ospite +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. # -# This program is free software. It comes without any warranty, to -# the extent permitted by applicable law. You can redistribute it -# and/or modify it under the terms of the Do What The Fuck You Want -# To Public License, Version 2, as published by Sam Hocevar. See -# http://sam.zoy.org/wtfpl/COPYING for more details. +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY 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 . set -e -set -x -[ "x" = "x$1" ] && { echo "usage: $(basename $0) []" 1>&2; exit 1; } +usage() { + cat < [] + +Screencast script based on GStreamer. + +Options: + --audio record audio from pulsesrc + --frame include the window manager border, without the shadows + --pointer capture the mouse pointer + --single-shot capture a single snapshot as a PNG instead of a video + -h, --help display this usage message and exit -[ -f "$1" ] && { echo "ERROR: file already exists!" 1>&2; exit 2; } +EOF +} + +CAPTURE_AUDIO=0 +WINDOW_FRAME=0 +SHOW_POINTER=0 +SINGLE_SHOT=0 + +while [ $# -gt 0 ]; +do + case "$1" in + -h|--help) + usage + exit 0 + ;; + --audio) + CAPTURE_AUDIO=1 + ;; + --frame) + WINDOW_FRAME=1 + ;; + --pointer) + SHOW_POINTER=1 + ;; + --single-shot) + SINGLE_SHOT=1 + ;; + -*) + echo "Error: Unknown option '${1}'" 1>&2 + ;; + *) + break; + esac + shift +done + +[ "x" = "x$1" ] && { usage 1>&2; exit 1; } + +[ -f "$1" ] && { echo "Error: file '${1}' already exists!" 1>&2; exit 2; } FILENAME="$1" +shift -if [ "x" = "x$2" ]; +if [ "x" = "x$1" ]; then - # uncomment to capure the whole frame with window manager border and decorations - XWININFO_OPTIONS="-frame" + SHADOW_SIZE=0 + SHADOW_X_OFFSET=0 + SHADOW_Y_OFFSET=0 + if [ $WINDOW_FRAME -eq 1 ]; + then + XWININFO_OPTIONS="-frame" - WIN_INFO="$(xwininfo $XWININFO_OPTIONS)" + # XXX the values below are still hardcoded, they may be different + # depending on the theme and the window manager. + SHADOW_SIZE=26 + SHADOW_X_OFFSET=0 + SHADOW_Y_OFFSET=3 + fi - #XID=$(echo "$WIN_INFO" | grep "Window id" | cut -d ' ' -f 4) - #XIMAGESRC_ARGS="xid=$XID" + WIN_INFO="$(xwininfo $XWININFO_OPTIONS)" X=$(echo "$WIN_INFO" | sed -n -e "/^[[:space:]]*Absolute upper-left X:[[:space:]]*/s///p") Y=$(echo "$WIN_INFO" | sed -n -e "/^[[:space:]]*Absolute upper-left Y:[[:space:]]*/s///p") WIDTH=$(echo "$WIN_INFO" | sed -n -e "/^[[:space:]]*Width:[[:space:]]*/s///p") HEIGHT=$(echo "$WIN_INFO" | sed -n -e "/^[[:space:]]*Height:[[:space:]]*/s///p") - BORDER_SIZE=27 - XIMAGESRC_ARGS="startx=$(($X - $BORDER_SIZE)) starty=$(($Y - $BORDER_SIZE)) endx=$(($X + $WIDTH + $BORDER_SIZE)) endy=$(($Y + $HEIGHT + $BORDER_SIZE))" - - XIMAGESRC_ARGS="startx=$(($X - $BORDER_SIZE - 1)) starty=$(($Y - $BORDER_SIZE - 7)) endx=$(($X + $WIDTH + $BORDER_SIZE)) endy=$(($Y + $HEIGHT + $BORDER_SIZE + 7))" + XIMAGESRC_ARGS="startx=$(($X + $SHADOW_SIZE - $SHADOW_X_OFFSET)) starty=$(($Y + $SHADOW_SIZE - $SHADOW_Y_OFFSET)) endx=$(($X + $WIDTH - 1 - $SHADOW_SIZE - $SHADOW_X_OFFSET)) endy=$(($Y + $HEIGHT - 1 - $SHADOW_SIZE - $SHADOW_Y_OFFSET))" else - XIMAGESRC_ARGS="$2" + XIMAGESRC_ARGS="$@" fi -VIDEO_CODEC="video/x-raw,format=I420 ! jpegenc quality=90" -#VIDEO_CODEC="openjpegenc" +if [ $SINGLE_SHOT -eq 1 ]; +then + gst-launch-1.0 -v \ + ximagesrc use-damage=0 show-pointer=$SHOW_POINTER $XIMAGESRC_ARGS num-buffers=1 ! \ + videoconvert ! pngenc ! filesink location="$FILENAME" +else + VIDEO_CODEC="video/x-raw,format=I420 ! jpegenc quality=90" + + if [ $CAPTURE_AUDIO -eq 1 ]; + then + # Record from everything + if ! pactl list short sinks | grep -q module-null-sink; + then -gst-launch-1.0 -v \ - ximagesrc use-damage=0 show-pointer=0 $XIMAGESRC_ARGS ! video/x-raw,framerate=25/1 ! \ - videoconvert ! videorate ! $VIDEO_CODEC ! queue ! mux. \ - matroskamux name=mux ! filesink location="$FILENAME" - #pulsesrc ! audioconvert ! 'audio/x-raw,rate=44100,channels=2' ! queue ! mux. \ + PA_IDS=$(pactl load-module module-null-sink) + trap 'exit 1' INT + trap 'trap INT; for pa_id in $PA_IDS; do pactl unload-module "$pa_id"; done' EXIT + + SOURCES=$(pactl list short sources | cut -f 2 | grep -v "^null\.monitor$") + for source in $SOURCES; + do + MODULE_ID=$(pactl load-module module-loopback latency_msec=1 source="$source" sink=null) + PA_IDS="$MODULE_ID $PA_IDS" + done + + pactl set-sink-mute null 0 + fi + + AUDIO_PIPELINE="pulsesrc device=null.monitor ! audioconvert ! audio/x-raw,rate=44100,channels=2 ! vorbisenc ! queue ! mux." + fi + + gst-launch-1.0 -v -e \ + matroskamux name=mux ! filesink location="$FILENAME" \ + ximagesrc use-damage=0 show-pointer=$SHOW_POINTER $XIMAGESRC_ARGS ! video/x-raw,framerate=25/1 ! \ + videoconvert ! videorate ! $VIDEO_CODEC ! queue ! mux. \ + $AUDIO_PIPELINE +fi