Get the FREE Ultimate OpenClaw Setup Guide →

obs-plugin-guide

npx machina-cli add skill UtakataKyosui/C2Lab/obs-plugin-guide --openclaw
Files (1)
SKILL.md
7.8 KB

OBS Studio プラグイン開発ガイド

プラグインの種類

OBS Studio には以下の種類のプラグインがある:

種類用途主要構造体
ソースプラグインカメラ・キャプチャなど映像/音声源obs_source_info
フィルタープラグイン映像/音声のエフェクト処理obs_source_info (type=FILTER)
出力プラグイン配信・録画先の定義obs_output_info
エンコーダープラグイン映像/音声エンコードobs_encoder_info

言語選択: C/C++ vs Rust

C/C++ アプローチ(推奨・実績多)

メリット:

  • OBS SDK がネイティブ C API
  • obs-plugintemplate などテンプレートが充実
  • コミュニティサポートが豊富

デメリット:

  • 手動メモリ管理(bzalloc/bfree の使用が必要)
  • バッファオーバーフロー等のリスク

Rust アプローチ(安全性重視)

メリット:

  • メモリ安全性(コンパイル時保証)
  • unsafe ブロックで FFI 境界を明示

デメリット:

  • FFI バインディングの手動実装が必要
  • obs-rs 等のラッパーは発展途上
  • CMake との連携設定が複雑

C/C++ アプローチ

プロジェクト構造(obs-plugintemplate ベース)

my-obs-plugin/
├── CMakeLists.txt
├── src/
│   ├── plugin-main.c      # obs_module_load / obs_module_unload
│   └── my-source.c        # ソース実装
├── data/
│   └── locale/
│       └── en-US.ini      # 文字列リソース
└── buildspec.json         # OBS ビルドシステム設定

必須エントリポイント

// plugin-main.c
#include <obs-module.h>

OBS_DECLARE_MODULE()
OBS_MODULE_USE_DEFAULT_LOCALE("my-plugin", "en-US")

bool obs_module_load(void)
{
    // ソース・フィルター等を登録
    obs_register_source(&my_source_info);
    blog(LOG_INFO, "Plugin loaded successfully");
    return true;
}

void obs_module_unload(void)
{
    blog(LOG_INFO, "Plugin unloaded");
}

obs_source_info 構造体(ソースプラグイン)

struct obs_source_info my_source_info = {
    .id            = "my_source",           // 一意な ID(必須)
    .type          = OBS_SOURCE_TYPE_INPUT, // プラグイン種別
    .output_flags  = OBS_SOURCE_VIDEO,      // 出力フラグ
    .get_name      = my_source_get_name,    // 表示名取得
    .create        = my_source_create,      // インスタンス生成
    .destroy       = my_source_destroy,     // インスタンス破棄
    .update        = my_source_update,      // プロパティ変更時
    .get_properties = my_source_properties, // UI プロパティ定義
    .video_render  = my_source_render,      // 映像描画(毎フレーム)
    .get_width     = my_source_get_width,
    .get_height    = my_source_get_height,
};

メモリ管理の基本

OBS では標準の malloc/free ではなく bzalloc/bfree を使う:

// 確保: bzalloc でゼロ初期化
struct my_data *data = bzalloc(sizeof(struct my_data));

// 解放: bfree で解放
bfree(data);

// 文字列の複製
char *name = bstrdup(source_name);
bfree(name); // 使い終わったら解放

CMakeLists.txt の基本設定

詳細: references/cmake-setup.md

cmake_minimum_required(VERSION 3.16)
project(my-obs-plugin VERSION 0.1.0)

find_package(libobs REQUIRED)

add_library(my-obs-plugin MODULE
    src/plugin-main.c
    src/my-source.c
)

target_link_libraries(my-obs-plugin
    OBS::libobs
)

Rust アプローチ

Cargo.toml 設定

[package]
name = "my-obs-plugin"
version = "0.1.0"
edition = "2021"

[lib]
# 共有ライブラリとしてビルド(OBS が dlopen でロード)
crate-type = ["cdylib"]

[dependencies]
# OBS との FFI には libc を使用
libc = "0.2"

エントリポイントの実装

// src/lib.rs
use std::ffi::c_int;

/// OBS がプラグインロード時に呼び出す
#[no_mangle]
pub unsafe extern "C" fn obs_module_load() -> bool {
    // ソース情報を登録
    unsafe {
        obs_register_source(&MY_SOURCE_INFO);
    }
    true
}

/// OBS がプラグインアンロード時に呼び出す
#[no_mangle]
pub unsafe extern "C" fn obs_module_unload() {
    // クリーンアップ処理
}

obs_source_info を Rust で定義

use std::ffi::{c_char, c_void};

// OBS の C 構造体と ABI 互換にするため repr(C) が必須
#[repr(C)]
pub struct ObsSourceInfo {
    pub id: *const c_char,
    pub source_type: u32,
    pub output_flags: u32,
    pub get_name: Option<unsafe extern "C" fn(type_data: *mut c_void) -> *const c_char>,
    pub create: Option<unsafe extern "C" fn(settings: *mut c_void, source: *mut c_void) -> *mut c_void>,
    pub destroy: Option<unsafe extern "C" fn(data: *mut c_void)>,
    // ... 他のフィールド
}

