How to run C++ code to manipulate webrtcsink/src plugins

Hi,
This is a very beginner question but I’m wondering how to use C++ code to manipulate the rust plugin library, more specifically the webrtc plugins.
My goal is to build an app that can take a shared memory and stream it with webrtc to my website.

What do you want to do exactly? In general, you’d use them like any other GStreamer element.

I’m trying to run the following code :

#include <gst/gst.h>
#include <iostream>
#include <string>

int main(int argc, char *argv[]) {
  gst_init(&argc, &argv);

  // Create the pipeline
  GstElement *pipeline = gst_pipeline_new("webrtc-pipeline");
  if (!pipeline) {
    std::cerr << "Failed to create pipeline" << std::endl;
    return -1;
  }

  // Create elements
  GstElement *videotestsrc = gst_element_factory_make("videotestsrc", "source");
  GstElement *queue = gst_element_factory_make("queue", "queue");
  GstElement *webrtcsink = gst_element_factory_make("webrtcsink", "webrtcsink");

  if (!videotestsrc || !queue || !webrtcsink) {
    std::cerr << "Failed to create one or more GStreamer elements" << std::endl;
    gst_object_unref(pipeline);
    return -1;
  }
  // Add elements to the pipeline
  gst_bin_add_many(GST_BIN(pipeline), videotestsrc, queue, webrtcsink, NULL);

  // Link the elements
  if (!gst_element_link_many(videotestsrc, queue, webrtcsink, NULL)) {
    std::cerr << "Failed to link elements" << std::endl;
    gst_object_unref(pipeline);
    return -1;
  }

  // Set the pipeline to the Playing state
  GstStateChangeReturn ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);
  if (ret == GST_STATE_CHANGE_FAILURE) {
    std::cerr << "Failed to set pipeline to Playing state" << std::endl;
    gst_object_unref(pipeline);
    return -1;
  }

  // Create a GMainLoop to handle bus messages
  GMainLoop *main_loop = g_main_loop_new(NULL, FALSE);

  // Get the bus from the pipeline
  GstBus *bus = gst_element_get_bus(pipeline);
  gst_bus_add_watch(
      bus,
      +[](GstBus *bus, GstMessage *msg, gpointer data) -> gboolean {
        GMainLoop *loop = static_cast<GMainLoop *>(data);
        switch (GST_MESSAGE_TYPE(msg)) {
        case GST_MESSAGE_EOS:
          std::cout << "EOS" << std::endl;
          g_main_loop_quit(loop);
          break;
        case GST_MESSAGE_ERROR: {
          GError *err;
          gchar *debug_info;
          gst_message_parse_error(msg, &err, &debug_info);
          std::cerr << "Error from "
                    << (GST_OBJECT_NAME(msg->src) ? GST_OBJECT_NAME(msg->src)
                                                  : "None")
                    << ": " << err->message << " ("
                    << (debug_info ? debug_info : "") << ")" << std::endl;
          g_clear_error(&err);
          g_free(debug_info);
          g_main_loop_quit(loop);
          break;
        }
        default:
          break;
        }
        return TRUE; // Continue receiving messages
      },
      main_loop);

  // Run the main loop
  g_main_loop_run(main_loop);

  // Clean up
  gst_element_set_state(pipeline, GST_STATE_NULL);
  gst_object_unref(bus);
  gst_object_unref(pipeline);
  g_main_loop_unref(main_loop);

  return 0;
}

As you can see it uses the webrtcsink plugin. This is my CMakeLists.txt :

cmake_minimum_required(VERSION 3.10)
project(GStreamerRustPOC)

set(CMAKE_CXX_STANDARD 17)


# Add the include directory
find_package(PkgConfig REQUIRED)
# find_package(CUDA REQUIRED)
pkg_check_modules(GST REQUIRED gstreamer-1.0 gstreamer-video-1.0 gstreamer-app-1.0 gstreamer-pbutils-1.0 gstreamer-plugins-base-1.0 gstreamer-rtsp-server-1.0)

