RTSP Streaming and video saving

Hello Everyone,

i have a query regarding the streaming and saving the video simultaneously.
My current code starts recording when streaming starts, but I want to make it independent. It should start recording the stream when the “start” command is received over a nano message and stop vice versa. i cant make two separate pipelines for both streaming and recording as it may increase the overhead on the device (two times encoding). any suggestion on how to start/stop recording regardless of the streaming activity.

#include <gst/gst.h>
#include <gst/rtsp-server/rtsp-server.h>
#include <nng/nng.h>
#include <nng/protocol/pair0/pair.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>

#define RTSP_PORT "8554"
#define RTSP_MOUNT_POINT "/stream"
#define RECORDING_FILE "/home/video_p.mkv"
#define NNG_SOCKET "ipc:///tmp/pipeline-control"

static gboolean recording = FALSE;
static GstElement *pipeline = NULL;
static GstElement *filesink = NULL;

static void start_recording() {
    if (recording || !filesink) return;
    g_print("Starting recording...\n");
    g_object_set(filesink, "location", RECORDING_FILE, NULL);
    recording = TRUE;
}

static void stop_recording() {
    if (!recording || !filesink) return;
    g_print("Stopping recording...\n");
    g_object_set(filesink, "location", "/dev/null", NULL);
    recording = FALSE;
}

static void *nng_listener_thread(void *arg) {
    nng_socket sock;
    nng_msg *msg;
    int rv;

    rv = nng_pair0_open(&sock);
    if (rv != 0) {
        fprintf(stderr, "Error opening NNG socket: %s\n", nng_strerror(rv));
        return NULL;
    }

    if ((rv = nng_listen(sock, NNG_SOCKET, NULL, 0)) != 0) {
        fprintf(stderr, "Error binding NNG IPC socket: %s\n", nng_strerror(rv));
        nng_close(sock);
        return NULL;
    }

    g_print("NNG Server Listening on %s\n", NNG_SOCKET);

    while (1) {
        rv = nng_recvmsg(sock, &msg, 0);
        if (rv != 0) {
            fprintf(stderr, "Error receiving NNG message: %s\n", nng_strerror(rv));
            continue;
        }

        char *message = (char *)nng_msg_body(msg);
        if (strcmp(message, "start") == 0) {
            start_recording();
        } else if (strcmp(message, "stop") == 0) {
            stop_recording();
        } else {
            g_print("Unknown command: %s\n", message);
        }

        nng_msg_free(msg);
    }

    nng_close(sock);
    return NULL;
}

static void media_configure(GstRTSPMediaFactory *factory, GstRTSPMedia *media, gpointer user_data) {
    pipeline = gst_rtsp_media_get_element(media);
    filesink = gst_bin_get_by_name(GST_BIN(pipeline), "fsink");
    g_print("Pipeline initialized!\n");
    gst_object_unref(pipeline);
}

static void start_rtsp_server(void) {
    GMainLoop *loop;
    GstRTSPServer *server;
    GstRTSPMountPoints *mounts;
    GstRTSPMediaFactory *factory;

    gst_init(NULL, NULL);
    loop = g_main_loop_new(NULL, FALSE);

    server = gst_rtsp_server_new();
    gst_rtsp_server_set_service(server, RTSP_PORT);

    mounts = gst_rtsp_server_get_mount_points(server);
    factory = gst_rtsp_media_factory_new();

gst_rtsp_media_factory_set_launch(factory,
    "( v4l2src ! video/x-raw,format=NV12,width=960,height=720,framerate=30/1 ! "
    "tee name=t "
    "t. ! queue ! videoconvert ! mpph265enc ! h265parse ! rtph265pay pt=96 name=pay0 config-interval=1 "
    "t. ! queue ! videoconvert ! mpph265enc ! h265parse ! mux. "
    "alsasrc ! queue ! audio/x-raw,rate=44100,channels=2 ! audioconvert ! voaacenc bitrate=320000 ! aacparse ! tee name=audiotee "
    "audiotee. ! queue ! rtpmp4apay pt=97 name=pay1 "
    "audiotee. ! queue ! mux. "
    "matroskamux name=mux ! filesink location=" RECORDING_FILE " sync=false )");

    gst_rtsp_media_factory_set_shared(factory, TRUE);
    g_signal_connect(factory, "media-configure", (GCallback)media_configure, NULL);

    gst_rtsp_mount_points_add_factory(mounts, RTSP_MOUNT_POINT, factory);
    g_object_unref(mounts);

    gst_rtsp_server_attach(server, NULL);

    g_print("RTSP Stream available at rtsp://<RK3576_IP>:%s%s\n", RTSP_PORT, RTSP_MOUNT_POINT);
    g_print("Recording to file: %s\n", RECORDING_FILE);

    g_main_loop_run(loop);
}

int main(int argc, char *argv[]) {
    pthread_t nng_thread;
    if (pthread_create(&nng_thread, NULL, nng_listener_thread, NULL) != 0) {
        fprintf(stderr, "Failed to create NNG listener thread.\n");
        return 1;
    }

    start_rtsp_server();
    pthread_join(nng_thread, NULL);
    return 0;
}

Regards.

You can add a filter element ( or Pass through).
The filter element should have one sink pad and two src pads.
One src pad will be connected to sink and other is connected to filesrc to dump your recording content.

By default when you start the playback, the content will be dropped and won’t be dumped. Make application to trigger a custom event (START_RECORDING). when the filter element receives this it starts dumping the data to file. when the STOP_RECORDING event is sent, it stops dumping…