A native OBS Studio source plugin that displays a single static PDF page as a video source, using Poppler + Cairo to rasterize the page (with real alpha channel support).
- Load any PDF file via a file picker in Source Properties.
- Previous / Next page buttons in the properties panel, plus OBS's built-in media-controls toolbar (shown under the preview when the source is selected) for Prev/Next — and, in scroll mode, Play/Pause to start/stop auto-scrolling and Prev/Next to jump by one viewport height. You can also bind global hotkeys for prev/next (OBS → Settings → Hotkeys → search "PDF").
- Two display modes: a Static Page mode (single page, prev/next/fit
controls as above) and a Continuous Scroll mode that renders every page
in the document stacked vertically and auto-scrolls through it.
- In scroll mode you set a Scroll Width (px each page is rendered at) and a Viewport Height (px — how much of the stack is visible at once); these define the source's own on-canvas size, independent of the document's total length.
- Scroll Speed (px/sec) controls how fast it moves; 0 pauses it.
- Loop replays from the top once it reaches the bottom; otherwise it stops at the last page.
- Only the pages currently near the viewport are rasterized — each page bitmap is cached after its first render, so steady scrolling is cheap (just GPU blits), not re-rendering PDF pages every frame.
- Fit modes: original size (custom DPI), fit width, fit height, or fit within canvas preserving aspect ratio (static mode only).
- Transparent background toggle — when off, a white page background is painted (like a normal document); when on, only the PDF's own ink is rendered, so you can overlay a page directly on top of other sources/scenes.
- Reload PDF from Disk button, for when the file changes and you want to re-open it without re-adding the source.
- Re-opening a different PDF is just changing the "PDF File" path — no need to remove/recreate the source.
You need the OBS Studio plugin SDK (headers/libobs), plus Poppler-GLib and Cairo development packages.
sudo apt install build-essential cmake pkg-config \
libobs-dev libpoppler-glib-dev libcairo2-dev libglib2.0-dev(If your distro doesn't ship libobs-dev, build/install OBS Studio from
source first, or point CMake at your OBS build tree with
-Dlibobs_DIR=/path/to/obs-studio/build.)
sudo dnf install cmake gcc-c++ pkgconf-pkg-config \
obs-studio-devel poppler-glib-devel cairo-devel glib2-develbrew install cmake pkg-config poppler cairo glib
# libobs headers: either install OBS via `brew install --cask obs`, or
# clone https://github.com/obsproject/obs-studio and build/install it so
# libobs is discoverable by CMake (see obs-studio's own build docs for the
# exact CMake package name/version you have installed).git clone <this repo> obs-pdf-source
cd obs-pdf-source
cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build build -j$(nproc)cmake --install buildThis places the shared library and locale data under your OBS plugins
directory (see CMakeLists.txt for the exact paths per-OS). Then just
restart OBS Studio.
If you'd rather install manually:
- Linux: copy
build/obs-pdf-source.soto~/.config/obs-studio/plugins/obs-pdf-source/bin/64bit/obs-pdf-source.soand thedata/folder to~/.config/obs-studio/plugins/obs-pdf-source/data/. - macOS: copy the built
.so/.dylibto~/Library/Application Support/obs-studio/plugins/obs-pdf-source/bin/64bit/anddata/alongside it under.../obs-pdf-source/data/.
- In OBS, click + under Sources → PDF Page (Static).
- Pick your PDF file.
- Set the page number, fit mode, and transparent background as desired.
- Use the Previous/Next Page buttons in the source's Properties dialog to flip pages, or assign hotkeys under Settings → Hotkeys for quick control without opening the dialog while live.
- To show a different document, just change the "PDF File" path in Properties — no need to delete and re-add the source.
- This renders a single static page as a bitmap (no PDF animations, links, or forms) — by design, since the goal is a simple page-turn slide source.
- Very large pages are capped at 8192px per side to avoid pathological memory/texture usage.
- Re-rendering happens once per page/setting change (on the next
video_tick), not every frame, so this is cheap on GPU/CPU while idle.