# include_directories(${CUDA_INCLUDE_DIRS})
include_directories(${GST_INCLUDE_DIRS})
link_directories(${GSTREAMER_LIBRARY_DIRS})

# Add executable
set(SOURCES
    main.cpp
)

# Add the executable target
add_executable(test ${SOURCES})

# Link the required libraries
target_link_libraries(test ${GST_LIBRARIES})

It seems to compile fine :

-- Detecting CXX compiler ABI info
ke-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found PkgConfig: /usr/bin/pkg-config (found version "0.29.2") 
-- Checking for modules 'gstreamer-1.0;gstreamer-video-1.0;gstreamer-app-1.0;gstreamer-pbutils-1.0;gstreamer-plugins-base-1.0;gstreamer-rtsp-server-1.0'
--   Found gstreamer-1.0, version 1.24.8.1
--   Found gstreamer-video-1.0, version 1.24.8.1
--   Found gstreamer-app-1.0, version 1.24.8.1
--   Found gstreamer-pbutils-1.0, version 1.24.8.1
--   Found gstreamer-plugins-base-1.0, version 1.24.8.1
--   Found gstreamer-rtsp-server-1.0, version 1.24.8.1
-- Configuring done
-- Generating done
-- Build files have been written to: /app/build
root@ubuntu:/app/build# make
[ 50%] Building CXX object CMakeFiles/test.dir/main.cpp.o
[100%] Linking CXX executable test
[100%] Built target test

However when I run it I get the following error :

0:00:00.003123024   127 0xaaaad77d38a0 ERROR     GST_PLUGIN_LOADING gstpluginloader.c:432:gst_plugin_loader_try_helper: Spawning gst-plugin-scanner helper failed: Failed to close file descriptor for child process (Operation not permitted)

(test:127): GStreamer-WARNING **: 12:15:55.450: External plugin loader failed. This most likely means that the plugin loader helper binary was not found or could not be run. You might need to set the GST_PLUGIN_SCANNER environment variable if your setup is unusual. This should normally not be required though.

(test:127): GLib-GObject-WARNING **: 12:15:55.492: cannot register existing type 'GstVideoScale'

(test:127): GLib-CRITICAL **: 12:15:55.492: g_once_init_leave: assertion 'result != 0' failed

(test:127): GStreamer-CRITICAL **: 12:15:55.492: gst_element_register: assertion 'g_type_is_a (type, GST_TYPE_ELEMENT)' failed
0:00:00.592721736   127 0xffff7c017690 ERROR             webrtcsink net/webrtc/src/webrtcsink/imp.rs:4358:gstrswebrtc::webrtcsink::imp::BaseWebRTCSink::start_stream_discovery_if_needed::{{closure}}:<webrtcsink> Error running discovery: No codec available for encoding stream video_0, check the webrtcsink logs and verify that the rtp plugin is available
Error from webrtcsink: There is no codec present that can handle the stream's type. (net/webrtc/src/webrtcsink/imp.rs(4359): gstrswebrtc::webrtcsink::imp::BaseWebRTCSink::start_stream_discovery_if_needed::{{closure}} (): /GstPipeline:webrtc-pipeline/GstWebRTCSink:webrtcsink:
Failed to look up output caps: No codec available for encoding stream video_0, check the webrtcsink logs and verify that the rtp plugin is available)

I have built the webrtc plugins using the following commands:

$ cargo cbuild -p gst-plugin-webrtc --prefix=/usr
$ cargo cinstall -p gst-plugin-webrtc --prefix=/usr

I have the same error when I try to run it from the command line :

gst-launch-1.0 videotestsrc ! webrtcsink run-signalling-server=true run-web-server=true
 
