Hi all,
I’m working on a multi-camera streaming setup using 4 ZED cameras connected via GMSL2 to a Jetson Orin NX 16GB running JetPack 6.0.
My goal is to stream 1080p@30FPS per camera to a desktop PC equipped with a 4060Ti, which handles the processing. I’m not doing any depth computation on the Jetson – it’s strictly acting as a streaming source.
The Jetson is configured with:
sudo nvpmodel -m 0
sudo jetson_clocks
- JetPack 6.0
I’m using H.265 streaming with bitrate = 5000
, chunk_size = 4096
, and adaptive_bitrate = true
.
Here is the simplified version of the streaming code I’m using:
#include <sl/Camera.hpp>
#include <thread>
#include <vector>
#include <atomic>
#include <csignal>
#include <iostream>
using namespace sl;
using namespace std;
static atomic<bool> exit_flags[4];
void signalHandler(int) {
for (auto &flag : exit_flags) flag.store(true);
}
void streamThread(int camID, int port) {
Camera zed;
InitParameters init_params;
init_params.camera_resolution = RESOLUTION::HD1080;
init_params.depth_mode = DEPTH_MODE::NONE;
init_params.camera_fps = 30;
init_params.input.setFromCameraID(camID);
if (zed.open(init_params) != ERROR_CODE::SUCCESS) return;
StreamingParameters stream_params;
stream_params.port = port;
stream_params.codec = STREAMING_CODEC::H265;
stream_params.bitrate = 5000;
stream_params.chunk_size = 4096;
stream_params.adaptative_bitrate = true;
if (zed.enableStreaming(stream_params) != ERROR_CODE::SUCCESS) {
zed.close();
return;
}
RuntimeParameters runtime_params;
runtime_params.enable_depth = false;
while (!exit_flags[camID].load()) {
auto t0 = chrono::high_resolution_clock::now();
if (zed.grab(runtime_params) == ERROR_CODE::SUCCESS) {
auto t1 = chrono::high_resolution_clock::now();
auto ms = chrono::duration_cast<chrono::milliseconds>(t1 - t0).count();
cout << "[Cam" << camID << "] Grab time: " << ms << " ms" << endl;
}
}
zed.disableStreaming();
zed.close();
}
int main() {
signal(SIGINT, signalHandler);
signal(SIGTERM, signalHandler);
const int numCams = 4;
const int basePort = 30000;
vector<thread> threads;
for (int i = 0; i < numCams; ++i) {
int port = basePort + i * 2;
threads.emplace_back(streamThread, i, port);
}
for (auto &t : threads) t.join();
return EXIT_SUCCESS;
}
Even with all depth computation disabled, the grab()
times fluctuate between 18 ms and 49 ms, meaning I never consistently hit 30 FPS per camera. On average, each camera sits around 22–25 FPS. Beyond 60 FPS, the bus becomes unstable and images get corrupted (as expected).
I’ve tested:
- Raising thread priority with
SCHED_FIFO
- Adding slight initial delays to stagger grabs
- Different bitrates and codecs (H.264 vs H.265)
But still, I can’t seem to push to 30 FPS across all 4 cameras simultaneously at 1080p.
Is this a hard limit due to GMSL2/CSI or encoder throughput on the Orin NX?
Thanks in advance for any help or insights!
If anyone has a working example of 4x 1080p@30FPS streaming from Orin NX, I’d love to benchmark it.