Creating Streaming Service Outputs with OBS_OUTPUT_SERVICE Protocol Support in OBS Studio

OBS Studio uses the OBS_OUTPUT_SERVICE protocol flag to bind streaming outputs to service objects that provide connection details like server URLs and stream keys, enabling a modular streaming architecture where outputs handle encoding and delivery while services manage endpoint configuration.

OBS Studio's plugin architecture separates the concerns of media delivery from connection management through the OBS_OUTPUT_SERVICE protocol flag. When building custom streaming outputs, implementing support for this flag allows your code to integrate seamlessly with OBS's existing service ecosystem, including RTMP, WHIP (WebRTC), and custom service configurations. This guide explains how to create streaming service outputs using the OBS_OUTPUT_SERVICE protocol based on the actual implementation in the obsproject/obs-studio repository.

Declaring the OBS_OUTPUT_SERVICE Flag

To create an output that requires service configuration, you must declare the OBS_OUTPUT_SERVICE flag in your obs_output_info structure. This flag, defined in libobs/obs-output.h as (1 << 3), signals to OBS that your output expects an associated service object at runtime.

In libobs/obs-output.h line 29, the flag is defined:

#define OBS_OUTPUT_SERVICE (1 << 3)

When OBS loads your plugin, it checks this flag to determine if the output supports service binding. The internal helper obs_output_has_service() in libobs/obs-output.c (line 110) verifies this:

return (output->info.flags & OBS_OUTPUT_SERVICE) != 0;

Real-world implementations demonstrate this pattern across multiple protocols. The RTMP output in plugins/obs-outputs/rtmp-stream.c (line 1798) registers with:

.flags = OBS_OUTPUT_AV | OBS_OUTPUT_ENCODED | OBS_OUTPUT_SERVICE | OBS_OUTPUT_MULTI_TRACK_AV,

Similarly, the WHIP output for WebRTC streaming in plugins/obs-webrtc/whip-output.cpp (line 723) uses:

const uint32_t base_flags = OBS_OUTPUT_ENCODED | OBS_OUTPUT_SERVICE | OBS_OUTPUT_MULTI_TRACK_AV;

Registering Outputs and Services

The registration process involves two distinct steps: registering the output that requires service support, and registering the service that provides connection data.

First, register your output using obs_register_output():

static struct obs_output_info my_output_info = {
    .id = "my_custom_output",
    .flags = OBS_OUTPUT_SERVICE | OBS_OUTPUT_ENCODED,
    .create = my_output_create,
    .destroy = my_output_destroy,
    .start = my_output_start,
    .stop = my_output_stop,
    .get_name = my_output_get_name,
};

// In your plugin load function
obs_register_output(&my_output_info);

Services are registered separately via obs_register_service(). Built-in services like RTMP Common in plugins/rtmp-services/rtmp-common.c (line 1160) implement the obs_service_info structure:

struct obs_service_info rtmp_common_service = {
    .id = "rtmp_common",
    .create = rtmp_common_create,
    .destroy = rtmp_common_destroy,
    .get_connect_info = rtmp_common_get_connect_info,
    // ...
};

Binding Services to Outputs

During configuration, OBS binds a service instance to your output using the public API declared in libobs/obs.h (lines 2061-2064). The workflow involves creating both objects and then associating them:

// Create the output
obs_output_t *output = obs_output_create("my_custom_output", "My Output", settings, NULL);

// Create the service
obs_service_t *service = obs_service_create("rtmp_common", "My Service", service_settings, NULL);

// Bind service to output
obs_output_set_service(output, service);

The output holds a reference to the service through reference counting (obs_service_addref/obs_service_release), ensuring the service remains valid throughout the streaming session.

Retrieving Connection Information

Once streaming starts, your output retrieves connection parameters from the bound service using obs_service_get_connect_info(). The API in libobs/obs.h (line 2555) provides:

const char *obs_service_get_connect_info(const obs_service_t *service, uint32_t type);

The WHIP output implementation in plugins/obs-webrtc/whip-output.cpp (lines 252-264) demonstrates this pattern:

obs_service_t *service = obs_output_get_service(output);
if (!service) {
    // Handle missing service error
    return false;
}

const char *endpoint_url = obs_service_get_connect_info(
    service, OBS_SERVICE_CONNECT_INFO_SERVER_URL);
const char *bearer_token = obs_service_get_connect_info(
    service, OBS_SERVICE_CONNECT_INFO_BEARER_TOKEN);

