DeepStream nvmultiurisrcbin Aborted (core dumped) when adding stream via REST API

I ran another test to verify whether nvmultiurisrcbin works properly. First, I created a simple pipeline using the following gst-launch-1.0 command that I had executed and tested before:

gst-launch-1.0 nvmultiurisrcbin port=9456 ip-address=localhost   batched-push-timeout=33333 max-batch-size=10 drop-pipeline-eos=1   rtsp-reconnect-interval=1 live-source=1 width=1920 height=1080 !   nvmultistreamtiler ! fakesink async=false

Then, I reproduced the same logic in C++:

#include <gst/gst.h>

#include <iostream>
#include <string>

class PipelineManager {
   private:
    GstElement *pipeline;
    GstElement *nvmultiurisrcbin;
    GstElement *nvmultistreamtiler;
    GstElement *fakesink;
    GMainLoop *main_loop;

   public:
    PipelineManager()
        : pipeline(nullptr),
          nvmultiurisrcbin(nullptr),
          nvmultistreamtiler(nullptr),
          fakesink(nullptr),
          main_loop(nullptr) {}

    ~PipelineManager() { cleanup(); }

    bool create_pipeline() {
        // Initialize GStreamer
        gst_init(nullptr, nullptr);

        // Create elements
        pipeline = gst_pipeline_new("multi-uri-pipeline");
        if (!pipeline) {
            std::cerr << "Failed to create pipeline" << std::endl;
            return false;
        }

        nvmultiurisrcbin =
            gst_element_factory_make("nvmultiurisrcbin", "nvmultiurisrcbin");
        if (!nvmultiurisrcbin) {
            std::cerr << "Failed to create nvmultiurisrcbin" << std::endl;
            return false;
        }

        nvmultistreamtiler = gst_element_factory_make("nvmultistreamtiler",
                                                      "nvmultistreamtiler");
        if (!nvmultistreamtiler) {
            std::cerr << "Failed to create nvmultistreamtiler" << std::endl;
            return false;
        }

        fakesink = gst_element_factory_make("fakesink", "fakesink");
        if (!fakesink) {
            std::cerr << "Failed to create fakesink" << std::endl;
            return false;
        }

        // Add elements to pipeline
        gst_bin_add_many(GST_BIN(pipeline), nvmultiurisrcbin,
                         nvmultistreamtiler, fakesink, nullptr);

        // Set properties for nvmultiurisrcbin
        g_object_set(G_OBJECT(nvmultiurisrcbin), "port", "9456", nullptr);
        g_object_set(G_OBJECT(nvmultiurisrcbin), "ip-address", "localhost",
                     nullptr);
        g_object_set(G_OBJECT(nvmultiurisrcbin), "batched-push-timeout", 33333,
                     nullptr);
        g_object_set(G_OBJECT(nvmultiurisrcbin), "max-batch-size", 10, nullptr);
        g_object_set(G_OBJECT(nvmultiurisrcbin), "drop-pipeline-eos", 1,
                     nullptr);
        g_object_set(G_OBJECT(nvmultiurisrcbin), "rtsp-reconnect-interval", 1,
                     nullptr);
        g_object_set(G_OBJECT(nvmultiurisrcbin), "live-source", 1, nullptr);
        g_object_set(G_OBJECT(nvmultiurisrcbin), "width", 1920, nullptr);
        g_object_set(G_OBJECT(nvmultiurisrcbin), "height", 1080, nullptr);

        // Try setting a config file that enables REST API
        // g_object_set(G_OBJECT(nvmultiurisrcbin), "config-file-path",
        // "/etc/deepstream/rest_api.conf", NULL);
        g_object_set(G_OBJECT(nvmultiurisrcbin), "uri-list",
                     "file:///root/Put.mp4", NULL);
        // g_object_set(G_OBJECT(nvmultiurisrcbin), "rtsp-reconnect-attempts",
        // 10, NULL);
        g_object_set(G_OBJECT(nvmultiurisrcbin), "drop-frame-interval", 5,
                     NULL);  // Skip frames if decoding lags behind.
        g_object_set(G_OBJECT(nvmultiurisrcbin), "file-loop", FALSE, NULL);
        g_object_set(G_OBJECT(nvmultiurisrcbin), "gpu-id", 0, NULL);
        g_object_set(
            G_OBJECT(nvmultiurisrcbin), "cudadec-memtype", 0,
            NULL);  // Memory type for CUDA decoding (0=default,
                    // 1=NVBUF_MEM_CUDA_PINNED, 2=NVBUF_MEM_CUDA_DEVICE,
                    // 3=NVBUF_MEM_CUDA_UNIFIED).
        g_object_set(G_OBJECT(nvmultiurisrcbin), "latency", 200,
                     NULL);  // Network jitter buffer latency (milliseconds).
                             // Used for RTSP.
        g_object_set(G_OBJECT(nvmultiurisrcbin), "sensor-id-list",
                     "UniqueSensorId1", NULL);
        g_object_set(G_OBJECT(nvmultiurisrcbin), "sensor-name-list",
                     "UniqueSensorName1", NULL);
        g_object_set(G_OBJECT(nvmultiurisrcbin), "buffer-pool-size", 16, NULL);
        g_object_set(G_OBJECT(nvmultiurisrcbin), "disable-audio", TRUE, NULL);

        // Set properties for fakesink
        g_object_set(G_OBJECT(fakesink), "async", FALSE, nullptr);

        // Link elements
        if (!gst_element_link_many(nvmultiurisrcbin, nvmultistreamtiler,
                                   fakesink, nullptr)) {
            std::cerr << "Failed to link elements" << std::endl;
            return false;
        }

        return true;
    }

