#!/bin/sh # # gst-screencast - screencasting of a window using GStreamer # # 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 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 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 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$1" ]; then SHADOW_SIZE=0 SHADOW_X_OFFSET=0 SHADOW_Y_OFFSET=0 if [ $WINDOW_FRAME -eq 1 ]; then XWININFO_OPTIONS="-frame" # 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 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") 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="$@" fi 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 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