Available connection info types include:

  • OBS_SERVICE_CONNECT_INFO_SERVER_URL
  • OBS_SERVICE_CONNECT_INFO_STREAM_KEY
  • OBS_SERVICE_CONNECT_INFO_BEARER_TOKEN

The FFmpeg muxer in plugins/obs-ffmpeg/obs-ffmpeg-mux.c (line 894) also utilizes this protocol:

.flags = OBS_OUTPUT_AV | OBS_OUTPUT_ENCODED | OBS_OUTPUT_MULTI_TRACK | OBS_OUTPUT_SERVICE,

Complete Implementation Example

Below is a complete skeleton demonstrating how to implement an output with OBS_OUTPUT_SERVICE support:

#include <obs-module.h>

struct my_stream_output {
    obs_output_t *output;
    // Your custom data
};

static const char *my_output_get_name(void *unused)
{
    UNUSED_PARAMETER(unused);
    return "My Service Output";
}

static void *my_output_create(obs_data_t *settings, obs_output_t *output)
{
    struct my_stream_output *data = bzalloc(sizeof(struct my_stream_output));
    data->output = output;
    return data;
}

static void my_output_destroy(void *data)
{
    bfree(data);
}

static bool my_output_start(void *data)
{
    struct my_stream_output *out = data;
    
    // Retrieve the bound service
    obs_service_t *service = obs_output_get_service(out->output);
    if (!service) {
        blog(LOG_ERROR, "No service attached to output");
        return false;
    }
    
    // Get connection details
    const char *server_url = obs_service_get_connect_info(
        service, OBS_SERVICE_CONNECT_INFO_SERVER_URL);
    const char *stream_key = obs_service_get_connect_info(
        service, OBS_SERVICE_CONNECT_INFO_STREAM_KEY);
    
    if (!server_url || !stream_key) {
        blog(LOG_ERROR, "Missing connection information");
        return false;
    }
    
    // Initialize your streaming connection using server_url and stream_key
    // ...
    
    return true;
}

static void my_output_stop(void *data, uint64_t ts)
{
    // Cleanup streaming connection
}

static struct obs_output_info my_output_info = {
    .id = "my_service_output",
    .flags = OBS_OUTPUT_SERVICE | OBS_OUTPUT_ENCODED | OBS_OUTPUT_AV,
    .get_name = my_output_get_name,
    .create = my_output_create,
    .destroy = my_output_destroy,
    .start = my_output_start,
    .stop = my_output_stop,
};

OBS_MODULE_EXPORT uint32_t obs_module_ver(void)
{
    return LIBOBS_API_VER;
}

OBS_MODULE_EXPORT bool obs_module_load(void)
{
    obs_register_output(&my_output_info);
    return true;
}

Summary

  • OBS_OUTPUT_SERVICE is defined in libobs/obs-output.h as (1 << 3) and indicates that an output requires service configuration.
  • Outputs declare this flag in their obs_output_info structure during registration via obs_register_output().
  • Services are registered separately using obs_register_service() and implement obs_service_get_connect_info() to expose connection data.
  • The binding occurs through obs_output_set_service(), which the OBS frontend calls when users select streaming profiles.
  • During streaming, outputs call obs_output_get_service() followed by obs_service_get_connect_info() to retrieve server URLs, stream keys, and authentication tokens.

Frequently Asked Questions

What is the difference between an output and a service in OBS Studio?

An output is the code module that encodes and transmits media data to a destination, while a service is a configuration object that provides connection parameters like server URLs and stream keys. The OBS_OUTPUT_SERVICE protocol allows outputs to remain generic while services handle platform-specific connection details.

How does OBS know if an output requires a service?

OBS checks the flags field of the obs_output_info structure when the output is registered. If the flag includes OBS_OUTPUT_SERVICE (verified by obs_output_has_service() in libobs/obs-output.c), OBS enables service binding functionality for that output instance.

Can third-party plugins create custom services for existing outputs?

Yes, third-party plugins can implement custom services by filling an obs_service_info structure and registering it with obs_register_service(). Any output that declares the OBS_OUTPUT_SERVICE flag can automatically use any registered service, including custom implementations that provide connection info through obs_service_get_connect_info().

What connection information types are available through the service API?

The service API supports multiple connection info types including OBS_SERVICE_CONNECT_INFO_SERVER_URL for the streaming endpoint, OBS_SERVICE_CONNECT_INFO_STREAM_KEY for authentication, and OBS_SERVICE_CONNECT_INFO_BEARER_TOKEN for token-based protocols like WHIP, as implemented in plugins/obs-webrtc/whip-output.cpp.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →