Easy GL Capture
A minimal OpenGL / OpenGL ES game capture tool for Linux, implemented as an LD_PRELOAD library.
This library intercepts GLX/EGL buffer swaps, reads the rendered framebuffer, and pipes frames to FFmpeg for video encoding. Recording can be toggled at runtime without modifying or rebuilding the target application.
Supported
- GLX: desktop OpenGL and GLES contexts created through GLX.
- EGL: OpenGL ES or desktop OpenGL contexts created through EGL.
- Dynamically loaded GL functions: applications using
dlopen()+dlsym()(e.g. SDL) are supported by intercepting function lookups. - EGL damage swaps: supports
eglSwapBuffersWithDamageKHRandeglSwapBuffersWithDamageEXT.
The GL API (desktop GL or GLES) is detected at runtime using GL_VERSION.
Limitations
- no Vulkan support.
- Pure Wayland environments cannot use the F6 hotkey; use
SIGUSR1instead. - Only the current GLX drawable or EGL draw surface is captured.
- Recording stops if the captured surface changes dimensions.
- Audio capture currently uses FFmpeg’s PulseAudio input.
Requirements
- A GLX or EGL application
- FFmpeg available in
PATH - FFmpeg built with
libx264(default video codec) - PulseAudio-compatible audio input, if recording audio
Build
git clone https://codeberg.org/itszariep/eglcapture
cd eglcapture
make
Usage
Run an application with capture enabled
LD_PRELOAD=/path/to/eglcap.so ./mygame
The library waits for the application to create a usable GL context and swap its framebuffer.
To capture a game:
eglcapture./mygame
LD_PRELOAD may also affect child processes. Use GLCAP_VERBOSE=1 to help identify which processes load the library.
Toggle recording
F6 (X11 / XWayland)
Press F6 to start recording. Press it again to stop and save the video.
SIGUSR1
You can also toggle recording by sending SIGUSR1 to the target process:
kill -USR1 "$(pidof mygame)"
Or use the PID printed in the capture log:
kill -USR1 <pid>
Second method also works on pure Wayland, where the F6 hotkey is unavailable.
Recording can only start when a usable GL context and capture surface are available.
Recording indicator
- red square is displayed in the corner while recording.
- A
RECORDINGlabel appears briefly when recording starts. - A
SAVEDlabel appears briefly after a successful save. - Labels are displayed for 3 seconds.
The overlay is drawn after framebuffer capture, so it does not appear in the recorded video.
Output files
By default, recordings are saved in the current working directory:
glcap_YYYYMMDD_HHMMSS.mp4
The filename uses the date and time when recording starts.
The output directory, container, codecs, and FFmpeg arguments can be customized using environment variables.
Environment variables
| Variable | Default | Description |
|---|---|---|
GLCAP_DIR |
. |
Output directory for recordings |
GLCAP_OUTPUT_FILE |
Empty | Exact file path for recording |
GLCAP_FPS |
24 |
Maximum capture rate in FPS. Values below 1 fall back to 24 |
GLCAP_VERBOSE |
0 |
Set to 1 to log load/exit diagnostics and intercepted function lookups |
GLCAP_QUIET |
0 |
Set to 1 to suppress all capture log output |
GLCAP_COLOR |
Auto | Set to 1 to force colored logs, 0 to disable |
GLCAP_CONTAINER |
mp4 |
Output container/extension |
GLCAP_VCODEC |
libx264 |
FFmpeg video codec |
GLCAP_ACODEC |
aac |
FFmpeg audio codec |
GLCAP_FFMPEG_ARGS |
Empty | Additional FFmpeg arguments |
GLCAP_AUDIO |
0 |
Set to 1 to enable audio capture |
GLCAP_AUDIO_DEVICE |
default.monitor |
PulseAudio input device for audio capture |
GLCAP_ALWAYS_RECORD |
Empty | Always record by default |
GLCAP_COLOR defaults to enabled when stderr is a TTY, unless NO_COLOR is set. An explicit GLCAP_COLOR value overrides this behavior.
GLCAP_QUIET=1 suppresses log messages, but does not disable recording.
Examples
Pipe the game so programs like ADSR can use it:
mkfifo /tmp/glcap.fifo &&
GLCAP_OUTPUT_FILE=/tmp/glcap.fifo GLCAP_VCODEC=rawvideo GLCAP_FFMPEG_ARGS="-pix_fmt bgr0 -f rawvideo" eglcapture glxgears
Record at 60 FPS:
GLCAP_FPS=60 eglcapture./mygame
Save recordings to a specific directory:
GLCAP_DIR="$HOME/Videos" eglcapture./mygame
Enable audio capture:
GLCAP_AUDIO=1 eglcapture./mygame
Choose a PulseAudio monitor/device:
GLCAP_AUDIO=1 \
GLCAP_AUDIO_DEVICE="default.monitor" \
eglcapture./mygame
Use a different video codec or FFmpeg preset:
GLCAP_VCODEC=libx264 \
GLCAP_FFMPEG_ARGS="-preset veryfast -crf 18" \
eglcapture./mygame
Enable verbose diagnostics:
GLCAP_VERBOSE=1 eglcapture./mygame
Disable all capture logs:
GLCAP_QUIET=1 eglcapture./mygame
How it works
LD_PRELOADloads the capture library into the target process.- GLX/EGL buffer swap functions are intercepted.
- The library checks for a current GL context and a usable drawable/surface.
- When recording is active, the default framebuffer is read back as RGBA pixels.
- Frames are rate-limited and piped to FFmpeg for encoding.
- On stop, FFmpeg is finalized and the recording is saved.
The capture code preserves relevant GL readback state, including pixel pack alignment, framebuffer binding, pixel pack buffer binding, and (for desktop GL) the read buffer.
The video is vertically flipped and cropped to even dimensions by FFmpeg for encoding.
If the application resizes its capture surface during recording, recording is stopped to avoid writing frames with inconsistent dimensions.