Skip to main content

pylibobs

Python bindings for libobs — the core C library of OBS Studio.

Lets Python scripts and apps drive libobs directly: initialize OBS, build scenes, configure encoders, mix audio, and record / stream — all without OBS Studio's UI running.

Status: beta. The public API is feature-complete and covered by tests. Reference counting semantics match OBS 32's obs_*_get_ref() model.


Why?

Existing options:

  • obspython runs inside OBS only — you can't pip install it or use it from a normal Python app.
  • obsws-python / simpleobsws talk to OBS via WebSocket — requires OBS to be running, and only exposes what the WebSocket API allows.

pylibobs links libobs directly (via cffi), so your Python process is the OBS host.


License

Copyright (C) 2026 Jonata Bolzan Loss and contributors.

pylibobs is licensed under GPL v2 or later, inherited from libobs. See LICENSE for the full text.

The published wheels bundle libobs's compiled binaries (also GPLv2+), so the wheel as distributed is covered by GPLv2+. Anything you build on top of pylibobs must be GPL-compatible if you redistribute it. Personal use carries no obligation.


Installation

pip install pylibobs

That's it on Windows / macOS / Linux. The wheel ships with bundled libobs binaries (libobs plus its plugin DLLs and data files, sourced from the official OBS Studio release on PyPI's build server). You don't need to install OBS Studio.

If you're installing from sdist (rare — only when no wheel is published for your platform), or you want to use a system-installed OBS, the loader falls back through:

  1. $LIBOBS_PATH environment variable (explicit override)
  2. Bundled libs inside the wheel — pylibobs/_libs/<platform>/<arch>/
  3. ctypes.util.find_library("obs")
  4. Well-known OBS Studio install paths

Maintainers / contributors can refresh the bundled libs by running:

python scripts/fetch_libs.py                  # current platform
python scripts/fetch_libs.py --all            # every platform
python scripts/fetch_libs.py --version 32.1.2 # pin OBS version

This downloads libobs from the official OBS GitHub release. The _libs/ tree is .gitignored and only populated during wheel builds.


Quick start

import time
from pylibobs import (
    OBSContext, OBSData, Source, Scene, Output,
    VideoEncoder, AudioEncoder,
)

with OBSContext() as obs:
    obs.set_video(width=1920, height=1080, fps_num=60)
    obs.set_audio()
    obs.load_modules()

    scene = Scene.create("main")
    cap = Source.create("monitor_capture", "Desktop", {"monitor": 0})
    scene.add(cap)

    venc = VideoEncoder.create("obs_x264", "video", {"crf": 23, "preset": "veryfast"})
    aenc = AudioEncoder.create("ffmpeg_aac", "audio", {"bitrate": 192})

    out = Output.create("ffmpeg_muxer", "rec", {"path": "out.mkv"})
    out.set_video_encoder(venc)
    out.set_audio_encoder(aenc)
    out.start()

    time.sleep(10)
    out.stop()

See examples/ for full recording and streaming scripts.

pylibobs-studio (tkinter, stdlib only)

examples/pylibobs_studio.py is a complete OBS-style desktop application built on nothing but the Python standard library:

python examples/pylibobs_studio.py

Features:

Pane What it does
Live preview libobs's D3D11 renderer draws directly into a tkinter Frame via its native HWND (Frame.winfo_id()Display.from_window(hwnd, w, h)). No Qt, no GTK, no extra deps.
Scenes Add / remove scenes; selecting one routes it to the program output.
Sources Per-scene list; add via a type-picker dialog populated from enum_input_types(), with auto-launched monitor/window/file pickers for the source types that need them. Reorder, toggle visibility, remove.
Audio mixer One row per audio-capable source: live VU meter (green / yellow / red), volume slider on an IEC dB curve, mute toggle. Levels come from a VolumeMeter queue read on the tk main loop.
Recording Standard MKV recording with live frames / bytes / dropped-frames in the status bar.

