Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Record audio, video and keystrokes simulatenously
;;; screencasting.el --- Tooling for screencasting -*- lexical-binding: t; -*-
;; Copyright (C) 2019 Damien Cassou
;; Author: Damien Cassou <>
;; Keywords:
;; 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 3 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
;; 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 <>.
;;; Commentary:
;; This package starts simultaneously
;; - (1) showkeys to see keystrokes on the screen
;; (,
;; - (2) an instance of ffmpeg to record video, and
;; - (3) another instance of ffmpeg to record audio
;;; Code:
(require 'f)
(defvar screencasting-showkeys-filename "~/Downloads/showkeys/showkeys")
(defvar screencasting-project-directory "~/Documents/presentations/2019-10-mpdel")
(defvar screencasting-record-video-command
`(,(executable-find "ffmpeg")
"-probesize" "10000000"
"-video_size" "1920x1080"
"-framerate" "30"
"-f" "x11grab"
"-i" ":0.0+0,0"
"-c:v" "libx264"
"-crf" "0"
"-preset" "ultrafast"))
(defvar screencasting-record-audio-command
`(,(executable-find "ffmpeg")
"-f" "pulse"
"-i" "default"))
(defvar screencasting--process-showkeys nil
"Process for showkeys.")
(defvar screencasting--process-record-video nil
"Process recording the screen.")
(defvar screencasting--process-record-audio nil
"Process recording audio.")
(defun screencasting-start-showkeys ()
"Start a process for showkeys."
(setq screencasting--process-showkeys
:name "showkeys"
:command (list screencasting-showkeys-filename))))
(defun screencasting-stop-showkeys ()
"Kill the showkeys process."
(when screencasting--process-showkeys
(interrupt-process screencasting--process-showkeys)
(setq screencasting--process-showkeys nil)))
(defun screencasting-ensure-showkeys ()
"Start showkeys if not already started."
(unless (and screencasting--process-showkeys (process-live-p screencasting--process-showkeys))
(defun screencasting--make-filename (basename counter extension)
"Return an absolute path for BASENAME with EXTENSION.
COUNTER is a number to make filename unique."
(format "%s/%s_%s.%s"
(expand-file-name screencasting-project-directory)
(defun screencasting--make-uniq-filename (basename extension)
"Return a filename for BASENAME with EXTENSION that is unique.
The returned filename is absolute in `screencasting-project-directory'."
(let* ((counter 1)
(filename (screencasting--make-filename basename counter extension)))
(while (f-exists-p filename)
(cl-incf counter)
(setq filename (screencasting--make-filename basename counter extension)))
(defun screencasting-start-record-video (basename)
"Start a process recording the screen."
(interactive (list (read-string "Basename? ")))
(let ((default-directory screencasting-project-directory)
(filename (screencasting--make-uniq-filename basename "mkv")))
(setq screencasting--process-record-video
:name "record screen"
:command (append screencasting-record-video-command
(list filename))
:buffer "*record screen*"))))
(defun screencasting-stop-record-video ()
"Stop the current video recording."
(when screencasting--process-record-video
(interrupt-process screencasting--process-record-video)
(setq screencasting--process-record-video nil)))
(defun screencasting-start-record-audio (basename)
"Start a process recording audio."
(interactive (list (read-string "Basename? ")))
(let ((default-directory screencasting-project-directory)
(filename (screencasting--make-uniq-filename basename "flac")))
(setq screencasting--process-record-audio
:name "record audio"
:command (append screencasting-record-audio-command
(list filename))
:buffer "*record audio*"))))
(defun screencasting-stop-record-audio ()
"Stop the current audio recording."
(when screencasting--process-record-audio
(interrupt-process screencasting--process-record-audio)
(setq screencasting--process-record-audio nil)))
(defun screencasting-start (basename)
"Start showkeys and recording for BASENAME."
(interactive (list (read-string "Basename? ")))
(screencasting-start-record-video basename)
(screencasting-start-record-audio basename))
(defun screencasting-stop ()
"Stop showkeys and recording."
(defun screencasting-setup ()
"Setup keybindings."
(bind-key "C-. q s" #'screencasting-start)
(bind-key "C-. q k" #'screencasting-stop))
(provide 'screencasting)
;;; screencasting.el ends here
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment