Lingering issue 3x USB camera at 60fps 1280x720

Hi,

I have an annoying lingering problem with bandwidth on the AGX Orin.
I run 3 cameras on the Jetson AGX Orin and I get a lot of frame drops.
The resolution is 1280x720 @60fps and saving to disk just does not keep up.
I try to save to onboard M2 but still not the speed I would like.
This is the gstreamer I use:

gst-launch-1.0 v4l2src device=/dev/video0 ! ‘video/x-raw , width=(int)1280 , height=(int)720 , format=(string)GRAY8 , framerate=(fraction)60/1’ ! nvvidconv ! ‘video/x-raw(memory:NVMM), width=(int)1280, height=(int)720, format=I420’ ! queue ! nvjpegenc ! multifilesink location=‘/home/localuser/Images/Image00_1%09d.jpg’

Running this on all three cameras at the same time I do not get the speed I want.
Also running a test gstreamer to see total fps from the cameras I get really good performance.
I just cant save all three to disk at 60fps.
This gstreamer testing the fps I get full 59.98 fps on all three cameras at the same time.
v4l2-ctl -d /dev/video0 --set-fmt-video=width=1280,height=720,pixelformat=GREY --stream-mmap

Any ideas how I can get the saving of images to work too?

Hi,
The bottleneck may be in JPEG encoding. Please try to encode to H264 or H265. See if you can achieve target frame rate.

I will try this!

have been able to run 3x60fps at 1600x1300 via USB to M2 mem on the Jetson NX.
Though it has not always been stable and the image freezes on one camera but still sends a frozen
image to file…

I just want to confirm that there is no bandwidth issue.
The spec. for Orin says:
10Gpbs per hub and there are 2 hubs. So
running keyboard and mouse on port 1 and Camera on 2 would result in almost 10Gbps on the cam usb 2.
The second and third would be on port 3 and for resulting in a shared 5Gpbs per camera.

Theoretical bitrate per camera would be at 60fps 0.552 Gpbs (1280x720x8x60) where 8 is image depth (gray8) and 60 the framerate. = 1.656 Gpbs per camera.

So that is well below what the USB can handle. So your though about the compression would make sense.

I made a try saving images raw and this is the speed I get saving it the M2 drive on which I run the OS.
It fluctuate quite a bit.
gst-launch-1.0 v4l2src device=/dev/video2 ! 'video/x-raw , width=(int)1280 , height=(int)720 , format=(string)GRAY8 , framerate=(fraction)60/1' ! nvvidconv ! 'video/x-raw(memory:NVMM),width=(int)1280, height=(int)720, format=I420' ! multifilesink location='/home/localuser/Output/ID1_Image01_%09d.raw'

The result with h264 encoding did not do the trick.

gst-launch-1.0 v4l2src device=/dev/video4 ! 'video/x-raw , width=(int)1280 , height=(int)720 , format=(string)GRAY8 , framerate=(fraction)60/1' ! nvvidconv ! 'video/x-raw(memory:NVMM),width=(int)1280, height=(int)720, format=I420' ! nvv4l2h264enc ! h264parse ! multifilesink location='/home/localuser/Output/ID2_Image01_1%09d.h264'

The framerate was the same 49-57 fps and this was to local M2.
Trying to network drive nfs is worse and of course is another story.

Hi,
Saving RAW data to storage has heavy loading. Please try with fpsdisplaysink like:
Is there drop any frame in capturing video? - #3 by DaneLLL

And there are two type C ports on the developer kit. Would suggest connect the cameras to the ports. Such as connecting one to type A port, one to type C port, and one to the other type C port.

I get this
image

With this g-streamer:
gst-launch-1.0 v4l2src device=/dev/video0 ! 'video/x-raw , width=(int)1280 , height=(int)720 , format=(string)GRAY8 , framerate=(fraction)60/1' ! nvvidconv ! 'video/x-raw(memory:NVMM),width=(int)1280, height=(int)720, format=I420' ! fpsdisplaysink text-overlay=0 video-sink=fakesink sync=0

I run from terminal ssh and not on the machine (will do so tomorrow) but since the sink is fakesink I would presume it would result in fps printout?

I tried this:

gst-launch-1.0 nvv4l2camerasrc device=/dev/video0 ! ‘video/x-raw(memory:NVMM), framerate=(fraction)60/1’ ! fpsdisplaysink text-overlay=0 video-sink=fakesink sync=0 -ev

and it produced

Cam 1:
/GstPipeline:pipeline0/GstFPSDisplaySink:fpsdisplaysink0: last-message = rendered: 1541, dropped: 0, current: 59.95, average: 60.03

Cam 2:
/GstPipeline:pipeline0/GstFPSDisplaySink:fpsdisplaysink0: last-message = rendered: 1178, dropped: 0, current: 59.99, average: 59.99

Cam 3:
/GstPipeline:pipeline0/GstFPSDisplaySink:fpsdisplaysink0: last-message = rendered: 573, dropped: 0, current: 59.95, average: 60.10

So it seems the camera stream is correct but not the saving to disc in this case. I will try the same also tomorrow on my Jetson NX just to verify.
The cap string is:
caps = video/x-raw(memory:NVMM), width=(int)1920, height=(int)1080, format=(string)UYVY, interlace-mode=(string)progressive, framerate=(fraction)60/1

Just for fun I created a OpenCV application in python without g-streamer (unless Python openCV uses it). And I let it save to disk M2 ssd. The framerate was not super stable but was pretty stable at 40fps.

So it seems that Orin cant save to disk at 3x60fps.

Here is the code below reproducing max working fps save to disk. It seems that gstreamer is not good enough in this particular case. I would like though to set the output FPS (since the discrete fps from the camera is either 60 or 10) with g-streamer to see if I can save 3x30 fps stable. something like

gst-launch-1.0 v4l2src device=/dev/video0 ! ‘video/x-raw , width=(int)1280 , height=(int)720 , format=(string)GRAY8 , framerate=(fraction)60/1’ ! nvvidconv ! ‘video/x-raw(memory:NVMM),width=(int)1280, height=(int)720, format=I420’ ! videorate ! ‘video/x-raw, framerate=(fraction)30/1’ ! nvv4l2h264enc ! h264parse ! multifilesink location=‘/mnt/fileshare01/HSP/240131_trials/ID0_Image01_1%09d.h264’

So incoming framerate with resolution by the camera in the first part then convert it to I420 and set framerate to 30. I would really like to know where the bottle neck is if Orin just cant manage the writing of the file to disk. The problem would result in 3x AGX Orin/Jetson Orin just for frame grabbing.

import cv2
import threading
import time
import os

def capture_and_save(camera_id, output_path_template, resolution=(1280, 720), show_fps=False):
    # Open the camera
    cap = cv2.VideoCapture(camera_id)
    
    # Set the resolution
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, resolution[0])
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, resolution[1])

    if not cap.isOpened():
        print(f"Error: Unable to open camera {camera_id}")
        return

    # Initialize frame counter and FPS variables
    frame_counter = 0
    start_time = time.time()
    fps_counter = 0

    # Create the output directory if it doesn't exist
    output_directory = "/home/localuser/Output"
    os.makedirs(output_directory, exist_ok=True)

    try:
        while True:
            # Capture frame-by-frame
            ret, frame = cap.read()

            if not ret:
                print(f"Error: Couldn't read frame from camera {camera_id}")
                break

            # Save the frame to disk as JPEG with unique filename
            output_path = os.path.join(output_directory, output_path_template.format(camera_id=camera_id, counter=frame_counter))
            cv2.imwrite(output_path, frame, [cv2.IMWRITE_JPEG_QUALITY, 95])

            # Increment frame counter
            frame_counter += 1

            # Calculate FPS and print every 10 seconds if show_fps is True
            fps_counter += 1
            elapsed_time = time.time() - start_time
            if elapsed_time >= 10:
                fps = fps_counter / elapsed_time
                if show_fps:
                    print(f"Camera {camera_id} FPS: {fps:.2f}")
                start_time = time.time()
                fps_counter = 0

    finally:
        # Release the camera
        cap.release()

def main():
    # Set the camera IDs (0, 2, 4 for three different cameras)
    camera_ids = [0, 2, 4]

    # Create threads for each camera
    threads = []
    for i, camera_id in enumerate(camera_ids):
        output_path_template = f"camera_{i + 1}_frame_{{counter}}.jpg"
        thread = threading.Thread(target=capture_and_save, args=(camera_id, output_path_template))
        threads.append(thread)
        thread.start()

    # Wait for all threads to finish
    for thread in threads:
        thread.join()

    print("Image capture complete.")

if __name__ == "__main__":
    main()

@DaneLLL
Hi, I tried now with one USB-C to see if anything improved. I used only one because one of the C-port is my power-supply, but all things considered, I would get some improvement. But no. The result is the same.
very slow write speed.

I then tried my Jetson NX with same type of three cameras, same length on cables and I save all three cameras to M2 @ 60fps, meaning 180fps in total. No problem. The resolution was 1280x720.

Only difference is that the Jetson NX has OS on MicroSD while the SSD runs only as secondary storage drive. The Orin has it as OS drive too. I dotn think the performance loss is due to this.

Orin in this case does not perform very well…

Hi,
So without saving to storage, you can achieve 60fps of 3 source on both AGX Orin and Xavier NX. And see performance drop while saving RAW frame data to eMMC in Orin. Is this correct? Would like to understand the situation correctly.

And for comparison, are both Xavier NX and AGX Orin in Jetpack 5.1.2?

Hi,

  • Saving to storage on Orin its impossible to get 3x60fps. (I tried both jpeg and raw). Its much lower, roughly 40fps and very unstable, its going up and down in fps over time.

  • Saving to storage on Jetson NX I get 3x60fps. (I tried both jpeg and raw) This works fine, I get stable 60 fps per camera.

Jetson is running an older jetpack, I don’t know which, but it was installed 2 years ago and was manually installed and not via the SDK Manager.

The AGX Orin is running 5.1.2, at least I think so, see below.

R35 (release), REVISION: 3.1, GCID: 32827747, BOARD: t186ref, EABI: aarch64, DATE: Sun Mar 19 15:19:21 UTC 2023

Hi,
There are known constraints:

PCIe throughput of Jetpack 5
Bad Jetpack5 nvme writing performance compared with Jetpack4 - #4 by DaneLLL

Embedded eMMC in AGX Orin module:
Disk write performance issue on Jetson AGX Orin - #10 by DaneLLL

So it is possible IO speed is worse when comparing to other Jetson platforms. Would suggest compress to H264 or H265.

H264 did not help. I tried that to with the pipeline

gst-launch-1.0 v4l2src device=/dev/video0 ! ‘video/x-raw , width=(int)1280 , height=(int)720 , format=(string)GRAY8 , framerate=(fraction)60/1’ ! nvvidconv ! ‘video/x-raw(memory:NVMM),width=(int)1280, height=(int)720, format=I420’ ! videorate ! ‘video/x-raw, framerate=(fraction)30/1’ ! nvv4l2h264enc ! h264parse ! multifilesink location=‘/mnt/fileshare01/HSP/240131_trials/ID0_Image01_1%09d.h264’

This is very bad! If this is true that the NX is outperforming the Orin that much on throughput then this really causes a problem. We based our future development on the orin platform due to the fact that NX was slow in inference.

Is it related to the Orin module or to the carrier board?

Hi,
Please try this and see if you can achieve 60fps:

gst-launch-1.0 videotestsrc is-live=1 num-buffers=900 ! 'video/x-raw , width=(int)1280 , height=(int)720 , format=(string)GRAY8 , framerate=(fraction)60/1' ! nvvidconv ! 'video/x-raw(memory:NVMM),width=(int)1280, height=(int)720, format=I420' ! nvv4l2h264enc ! h264parse ! matroskamux ! filesink location=a.mkv

We run it on AGX Orin developer kit(save to eMMC) and it is 60fps as expected. Please try the same but save to /mnt/fileshare01/. See if saving to the storage device is the bottleneck.

I Ran the gstream but had to change the format from NV12 to I420 due to
(ERROR: from element /GstPipeline:pipeline0/GstVideoTestSrc:videotestsrc0: Internal data stream error.)

I got the following results running three attempts:

1 stream:
900 images in 15 sek = 60fps

2 streams:
900 images in 15.1 sek = 60 fps

3 streams:
900 images in 18,6 sek = 48.3 fps
900 images in 18,4 sek = 48.9 fps
900 images in 18,23 = 49.3 fps

Hi,
You are correct that it should be I420. So does it occur when running the 3 streams in 3 processes? Or 3 threads in single process?

I have three individual terminal windows open and run them individually one in each terminal

Hi,
Thanks for the information. We will set up AGX Orin devkit to reproduce the issue and check.

I checked the Jetpack version with jtop and it says 5.1.1 ´, L4T 35.3.1.

@DaneLLL

I think I made a mistake.
I wrote to the onboard emmc and not to a M2 installed SSD. I installed a 250GB M2 memory and it seems
that I get 3x60 FPS. So the issue was that it was just writing to something not capable of managing the data.

I think now streaming over network will be next challenge but that is more network related. I hope throughput is enough on the network adapter for this. Because that also works on the NX. I keep you posted on that in another thread.

I will do more testing but I think I found the issue and will mark this as complete as soon as I have verified my speed. I really appreciate your support still and i apologize for misleading you!

Hi,
It is good to see it is clarified. For further issues please create new topic for clearness.