The whole app is ~600 lines in a single file. Use it as a starting point for your own pylibobs-based applications.


API overview

Class Wraps Notes
OBSContext obs_startup / obs_shutdown, video/audio reset Use as a context manager.
OBSData obs_data_t Dict-like; OBSData({"k": "v"})
Source obs_source_t Source.create(kind, name, settings)
Scene / SceneItem obs_scene_t / obs_sceneitem_t Add sources, set visibility, iterate items
VideoEncoder / AudioEncoder obs_encoder_t Per-type factory
Service obs_service_t RTMP/streaming targets
Output obs_output_t File or stream sinks; start()/stop()
Display obs_display_t Live preview into a native window (HWND)

Testing

pip install -e ".[dev]"

# Unit tests (mocked cffi layer — fast, no libobs needed)
pytest tests/unit

# Integration tests (need a real libobs)
pytest tests/integration -m integration

# On Linux CI with no display:
Xvfb :99 -screen 0 1920x1080x24 &
DISPLAY=:99 pytest tests/integration -m integration

CI runs the full matrix on Windows, Linux, and macOS — see .github/workflows/ci.yml.


Project layout

pylibobs/
├── pylibobs/
│   ├── _lib.py            # Library locator
│   ├── _ffi.py            # cffi instance
│   ├── _declarations.py   # C API declarations for cdef()
│   ├── context.py         # OBSContext
│   ├── data.py            # OBSData
│   ├── source.py          # Source
│   ├── scene.py           # Scene / SceneItem
│   ├── encoder.py         # VideoEncoder / AudioEncoder
│   ├── service.py         # Service
│   ├── output.py          # Output
│   └── _libs/             # Bundled libobs binaries (after fetch_libs.py)
├── tests/unit/            # Mocked tests
├── tests/integration/     # Real libobs tests
├── scripts/fetch_libs.py  # Pull libobs from OBS releases
└── examples/              # record_to_file.py, stream_to_rtmp.py

Coverage / known gaps

pylibobs currently declares 100% of the public libobs API (all 1388 exported obs_* / gs_* / signal_* / audio_resampler_* / media_remux_* functions are callable via pylibobs._ffi.get_lib()). Pythonic class-based wrappers cover the common workflows:

  • Lifecycle, video/audio init, scenes, sources, scene items, transforms (pos/scale/rot/crop/bounds)
  • Outputs (file + RTMP streaming), encoders (incl. ROI hints), services
  • Live preview (Display attached to a native window via HWND)
  • Filters, transitions, hotkeys, fader + VU meter, audio monitoring
  • Raw audio/video callbacks (numpy-friendly), audio resampler, media remux
  • Properties API (read + edit, with type-aware widgets in examples/pylibobs_studio.py)
  • Save / load whole scene collections to JSON

What's intentionally raw-only (callable via get_lib() but no class wrapper):

  • The 290 gs_* graphics primitives — exposing them invites GPU-thread bugs; use obs_render_main_texture() instead.
  • Property builders (obs_properties_add_*) — only useful for C plugin authors.
  • Multi-canvas API (obs_canvas_*), obs_view_*, codec bitstream parsers (obs_avc_* / obs_av1_*).

Contributing

git clone https://github.com/jonata/pylibobs.git
cd pylibobs
python -m venv .venv && source .venv/bin/activate    # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
python scripts/fetch_libs.py                          # download bundled libobs
pytest                                                # 100+ tests, mock + integration

