RTSP Server (GStreamer) on Jetson Orin – Only one VLC client works with shared pipeline (appsrc + nvv4l2h264enc)

Hi,

I am facing an issue on Jetson AGX Orin where an RTSP stream works with only one client, but fails (or does not play properly) when a second VLC client connects.

This behavior appears specific to Orin or nvv4l2h264enc


Setup

  • Platform: Jetson AGX Orin

  • JetPack: (please fill your version, e.g. 6.0 / 5.1.2)

  • GStreamer: (gst-launch-1.0 --version)

  • Encoder: nvv4l2h264enc


RTSP Pipeline

gst_rtsp_media_factory_set_launch(factory,
"( appsrc name=mysrc is-live=true format=time ! \
   video/x-raw, format=I420 ! \
   nvvidconv ! video/x-raw(memory:NVMM),format=I420 ! \
   nvv4l2h264enc insert-sps-pps=true bitrate=5000000 iframeinterval=30 ! \
   h264parse ! rtph264pay config-interval=1 name=pay0 pt=96 )");

gst_rtsp_media_factory_set_shared(factory, TRUE);


Observed Behavior

  • First VLC client: works correctly

  • Second VLC client:

    • Does not play / freezes / fails to start

    • Server logs show warnings related to suspend/resume

Hi,
In Jetson AGX Orin FAQ we have the example of using test-launch. And this sample seems to support only single client. There are other samples such as test-mp4, test-appsrc, test-appsrc2. You may give them a try.

You could try and add some queue elements before/after the encoder. There might be some latency in the pipeline that is affecting the stream. You could also check if adding this option helps with the instability:

gst_rtsp_media_factory_set_suspend_mode(factory, GST_RTSP_SUSPEND_MODE_NONE);

This will make the RTSP pipeline always run, even without clients, but I will make it more stable when a new client connects.

Jafet Garcia
Embedded SW Engineer at RidgeRun
Contact us: support@ridgerun.com
Developers wiki: https://developer.ridgerun.com
Website: www.ridgerun.com

tied these sample apps. they are not working with multiple rtsp clients when fps is set to 30 or 50. default fps is set to 0 in these sample apps. this issue specific to orin only. on earlier jetsons this issue was not there.

tried this.but didnt help. gst_rtsp_media_factory_set_suspend_mode(factory, GST_RTSP_SUSPEND_MODE_NONE);

tied these gstreamer sample apps. they are not working with multiple rtsp clients when fps is set to 30 or 50. default fps is set to 0 in these sample apps. this issue specific to orin only. on earlier jetsons this issue was not there.

sample apps are using x264enc. when I replaced it with nvv4l2h264enc. its not working with more than 1 rtsp clients?

is this a gstreamer issue?

tonbo@tonbo-desktop:~/wolfpack/src$ gst-launch-1.0 --version
pkg-config --modversion gstreamer-1.0
pkg-config --modversion gstreamer-rtsp-server-1.0
gst-launch-1.0 version 1.20.3
GStreamer 1.20.3
1.20.3
1.20.1

sample apps are using x264enc. when I replaced it with nvv4l2h264enc and fps to 30 or 50. its not working with more than 1 rtsp clients. please suggest the pipeline changes. or this is a known issue on orin with shared pipeline?

i am not able to play multiple vlc and ffplay clients with this pipeline as well which is shared on other related posts on forum? .

$ GST_DEBUG=3 ./test-launch "videotestsrc ! video/x-raw,format=YUY2,width=640,height=480,framerate=30/1 ! nvvidconv ! video/x-raw(memory:NVMM),format=(string)I420 ! nvv4l2h264enc ! h264parse ! rtph264pay name=pay0 pt=96"

Hi,
Loos like the samples of 1.20 are moved to gitlab site:
Making sure you're not a bot!

And may try test-multicast.c or test-multicast2.c

We try test-launch as server on AGX Orin developer kit/Jetpack 6.2.2 r36.5, and can connect two clients, as shown in the screenshot:

Hi DaneLLL,

my implementation uses appsrc similar to test-appsrc. but need_data function is designed like this. but this is working only with single rtsp client.

static void need_data (GstElement * appsrc, guint unused, MyContext * ctx)
{
GstBuffer *buffer;
guint size;
GstMapInfo info;
GstFlowReturn ret;

size = ctx->buffer_size;

buffer = gst_buffer_new_allocate (NULL, size, NULL);

gst_buffer_map(buffer, &info, GST_MAP_WRITE);

GstRTSP *pointer = (GstRTSP *)ctx->ptr;

unsigned char *img;

pointer->UnGetImage();
img = pointer->GetImage();

memmove(info.data, img, size);

gst_buffer_unmap(buffer, &info);

//gst_buffer_memset(buffer, 0, ctx->white ? 0xff : 0x00, size);
//ctx->white = !ctx->white;
GST_BUFFER_PTS (buffer) = ctx->timestamp;
GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale_int (1, GST_SECOND, 30);
ctx->timestamp += GST_BUFFER_DURATION (buffer);

g_signal_emit_by_name (appsrc, “push-buffer”, buffer, &ret);

gst_buffer_unref(buffer);
}

Frames come from a producer-consumer queue:

  • camera Capture thread pushes frames into queue at 30/50 fps.

  • need_data() pulls frames using:


frame = GetImage();   // fetch from queue
...
UnGetImage(frame);    // return/release buffer

gstreamer launch pipeline.

"( appsrc name=mysrc is-live=true format=time "
"! video/x-raw,format=I420,width=1920,height=1080,framerate=30/1 "
"! nvvidconv ! video/x-raw(memory:NVMM),format=I420 "
"! nvv4l2h264enc insert-sps-pps=1 idrinterval=30 bitrate=20000000 "
“! h264parse ! rtph264pay config-interval=1 name=pay0 pt=96 )”