0:00:00.002916879    16 0xaaaaffdd1ea0 ERROR     GST_PLUGIN_LOADING gstpluginloader.c:432:gst_plugin_loader_try_helper: Spawning gst-plugin-scanner helper failed: Failed to close file descriptor for child process (Operation not permitted)

(gst-launch-1.0:16): GStreamer-WARNING **: 12:22:17.426: External plugin loader failed. This most likely means that the plugin loader helper binary was not found or could not be run. You might need to set the GST_PLUGIN_SCANNER environment variable if your setup is unusual. This should normally not be required though.

(gst-launch-1.0:16): GLib-GObject-WARNING **: 12:22:17.468: cannot register existing type 'GstVideoScale'

(gst-launch-1.0:16): GLib-CRITICAL **: 12:22:17.468: g_once_init_leave: assertion 'result != 0' failed

(gst-launch-1.0:16): GStreamer-CRITICAL **: 12:22:17.468: gst_element_register: assertion 'g_type_is_a (type, GST_TYPE_ELEMENT)' failed
Setting pipeline to PAUSED ...
Pipeline is live and does not need PREROLL ...
Pipeline is PREROLLED ...
Setting pipeline to PLAYING ...
New clock: GstSystemClock
0:00:00.587802939    16 0xffff78004700 ERROR             webrtcsink net/webrtc/src/webrtcsink/imp.rs:4358:gstrswebrtc::webrtcsink::imp::BaseWebRTCSink::start_stream_discovery_if_needed::{{closure}}:<webrtcsink0> Error running discovery: No codec available for encoding stream video_0, check the webrtcsink logs and verify that the rtp plugin is available
ERROR: from element /GstPipeline:pipeline0/GstWebRTCSink:webrtcsink0: There is no codec present that can handle the stream's type.
Additional debug info:
net/webrtc/src/webrtcsink/imp.rs(4359): gstrswebrtc::webrtcsink::imp::BaseWebRTCSink::start_stream_discovery_if_needed::{{closure}} (): /GstPipeline:pipeline0/GstWebRTCSink:webrtcsink0:
Failed to look up output caps: No codec available for encoding stream video_0, check the webrtcsink logs and verify that the rtp plugin is available
Redistribute latency...
Execution ended after 0:00:00.003018928
Setting pipeline to NULL ...
Freeing pipeline ...

It’s weird because it was running fine when I first tested this command.

It seems to be dependent on the rust rtp plugin so I build it aswell. Now the command line pipeline run but give me my webcam stream rather than the videotestsrc stream.

For the program I had an error about h264 stream so I added a videoconvert and I got the following error:

./test 
0:00:00.003007311   127 0xaaab05b958a0 ERROR     GST_PLUGIN_LOADING gstpluginloader.c:432:gst_plugin_loader_try_helper: Spawning gst-plugin-scanner helper failed: Failed to close file descriptor for child process (Operation not permitted)

(test:127): GStreamer-WARNING **: 12:48:53.363: External plugin loader failed. This most likely means that the plugin loader helper binary was not found or could not be run. You might need to set the GST_PLUGIN_SCANNER environment variable if your setup is unusual. This should normally not be required though.

(test:127): GLib-GObject-WARNING **: 12:48:53.405: cannot register existing type 'GstVideoScale'

(test:127): GLib-CRITICAL **: 12:48:53.405: g_once_init_leave: assertion 'result != 0' failed

(test:127): GStreamer-CRITICAL **: 12:48:53.405: gst_element_register: assertion 'g_type_is_a (type, GST_TYPE_ELEMENT)' failed
0:00:00.594917006   127 0xffffa402b690 ERROR             webrtcsink net/webrtc/src/webrtcsink/imp.rs:4358:gstrswebrtc::webrtcsink::imp::BaseWebRTCSink::start_stream_discovery_if_needed::{{closure}}:<webrtcsink> Error running discovery: No codec available for encoding stream video_0, check the webrtcsink logs and verify that the rtp plugin is available
Error from webrtcsink: There is no codec present that can handle the stream's type. (net/webrtc/src/webrtcsink/imp.rs(4359): gstrswebrtc::webrtcsink::imp::BaseWebRTCSink::start_stream_discovery_if_needed::{{closure}} (): /GstPipeline:webrtc-pipeline/GstWebRTCSink:webrtcsink:
Failed to look up output caps: No codec available for encoding stream video_0, check the webrtcsink logs and verify that the rtp plugin is available)

This suggests that multiple versions of GStreamer are available on your system, and two of them are loaded into the same process and cause these issues. You should check your environment setup.

I believe I fixed the mistake on the environment but I still get this error :

gst-launch-1.0 videotestsrc ! webrtcsink run-signalling-server=true run-web-server=true
0:00:00.020047982    31 0xaaab134f5470 ERROR     GST_PLUGIN_LOADING gstpluginloader.c:432:gst_plugin_loader_try_helper: Spawning gst-plugin-scanner helper failed: Failed to close file descriptor for child process (Operation not permitted)

(gst-launch-1.0:31): GStreamer-WARNING **: 15:42:45.680: External plugin loader failed. This most likely means that the plugin loader helper binary was not found or could not be run. You might need to set the GST_PLUGIN_SCANNER environment variable if your setup is unusual. This should normally not be required though.
0:00:00.048903253    31 0xaaab134f5470 ERROR           GST_PIPELINE subprojects/gstreamer/gst/parse/grammar.y:686:gst_parse_element_make: no property "run-signalling-server" in element "webrtcsink"
0:00:00.048958998    31 0xaaab134f5470 ERROR           GST_PIPELINE subprojects/gstreamer/gst/parse/grammar.y:1330:priv_gst_parse_yyparse: link has no sink [source=@0xaaab136b3670]
WARNING: erroneous pipeline: no property "run-signalling-server" in element "webrtcsink"
root@ubuntu:/opt/gst-plugins-rs/net/webrtc# ls
Cargo.toml       README.md  examples       node_modules       package.json  signalling
LICENSE-MPL-2.0  build.rs   gstwebrtc-api  package-lock.json  protocol      src

This is the dockerfile I am using:


FROM ubuntu:22.04


ENV DEBIAN_FRONTEND=noninteractive



ENV ARCH=x86_64

# Install necessary dependencies
RUN ln -fs /usr/share/zoneinfo/$TZ /etc/localtime && \
    apt-get update && \
    apt-get install -y \
        tzdata \
        build-essential \
        ninja-build \
        git \
        python3 \
        python3-pip \
        python3-setuptools \
        cmake \
        pkg-config \
        flex \
        bison \
        libglib2.0-dev \
        libdrm-dev \
        libssl-dev \
        libclang-dev \
        clang \
        curl \
        wget \
        software-properties-common \
        ca-certificates \
        gnupg \
        libgtk-3-dev \
        libpango1.0-dev \
        libsoup2.4-dev \
        libnice-dev \
        libopus-dev \
        libvpx-dev \
        libx264-dev \
        libsrtp2-dev && \
    dpkg-reconfigure --frontend noninteractive tzdata

# Upgrade pip and install Meson using pip
RUN python3 -m pip install --upgrade pip && \
    python3 -m pip install meson

# Install Rust using rustup
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y && \
    /root/.cargo/bin/rustup install stable && \
    /root/.cargo/bin/rustup default stable

# Add Rust's Cargo bin directory to PATH
ENV PATH="/root/.cargo/bin:${PATH}"


RUN cargo install cargo-c

RUN git clone --depth 1 --branch 1.24 https://gitlab.freedesktop.org/gstreamer/gstreamer.git /opt/gstreamer


RUN cd /opt/gstreamer && \
    meson setup builddir --prefix=/usr && \
    meson compile -C builddir && \
    meson install -C builddir && \
    ldconfig

RUN git clone https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs /opt/gst-plugins-rs && cd /opt/gst-plugins-rs && git checkout 0.13

RUN cd /opt/gst-plugins-rs/net/webrtc && cargo cbuild -p gst-plugin-webrtc --prefix=/usr && cargo cinstall -p gst-plugin-webrtc --prefix=/usr

RUN curl -sL https://deb.nodesource.com/setup_18.x -o nodesource_setup.sh && \
    bash nodesource_setup.sh && \
    apt-get install -y nodejs 

RUN cd /opt/gst-plugins-rs/net/webrtc/gstwebrtc-api && npm install

RUN cd /opt/gst-plugins-rs/net/webrtc && npm install rimraf && npm install webpack && npm install -D webpack-cli && cargo build &&  npm --prefix gstwebrtc-api/ run make


ENV GST_PLUGIN_PATH=/usr/lib/aarch64-linux-gnu/gstreamer-1.0
ENV LD_LIBRARY_PATH=/usr/lib/${ARCH}-linux-gnu
ENV GST_PLUGIN_SCANNER=/usr/lib/aarch64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner


RUN if [ -f "$GST_PLUGIN_SCANNER" ]; then echo "gst-plugin-scanner found at $GST_PLUGIN_SCANNER"; else echo "gst-plugin-scanner not found!"; fi

RUN mkdir /app
WORKDIR /app
COPY . .


CMD ["gst-launch-1.0", "--version"]

Maybe there is an official docker version for GStreamer that I missed or an already built image ? (for the plugins or gstreamer)

I changed the branch to 0.13 for the rust plugins maybe that wasn’t a good idea. I’m testing with main and this is what I get :

gst-launch-1.0 videotestsrc ! webrtcsink run-signalling-server=true r
un-web-server=true                                                                                               
0:00:00.002582196    18 0xaaaae63d8aa0 ERROR     GST_PLUGIN_LOADING gstpluginloader.c:432:gst_plugin_loader_try_h
elper: Spawning gst-plugin-scanner helper failed: Failed to close file descriptor for child process (Operation not permitted)                                                                                                     
                            
(gst-launch-1.0:18): GStreamer-WARNING **: 16:28:30.423: External plugin loader failed. This most likely means th
at the plugin loader helper binary was not found or could not be run. You might need to set the GST_PLUGIN_SCANNER environment variable if your setup is unusual. This should normally not be required though.
Setting pipeline to PAUSED ...
Pipeline is live and does not need PREROLL ...
Pipeline is PREROLLED ...                               
Setting pipeline to PLAYING ... 
New clock: GstSystemClock                               
Redistribute latency... 
0:00:00.471205558    18 0xffffb4014210 ERROR             webrtcsink net/webrtc/src/webrtcsink/imp.rs:4358:gstrswe
brtc::webrtcsink::imp::BaseWebRTCSink::start_stream_discovery_if_needed::{{closure}}:<webrtcsink0> Error running 
discovery: No codec available for encoding stream video_0, check the webrtcsink logs and verify that the rtp plug
in is available                                         
ERROR: from element /GstPipeline:pipeline0/GstWebRTCSink:webrtcsink0: There is no codec present that can handle t
he stream's type.                                       
Additional debug info:                                                                                           
net/webrtc/src/webrtcsink/imp.rs(4359): gstrswebrtc::webrtcsink::imp::BaseWebRTCSink::start_stream_discovery_if_n
eeded::{{closure}} (): /GstPipeline:pipeline0/GstWebRTCSink:webrtcsink0:
Failed to look up output caps: No codec available for encoding stream video_0, check the webrtcsink logs and veri
fy that the rtp plugin is available
Execution ended after 0:00:00.003264889
Setting pipeline to NULL ... 
Freeing pipeline ...

I get the same behavior, for the command line, the streams run with a few errors, and I get the webcam streams on the web server rather than the videotestsrc:

gst-launch-1.0 videotestsrc ! webrtcsink run-signalling-server=true run-web-server=true
0:00:00.020066048   136 0xaaaadf791470 ERROR     GST_PLUGIN_LOADING gstpluginloader.c:432:gst_plugin_loader_try_helper: Spawning gst-plugin-scanner helper failed: Failed to close file descriptor for child process (Operation not permitted)

(gst-launch-1.0:136): GStreamer-WARNING **: 16:48:27.293: External plugin loader failed. This most likely means that the plugin loader helper binary was not found or could not be run. You might need to set the GST_PLUGIN_SCANNER environment variable if your setup is unusual. This should normally not be required though.
Setting pipeline to PAUSED ...
Pipeline is live and does not need PREROLL ...
Pipeline is PREROLLED ...
Setting pipeline to PLAYING ...
New clock: GstSystemClock
Redistribute latency...
0:00:00.220586568   136 0xffffa00850a0 ERROR             webrtcsink net/webrtc/src/webrtcsink/imp.rs:1822:gstrswebrtc::webrtcsink::imp::BaseWebRTCSink::configure_congestion_control:<webrtcsink0> Bitrate handling is not supported yet for openh264enc
2024-10-04T14:48:27.743755Z  INFO ThreadId(01) gst_plugin_webrtc_signalling::server: New WebSocket connection this_id=6e3a9076-389c-4706-a2e5-e532a547b616
2024-10-04T14:48:27.744134Z  INFO ThreadId(01) gst_plugin_webrtc_signalling::server: Received message Ok(Text("{\"type\":\"setPeerStatus\",\"roles\":[\"producer\"],\"meta\":null,\"peerId\":\"6e3a9076-389c-4706-a2e5-e532a547b616\"}"))
2024-10-04T14:48:27.744200Z  INFO ThreadId(01) gst_plugin_webrtc_signalling::handlers: registered as a producer peer_id=6e3a9076-389c-4706-a2e5-e532a547b616
^Chandling interrupt.
Interrupt: Stopping pipeline ...
Execution ended after 0:00:01.706935801
Setting pipeline to NULL ...
2024-10-04T14:48:29.036526Z  INFO ThreadId(01) gst_plugin_webrtc_signalling::server: Received message Ok(Close(None))
2024-10-04T14:48:29.036565Z  INFO ThreadId(01) gst_plugin_webrtc_signalling::server: connection closed: None this_id=6e3a9076-389c-4706-a2e5-e532a547b616
2024-10-04T14:48:29.036704Z  INFO ThreadId(01) gst_plugin_webrtc_signalling::handlers: removing peer peer_id=6e3a9076-389c-4706-a2e5-e532a547b616
Freeing pipeline ...

For the app it still doesn’t run:

./test 
0:00:00.020957226   148 0xaaaaf98d0470 ERROR     GST_PLUGIN_LOADING gstpluginloader.c:432:gst_plugin_loader_try_helper: Spawning gst-plugin-scanner helper failed: Failed to close file descriptor for child process (Operation not permitted)

(test:148): GStreamer-WARNING **: 16:49:35.374: External plugin loader failed. This most likely means that the plugin loader helper binary was not found or could not be run. You might need to set the GST_PLUGIN_SCANNER environment variable if your setup is unusual. This should normally not be required though.
0:00:00.222202078   148 0xffff88068810 ERROR             webrtcsink net/webrtc/src/webrtcsink/imp.rs:1822:gstrswebrtc::webrtcsink::imp::BaseWebRTCSink::configure_congestion_control:<webrtcsink> Bitrate handling is not supported yet for openh264enc
Error from webrtcsink: GStreamer encountered a general stream error. (net/webrtc/src/webrtcsink/imp.rs(2400): gstrswebrtc::webrtcsink::imp::BaseWebRTCSink::connect_signaller::{{closure}}::{{closure}} (): /GstPipeline:webrtc-pipeline/GstWebRTCSink:webrtcsink:
Signalling error: Error receiving: IO error: Connection refused (os error 111))