The integration suite needs process isolation (libobs can't gracefully restart inside a single process); use the included runner:

python scripts/run_tests.py

Release process

  1. Bump version in pyproject.toml and tag the commit vX.Y.Z.
  2. Push the tag. GitHub Actions:
    • Builds platform-specific wheels with bundled libobs (Windows / Linux / macOS Intel + Apple Silicon)
    • Builds the sdist
    • Publishes to PyPI via Trusted Publishing (no token needed in repo secrets)
    • Attaches all wheels to a GitHub Release with auto-generated notes

To set up Trusted Publishing on PyPI for this repo, register pylibobs as a project on PyPI, then in Project settings → Publishing, add a "GitHub Actions" trusted publisher pointing at <owner>/pylibobs / workflow release.yml / environment pypi.


Contributions welcome — PRs against main.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pylibobs-0.1.0.tar.gz (98.4 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

pylibobs-0.1.0-py3-none-win_amd64.whl (43.5 MB view details)

Uploaded Python 3Windows x86-64

pylibobs-0.1.0-py3-none-manylinux_2_31_x86_64.whl (17.0 MB view details)

Uploaded Python 3manylinux: glibc 2.31+ x86-64

pylibobs-0.1.0-py3-none-macosx_12_0_arm64.whl (40.6 MB view details)

Uploaded Python 3macOS 12.0+ ARM64

File details

Details for the file pylibobs-0.1.0.tar.gz.

File metadata

  • Download URL: pylibobs-0.1.0.tar.gz
  • Upload date:
  • Size: 98.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pylibobs-0.1.0.tar.gz
Algorithm Hash digest
SHA256 c5d4663e112008595f9e08c06db50932db66fa18e12072cfef719b2eb2871c72
MD5 e7173bf7838b538cb45eaf5de832affc
BLAKE2b-256 98915192f50b1f2fb6e63615009b5eff9c22c44a97d471da0c17def3a9cda607

See more details on using hashes here.

Provenance

The following attestation bundles were made for pylibobs-0.1.0.tar.gz:

Publisher: release.yml on jonata/pylibobs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pylibobs-0.1.0-py3-none-win_amd64.whl.

File metadata

  • Download URL: pylibobs-0.1.0-py3-none-win_amd64.whl
  • Upload date:
  • Size: 43.5 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pylibobs-0.1.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 cd3f30aed76a5b3131da8eae2a187db5511ef6cdf1ece36dff431b072c52df51
MD5 fc07807e18e7f8ff7ad4f0478fa7581b
BLAKE2b-256 717e3670a69ce5634f4344306eef2453743ebac9e340e7419a513cf233bab8b6

See more details on using hashes here.

Provenance

The following attestation bundles were made for pylibobs-0.1.0-py3-none-win_amd64.whl:

Publisher: release.yml on jonata/pylibobs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pylibobs-0.1.0-py3-none-manylinux_2_31_x86_64.whl.

File metadata

File hashes

Hashes for pylibobs-0.1.0-py3-none-manylinux_2_31_x86_64.whl
Algorithm Hash digest
SHA256 a0d121f938f28ad0b0f63743905399acd9090ece15133aab68f43c18f69f1dab
MD5 1abb913e7bcf1552f0c8e66d6d9f99fd
BLAKE2b-256 35c0e64d9a438a9321fa18977b490d8a11829c609ae94f993a0d019347e1bb01

See more details on using hashes here.

Provenance

The following attestation bundles were made for pylibobs-0.1.0-py3-none-manylinux_2_31_x86_64.whl:

Publisher: release.yml on jonata/pylibobs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pylibobs-0.1.0-py3-none-macosx_12_0_arm64.whl.

File metadata

File hashes

Hashes for pylibobs-0.1.0-py3-none-macosx_12_0_arm64.whl
Algorithm Hash digest
SHA256 75facb41b0faade14e3df68a41507a573daab71cdcbae003f4f16a8aacdb74a4
MD5 f9d585f0310cf6ed82cfd2be2cf0764b
BLAKE2b-256 35cf9c30a5cd71217c9d6104365a33a2c3f3336f8772bad63fe3ce4db1044f1a

See more details on using hashes here.

Provenance

The following attestation bundles were made for pylibobs-0.1.0-py3-none-macosx_12_0_arm64.whl:

Publisher: release.yml on jonata/pylibobs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.1.2

4 files

0.1.1

4 files

This release

0.1.0 This release

4 files

0.0.1

4 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page