static MY_SOURCE_INFO: ObsSourceInfo = ObsSourceInfo {
    id: b"my_rust_source\0".as_ptr() as *const c_char,
    source_type: OBS_SOURCE_TYPE_INPUT,
    output_flags: OBS_SOURCE_VIDEO,
    get_name: Some(my_source_get_name),
    create: Some(my_source_create),
    destroy: Some(my_source_destroy),
    // ...
};

メモリ管理(Rust の場合)

// Box を使ってデータを管理
unsafe extern "C" fn my_source_create(
    settings: *mut ObsData,
    source: *mut ObsSource,
) -> *mut c_void {
    let data = Box::new(MySourceData {
        source,
        width: 1920,
        height: 1080,
    });
    // raw ポインタとして OBS に渡す(OBS が destroy で返してくる)
    Box::into_raw(data) as *mut c_void
}

unsafe extern "C" fn my_source_destroy(data_ptr: *mut c_void) {
    // Box::from_raw で所有権を回収 → スコープ終了時に自動解放
    let _ = Box::from_raw(data_ptr as *mut MySourceData);
}

build.rs での OBS SDK パス検出

// build.rs
fn main() {
    // OBS SDK のヘッダーパスを環境変数から取得
    let obs_include = std::env::var("OBS_INCLUDE_DIR")
        .unwrap_or_else(|_| "/usr/include/obs".to_string());

    println!("cargo:rerun-if-env-changed=OBS_INCLUDE_DIR");
    println!("cargo:include={}", obs_include);
}

詳細: references/rust-approach.md


インストール先(プラットフォーム別)

OSインストールパス
Linux~/.config/obs-studio/plugins/<plugin-name>/bin/64bit/
macOS~/Library/Application Support/obs-studio/plugins/<plugin-name>/bin/
Windows%APPDATA%\obs-studio\plugins\<plugin-name>\bin\64bit\

システム全体にインストールする場合:

  • Linux: /usr/lib/obs-plugins/
  • macOS: /Library/Application Support/obs-studio/plugins/

参考ファイル

  • references/cmake-setup.md - CMakeLists.txt の詳細設定・find_package/FetchContent
  • references/source-plugin.md - ソースプラグイン実装例(C/C++)
  • references/filter-plugin.md - フィルタープラグイン実装例(C/C++)
  • references/api-reference.md - OBS API リファレンス(obs-module.h / obs.h 等)
  • references/rust-approach.md - Rust での FFI 実装、cargo + cmake 連携
  • references/debugging.md - GDB/Valgrind/AddressSanitizer 活用

Source

git clone https://github.com/UtakataKyosui/C2Lab/blob/main/plugins/obs-plugin-dev/skills/obs-plugin-guide/SKILL.mdView on GitHub

Overview

OBS Studio のプラグインを C/C++ または Rust で作成するための実践ガイドです。ソース・フィルター・出力・エンコーダープラグインの構造、obs_module_load/unload の実装、CMakeLists.txt の設定、OBS SDK API の使い方、Rust の FFI アプローチを詳しく解説します。

How This Skill Works

C/C++ では obs-plugintemplate ベースのプロジェクト構造を使い、obs_module_load でプラグインを登録して、source/filter/output/encoder の各情報を obs_source_info などに実装します。Rust では cdylib を使い unsafe FFI で OBS との境界を明示し、ObsSourceInfo の定義と extern C エントリを組み合わせます。安全性を重視する反面、FFI バインディングの手動実装や obs-rs のラッパーは未成熟で、CMake 連携設定が難しい点に留意します。

When to Use It

  • 新しいソース/フィルター/エンコーダーを作成して OBS に組み込みたい時
  • OBS SDK API の使い方とプラグインの基本構造を理解したい時
  • C/C++ と Rust のどちらで実装するか比較検討したい時
  • CMakeLists.txt や Cargo.toml などビルド設定を整えたい時
  • プラグインのビルド・デバッグ手順を実践的に知りたい時

Quick Start

  1. Step 1: C/C++ か Rust の選択と、CMakeLists.txt/Cargo.toml を準備する
  2. Step 2: obs_module_load を実装し、obs_source_info などの構造を登録する
  3. Step 3: OBS にプラグインをビルドしてロード、ログメッセージを確認する

Best Practices

  • OBS SDK のネイティブ C APIに合わせた実装を心がける
  • メモリ管理は bzalloc/bfree を使い、標準 malloc/free の代わりに管理
  • obs_module_load でソース・フィルター等を適切に登録する
  • Rust を使う場合 unsafe FFI の境界を明示し、FFIの安全性を最優先にする
  • CMakeLists.txt やテンプレートを活用して一貫性を保つ

Example Use Cases

  • ソースプラグインの基本例を実装して OBS にロードする
  • フィルターを追加して映像エフェクトを処理する
  • 出力プラグインを定義して配信先を拡張する
  • エンコーダープラグインの追加でエンコード動作を拡張する
  • CMakeLists.txt の設定を使ってビルドテンプレを確立する

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers