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))