Blame


1 2153543f 2020-12-12 op 2020/12/12 edit: typos.
2 2153543f 2020-12-12 op
3 db5b749f 2020-12-09 op Today I chatted with a friend about screen recording. He had a problem with a the record script he was using, and this made me thinking about how I record the screen.
4 db5b749f 2020-12-09 op
5 db5b749f 2020-12-09 op I find useful to share some little screen records, to showcase something I'm doing with friends usually. Some time ago I quickly wrote a small record script:
6 db5b749f 2020-12-09 op
7 db5b749f 2020-12-09 op ``` sh
8 db5b749f 2020-12-09 op #!/bin/ksh
9 db5b749f 2020-12-09 op
10 db5b749f 2020-12-09 op if ! s=$(slop -f "%x %y %w %h"); then
11 db5b749f 2020-12-09 op exit 1
12 db5b749f 2020-12-09 op fi
13 db5b749f 2020-12-09 op
14 db5b749f 2020-12-09 op set -A s -- $s
15 db5b749f 2020-12-09 op
16 db5b749f 2020-12-09 op x=${s[0]}
17 db5b749f 2020-12-09 op y=${s[1]}
18 db5b749f 2020-12-09 op w=${s[2]}
19 db5b749f 2020-12-09 op h=${s[3]}
20 db5b749f 2020-12-09 op
21 db5b749f 2020-12-09 op exec ffmpeg -y \
22 db5b749f 2020-12-09 op -f x11grab \
23 db5b749f 2020-12-09 op -s ${w}x${h} \
24 db5b749f 2020-12-09 op -framerate 30 \
25 db5b749f 2020-12-09 op -i $DISPLAY+${x},${y} \
26 db5b749f 2020-12-09 op ${1:?missing output file}
27 db5b749f 2020-12-09 op ```
28 db5b749f 2020-12-09 op
29 db5b749f 2020-12-09 op Frankly, it's ugly. But was quickly to write, it worked, and I had better things to do than improve it.
30 db5b749f 2020-12-09 op
31 2153543f 2020-12-12 op The drawback is the need to keep an xterm open while recording. So why don't integrate this into my window manager?
32 db5b749f 2020-12-09 op
33 2153543f 2020-12-12 op I'm using stumpwm: it's a window manager written in common lisp. Being written in lisp, it's exceptionally good at interactive development. And trust me, having a REPL connected to your window manager is really cool at times like this. Being able to fire up Emacs, connect it to the window manager, drafting functions and commands and refining them into something that works, all without interruptions (reload the window manager, restart the thing, recompile stuff...) is pretty cool, not gonna lie.
34 db5b749f 2020-12-09 op
35 db5b749f 2020-12-09 op So, without further ado, here's the snippet in all its glory:
36 db5b749f 2020-12-09 op
37 db5b749f 2020-12-09 op ``` common-lisp
38 db5b749f 2020-12-09 op (defparameter *my/record-process* nil
39 db5b749f 2020-12-09 op "Holds the record process if its running, nil otherwise.")
40 db5b749f 2020-12-09 op
41 db5b749f 2020-12-09 op (defun my/select-area ()
42 db5b749f 2020-12-09 op "Select an area using slop, returning (x, y, w, h) or nil."
43 db5b749f 2020-12-09 op (ignore-errors
44 db5b749f 2020-12-09 op (mapcar #'parse-integer
45 db5b749f 2020-12-09 op (cl-ppcre:split " "
46 db5b749f 2020-12-09 op (with-output-to-string (out)
47 db5b749f 2020-12-09 op (uiop:run-program "slop -f \"%x %y %w %h\""
48 db5b749f 2020-12-09 op :ignore-error-status t
49 db5b749f 2020-12-09 op :output out))))))
50 db5b749f 2020-12-09 op
51 db5b749f 2020-12-09 op (defcommand my/record () ()
52 db5b749f 2020-12-09 op "Record (or stop the recording) of the screen (or part of)."
53 db5b749f 2020-12-09 op (ignore-errors
54 db5b749f 2020-12-09 op (if *my/record-process*
55 db5b749f 2020-12-09 op (progn (uiop:terminate-process *my/record-process*)
56 db5b749f 2020-12-09 op (setq *my/record-process* nil))
57 db5b749f 2020-12-09 op (when-let (filename (completing-read (current-screen) "record into file: " nil
58 db5b749f 2020-12-09 op :initial-input "/tmp/record.mkv"))
59 db5b749f 2020-12-09 op (destructuring-bind (x y w h) (my/select-area)
60 db5b749f 2020-12-09 op (let ((proc (format nil
61 db5b749f 2020-12-09 op "exec ffmpeg -y -f x11grab -s ~ax~a -framerate 30 -i :0.0+~a,~a ~a"
62 db5b749f 2020-12-09 op w h x y
63 db5b749f 2020-12-09 op filename)))
64 db5b749f 2020-12-09 op (setf *my/record-process*
65 db5b749f 2020-12-09 op (uiop:launch-program proc))))))))
66 db5b749f 2020-12-09 op ```
67 db5b749f 2020-12-09 op
68 db5b749f 2020-12-09 op (The exec before ffmpeg is needed because otherwise uiop:terminate-process will kill the shell and not ffmpeg.)
69 db5b749f 2020-12-09 op
70 db5b749f 2020-12-09 op It asks for a file name, then uses slop to select an area, or a window, just like the original script, and starts ffmpeg.
71 db5b749f 2020-12-09 op
72 db5b749f 2020-12-09 op Those ignore-errors are there because I'm pretty lazy today. Also, this needs cl-ppcre installed, because I didn't want to roll my own split-string-on-space. Again, I'm pretty lazy today.
73 db5b749f 2020-12-09 op
74 2153543f 2020-12-12 op Oh, and there is another small gem: the bar (modeline) is part of the window manager too, so we have fully control over it. I added the following customisation to the format of the modeline, and when I'm recording a [rec] label will appear right after the group indicator.
75 db5b749f 2020-12-09 op
76 db5b749f 2020-12-09 op ``` common-lisp
77 db5b749f 2020-12-09 op (setf *screen-mode-line-format* (list "[%n] "
78 db5b749f 2020-12-09 op '(:eval (if *my/record-process*
79 db5b749f 2020-12-09 op "[rec] "
80 db5b749f 2020-12-09 op ""))
81 db5b749f 2020-12-09 op "%d | %w"))
82 db5b749f 2020-12-09 op ```