    bool start_pipeline() {
        // Set pipeline to PLAYING state
        GstStateChangeReturn ret =
            gst_element_set_state(pipeline, GST_STATE_PLAYING);
        if (ret == GST_STATE_CHANGE_FAILURE) {
            std::cerr << "Failed to start pipeline" << std::endl;
            return false;
        }

        // Create and run main loop
        main_loop = g_main_loop_new(nullptr, FALSE);

        // Add bus watch for messages
        GstBus *bus = gst_element_get_bus(pipeline);
        gst_bus_add_watch(bus, bus_callback, this);
        gst_object_unref(bus);

        std::cout << "Pipeline started successfully" << std::endl;
        std::cout << "REST server available at: http://localhost:9456"
                  << std::endl;

        g_main_loop_run(main_loop);

        return true;
    }

    void stop_pipeline() {
        if (pipeline) {
            gst_element_set_state(pipeline, GST_STATE_NULL);
        }
        if (main_loop) {
            g_main_loop_quit(main_loop);
        }
    }

    void cleanup() {
        if (pipeline) {
            gst_object_unref(pipeline);
            pipeline = nullptr;
        }
        if (main_loop) {
            g_main_loop_unref(main_loop);
            main_loop = nullptr;
        }
    }

   private:
    static gboolean bus_callback(GstBus *bus, GstMessage *msg, gpointer data) {
        (void)bus;
        PipelineManager *self = static_cast<PipelineManager *>(data);

        switch (GST_MESSAGE_TYPE(msg)) {
            case GST_MESSAGE_ERROR: {
                gchar *debug;
                GError *error;
                gst_message_parse_error(msg, &error, &debug);
                std::cerr << "Error: " << error->message << std::endl;
                if (debug) {
                    std::cerr << "Debug info: " << debug << std::endl;
                }
                g_error_free(error);
                g_free(debug);
                self->stop_pipeline();
                break;
            }
            case GST_MESSAGE_EOS:
                std::cout << "End of stream" << std::endl;
                self->stop_pipeline();
                break;
            case GST_MESSAGE_STATE_CHANGED: {
                if (GST_MESSAGE_SRC(msg) == GST_OBJECT(self->pipeline)) {
                    GstState old_state, new_state, pending;
                    gst_message_parse_state_changed(msg, &old_state, &new_state,
                                                    &pending);
                    std::cout << "Pipeline state changed from "
                              << gst_element_state_get_name(old_state) << " to "
                              << gst_element_state_get_name(new_state)
                              << std::endl;
                }
                break;
            }
            default:
                break;
        }
        return TRUE;
    }
};

int main(int argc, char *argv[]) {
    (void)argc;
    (void)argv;
    PipelineManager pipeline_manager;

    // Create pipeline
    if (!pipeline_manager.create_pipeline()) {
        std::cerr << "Failed to create pipeline" << std::endl;
        return -1;
    }

    // Start pipeline
    if (!pipeline_manager.start_pipeline()) {
        std::cerr << "Failed to start pipeline" << std::endl;
        return -1;
    }

    // Cleanup
    pipeline_manager.cleanup();

    return 0;
}

I tested adding another stream via curl:

curl -v -XPOST 'http://localhost:9456/api/v1/stream/add' -d '{
    "key": "sensor",
    "value": {
        "camera_id": "uniqueSensorID2",
        "camera_name": "front_door_1",
        "camera_url": "file:///root/P.mp4",
        "change": "camera_add",
        "metadata": {
            "resolution": "1920 x1080",
            "codec": "h264",
            "framerate": 30
        }
    },
    "headers": {
        "source": "vst",
        "created_at": "2021-06-01T14:34:13.417Z"
    }
}'

Program output:

Civetweb version: v1.16
Server running at port: 9456
Pipeline started successfully
REST server available at: http://localhost:9456
Pipeline state changed from NULL to READY
Pipeline state changed from READY to PAUSED
Failed to query video capabilities: Invalid argument
Pipeline state changed from PAUSED to PLAYING
uri:/api/v1/stream/add
method:POST
Failed to query video capabilities: Invalid argument
nvstreammux: Successfully handled EOS for source_id=1
nvstreammux: Successfully handled EOS for source_id=0

Curl response:

Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 127.0.0.1:9456...
* Connected to localhost (127.0.0.1) port 9456 (#0)
> POST /api/v1/stream/add HTTP/1.1
> Host: localhost:9456
> User-Agent: curl/7.81.0
> Accept: */*
> Content-Length: 427
> Content-Type: application/x-www-form-urlencoded
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Access-Control-Allow-Origin: *
< Content-Type: text/plain
< Content-Length: 67
< Connection: close
< 
{
	"reason" : "STREAM_ADD_SUCCESS",
	"status" : "HTTP/1.1 200 OK"
* Closing connection 0

This confirms that I was able to successfully add another stream.

As an additional note: in my main project I also use Prometheus for performance monitoring. Could that have any side effects on the behavior of nvmultiurisrcbin or REST server?

Finally, here’s the relevant part of my main pipeline structure for context:


if (sink_manager->display_output < 3) {
    gst_bin_add_many(GST_BIN(pipeline),
                     nv_infer_server_manager->primary_detector,
                     nv_tracker_manager->tracker,
                     face_nv_infer_server_manager->face_detector,
                     // gstds_example_manager->custom_plugin,
                     tiler_manager->tiler, queue_array[2].queue,
                     nv_video_convert_manager->nvvidconv, nv_osd_manager->nvosd,
                     sink_manager->sink, NULL);

    /* we link the elements together
     * nvstreammux -> nvinfer -> nvtiler -> nvvidconv -> nvosd ->
     * video-renderer */
    if (!gst_element_link_many(  // streammux_manager->streammux,
            SourceBin::nvmultiurisrcbin, nv_video_convert_manager->nvvidconv,
            nv_infer_server_manager->primary_detector,
            nv_tracker_manager->tracker,
            face_nv_infer_server_manager->face_detector,
            //    gstds_example_manager->custom_plugin,
            tiler_manager->tiler, nv_osd_manager->nvosd, sink_manager->sink,
            NULL)) {
        g_printerr("Elements could not be linked.\n");
        return false;
    }
} else {
    gst_bin_add_many(
        GST_BIN(pipeline), nv_infer_server_manager->primary_detector,
        nv_tracker_manager->tracker,
        face_nv_infer_server_manager->face_detector,
        // gstds_example_manager->custom_plugin,
        tiler_manager->tiler, queue_array[2].queue,
        nv_video_convert_manager->nvvidconv, nv_osd_manager->nvosd,
        sink_manager->nvvidconv_postosd, sink_manager->caps,
        sink_manager->encoder, sink_manager->rtppay, sink_manager->sink, NULL);

    //            Link the elements together:
    //            file-source -> h264-parser -> nvh264-decoder ->
    //            nvinfer -> nvvidconv -> nvosd -> nvvidconv_postosd ->
    //            caps -> encoder -> rtppay -> udpsink
    if (!gst_element_link_many(  // streammux_manager->streammux,
            SourceBin::nvmultiurisrcbin, nv_video_convert_manager->nvvidconv,
            nv_infer_server_manager->primary_detector,
            nv_tracker_manager->tracker,
            face_nv_infer_server_manager->face_detector,
            // gstds_example_manager->custom_plugin,
            tiler_manager->tiler, nv_osd_manager->nvosd,
            sink_manager->nvvidconv_postosd, sink_manager->caps,
            sink_manager->encoder, sink_manager->rtppay, sink_manager->sink,
            NULL)) {
        g_printerr("Elements could not be linked.\n");
        return false;
    }
}