-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathffmpeg-dump
executable file
·232 lines (218 loc) · 9.17 KB
/
ffmpeg-dump
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
#! /usr/bin/env ksh93
# A full screen or individual window screenshot tool using ffmpeg's x11grab.
# usage:
# -f: screenshot of entire screen
# -b: include borders of selected window (default: no decorations)
# Get more details on usage from running the program with '-h' or '--help'.
# Requires `xwininfo`, `xprop`, `ffmpeg`, `sed`, `cut`, and `grep`.
# `xdotool` is an optional dependency, but recommended.
# The first two are installed in the 'x11-utils' package on Debian and similar.
# I think it should work with bash as well as to ksh93 (which I wrote it for);
# to try it, replace the '#! /usr/bin/env ksh93' at the top with '#! /bin/bash'
# for instance. I think for POSIX shell (/bin/sh) to work I'd have to rewrite
# the $(( )) math operations to use 'expr' or 'bc' instead.
# It can optionally use `xdotool` to try to give focus screenshotted window;
# presently, this is just done automatically if xdotool is detected on the
# system, but if it bothers anyone I'd be happy to make it a configuration
# option or run-time flag.
help_text() {
echo "$0"
echo "A full screen or individual-window screenshot tool using ffmpeg/x11grab."
echo "Usage:"
echo "$(basename "$0")"' [OPTIONS] OUTPUT-DIR [FILENAME]'
echo "If FILENAME is not specified, then the screenshot will be saved in"
echo 'OUTPUT-DIR and given a name in the format:'
echo '"Screenshot at YYYY-MM-DD HH-MM-DD.png".'
echo "Unless otherwise requested, default behavior is to allow the user to click"
echo "the window to be screenshotted. Other modes of operation are described below."
echo ""
echo "OPTIONS:"
echo "-b, --borders Include window borders (decorations) in a window screenshot"
echo " (can be used alongside -w or on its own)."
echo " Default: don't include window borders/decorations."
echo "-d, --decorations Synonyms for -b."
echo "-f, --fullscreen Take screenshot of the entire screen instead of one window."
echo "-h, --help Show this message and exit."
echo "-m, --show-cursor Show mouse pointer in screenshot (default: hide pointer)."
echo "-t, --timer [int] Wait [int] seconds before capturing."
echo "-w, --window Take a screenshot of only one window selected by integer"
echo " window ID."
}
wininfoattr()
{
# $1 is window id
# $2 is attribute to get
xwininfo -id "$1" | grep "$2" | sed 's/.*\: *//'
}
unalias grep 2>/dev/null
unalias ffmpeg 2>/dev/null
unalias xwininfo 2>/dev/null
FULL_SCR=0
WIN_ID=0
WIDTH=0
HEIGHT=0
RESOLUTION=""
INCLUDE_BORDERS=0
DELAY_TIME=0
PARSING=1
SHOW_CURSOR=0
if [ "$#" -eq 0 ]; then
1>&2 echo "Error: no arguments given."
1>&2 help_text
exit 1
fi
while [[ $PARSING -eq 1 ]]; do
case "$1" in
'-b' | '--borders' | '-d' | '--decorations')
INCLUDE_BORDERS=1
shift
;;
'-t' | '--timer' | '--delay' )
if [[ "$#" -gt 1 ]]; then
DELAY_TIME="$2"
shift 2
else
# bug: actually check if a number was passed, since this error message
# will NOT be generated if timer is not the last argument and
# no delay will be used.
1>&2 echo "Error: No time was specified for timer. Exiting."
exit 1
fi
;;
'-f' | '--full' | '--fullscreen' )
FULL_SCR=1
if [ "$DELAY_TIME" -eq 0 ]; then
DELAY_TIME=1
fi
shift
;;
'-m' | '--show-cursor')
SHOW_CURSOR=1
shift
;;
'-w' | '--window')
shift
WIN_ID="$1"
shift
;;
'-h' | '--help')
help_text
exit 0
;;
*)
PARSING=0
;;
esac
done
if [[ "$FULL_SCR" -eq 1 ]]; then
WIN_ID=`xwininfo -root -int|grep Window\ id|sed 's/.*Window id\: //;s/ .*//'`
RESOLUTION=`xwininfo -id "$WIN_ID" | grep geometry | sed 's/^.*geometry *//;s/+.*//;s/-.*//'`
X_CORNER=0
Y_CORNER=0
else
# click to select window
# geometry is unreliable for e.g. terminal windows, so use width and height
# instead, which are guaranteed pixels i think.
# WIN_ID=`xdotool getwindowfocus`
# xwininfo comes in x11-utils, so the xdotool dependency can be avoided if
# we use it instead.
if [[ "$WIN_ID" -eq 0 ]]; then # can be set by -w at run-time
WIN_ID=`xwininfo -int|grep Window\ id|sed 's/.*Window id\: //;s/ .*//'`
fi
if [[ "$INCLUDE_BORDERS" -ne 1 ]]; then
WIDTH=`wininfoattr "$WIN_ID" 'Width'`
HEIGHT=`wininfoattr "$WIN_ID" 'Height'`
X_CORNER=`wininfoattr "$WIN_ID" 'Absolute upper-left X'`
Y_CORNER=`wininfoattr "$WIN_ID" 'Absolute upper-left Y'`
BORDER_WIDTH_LEFT=0
BORDER_WIDTH_RIGHT=0
BORDER_HEIGHT_TOP=0
BORDER_HEIGHT_BOTTOM=0
else
# check if we have xdotool for a little bonus feature (in my opinion)
2>/dev/null type xdotool > /dev/null
if [[ "$?" -eq 0 ]]; then
# If we have xdotool, we can use it to set the active window focus.
# if we don't have xdotool, don't worry about it; it's not too important.
# Basically, though, since the GUI wrapper tool I wrote for this script
# will steal the input focus, we can just do this in order to try to
# return it to the window we were using afterwards without requiring any
# further user actions.
# Note that this might not pop the window to the topmost level; it just
# returns keyboard focus and stuff.
xdotool windowfocus "$WIN_ID"
fi
# Factor in window decorations.
# Thanks to stack overflow for the xprop command, I wasn't able to find
# out any other ways to get decoration info. (X protocol limitations, yay)
EXTENTS="$(xprop _NET_FRAME_EXTENTS -id "$WIN_ID")"
# BORDER_WIDTH_LEFT="$(echo $EXTENTS | sed 's/.* = //;s/,.*//')"
# BORDER_WIDTH_RIGHT="$()"
BORDER_WIDTH_LEFT="$(echo $EXTENTS | cut -d ',' -f 1 | sed 's/.*= *//')" # width of left border
BORDER_WIDTH_RIGHT="$(echo $EXTENTS | cut -d ',' -f 2 | sed 's/ *//')" # width of right border
BORDER_HEIGHT_TOP="$(echo $EXTENTS | cut -d ',' -f 3 | sed 's/ *//')" # height of title bar
BORDER_HEIGHT_BOTTOM="$(echo $EXTENTS | cut -d ',' -f 4 | sed 's/ *//')" # height of bottom border
WIDTH=$((`wininfoattr "$WIN_ID" 'Width'`+"$BORDER_WIDTH_RIGHT"+"$BORDER_WIDTH_LEFT"))
X_CORNER=$((`wininfoattr "$WIN_ID" 'Absolute upper-left X'`-"$BORDER_WIDTH_LEFT"))
HEIGHT=$((`wininfoattr "$WIN_ID" 'Height'`+"$BORDER_HEIGHT_BOTTOM"+"$BORDER_HEIGHT_TOP"))
Y_CORNER=$((`wininfoattr "$WIN_ID" 'Absolute upper-left Y'`-"$BORDER_HEIGHT_TOP"))
fi
SCREEN_HEIGHT=`xwininfo -root -int | grep Height | sed 's/.*\: *//'`
SCREEN_WIDTH=`xwininfo -root -int | grep Width | sed 's/.*\: *//'`
# catch things that would make x11grab fail, like off-screen window corners.
# to correct anything off the top or the left, adjust CORNER variables.
# to correct anything off the bottom or the right, adjust WIDTH or HEIGHT.
# window goes off left side of screen
if [[ "$X_CORNER" -lt 0 ]]; then
WIDTH=$(("$WIDTH"+"$X_CORNER")) # subtract unseen area from total width.
X_CORNER=0
fi
# window goes off top of screen
if [[ "$Y_CORNER" -lt 0 ]]; then
HEIGHT=$(("$HEIGHT"+"$Y_CORNER")) # subtract unseen area from total height.
Y_CORNER=0
fi
# window goes off right of screen
if [[ $(("$WIDTH"+"$X_CORNER")) -gt "$SCREEN_WIDTH" ]]; then
WIDTH=$(("$SCREEN_WIDTH"-"$X_CORNER"))
fi
# window goes off bottom of screen
if [[ $(("$HEIGHT"+"$Y_CORNER")) -gt "$SCREEN_HEIGHT" ]]; then
HEIGHT=$(("$SCREEN_HEIGHT"-"$Y_CORNER"))
fi
RESOLUTION="$WIDTH"'x'"$HEIGHT"
fi
dograb()
{
# args: [destination-dir] [filename]
# ffmpeg command dissected
# -loglevel warning Don't print anything except warnings/errors.
# -video_size Tell ffmpeg x11grab the size of the area to grab.
# -f x11grab Use x11grab for video capture
# -draw_mouse 0 Prevent x11grab from drawing the cursor over the
# screenshot
# -i Input (X11 display and corner information)
# -frames:v 1 Only write a single frame (since this isn't a video).
# -s Set output frame size
# -f image2 Force 'image2' output format. IIRC, 'image' is a
# long-obsolete format.
# -y Overwrite (assume 'yes' to questions).
# $1 Pass output file name argument
if [[ "$#" -ge 2 ]]; then
FILENAME="$1""/""$2"
else
FILENAME="$1""/""$(date +'Screenshot at %Y-%m-%d %H-%M-%S')"".png"
fi
echo PARAMS: "$@"
# ffmpeg -loglevel warning -video_size "$RESOLUTION" -f x11grab $MOUSEPARAM_A $MOUSEPARAM_B -i "$DISPLAY"'+'"$X_CORNER"','"$Y_CORNER" -frames:v 1 -s "$RESOLUTION" -f image2 -y "$FILENAME"
# imagemagick convert seems to give better compression. we output uncompressed png from ffmpeg using -compression_level 0 and then let imagemagick do all the heavy lifting.
ffmpeg -loglevel warning -video_size "$RESOLUTION" -f x11grab -draw_mouse "$SHOW_CURSOR" -i "$DISPLAY"'+'"$X_CORNER"','"$Y_CORNER" -frames:v 1 -s "$RESOLUTION" -f image2 -compression_level 0 -vcodec png - | convert png:- "$FILENAME"
echo 'Image saved as '"$FILENAME"'.'
exit
}
if [[ "$DELAY_TIME" -gt 0 ]]; then
# not necessary to have behind the 'if' gate, necessarily, but this might
# actually improve speed by avoiding fetching a program from the disk.
sleep "$DELAY_TIME"
fi
dograb "$@"