RTP stream from Jetson Nano CSI Camera to macOS

Would you like to stream from the CSI Camera (Jetson Nano) to your macOS? No problem, it’s super easy! In this tutorial I will show you 2 ways to display the RTP video stream on your macOS. Both options require only a few steps and which one you choose is up to you.

Condition

  • Both devices (Jetson Nano & macOS) must be on the same network
  • SSH connection from macOS to Jetson Nano is available
  • You know the IP or the domain name (.local) of the macOS
  • Firewall on macOS is disabled (for simplicity)
  • The CSI camera on the Jetson Nano is operational

Use of ffplay

Download ffplay for macOS from the official provider site. Unzip the archive and move binary to target directory.

# move binary to target directory
$ mv ffplay /usr/local/bin/ffplay

# test ffplay version (optional)
$ ffplay -version

Now create an SDP file for ffplay (for example directly on your desktop).

SDP:
v=0
o=- 0 0 IN IP4 127.0.0.1
s=NanoStream
c=IN IP4 127.0.0.1
t=0 0
a=tool:libavformat 56.15.102
m=video 1234 RTP/AVP 96
a=rtpmap:96 H264/90000

Note: Note the port specification (m=video 1234 RTP/AVP 96), if this is already occupied on your system, you must change this value and adapt the following steps.

Connect (via SSH) to the Jetson Nano and start the video stream from the camera there.

# start video stream from csi camera
$ gst-launch-1.0 nvarguscamerasrc ! 'video/x-raw(memory:NVMM), format=NV12, width=1920, height=1080' ! nvvidconv flip-method=2 ! nvv4l2h264enc insert-sps-pps=true ! h264parse ! rtph264pay pt=96 ! udpsink host=(IP or Domain from macOS) port=1234 sync=false -e

If there are no problems, leave this terminal connection and start another terminal on the macOS.

# start ffplay
$ ffplay -protocol_whitelist "file,udp,rtp" -i ~/Desktop/ffplay.sdp

After confirming the command, a window should open after a few seconds and you will see the video stream.

Use of VLC

Download latest VLC player from official VLC website. Now install VLC Player. Optionally you can test whether everything works. Also create an SDP file for the VLC Player.

c=IN IP4 127.0.0.1
m=video 1234 RTP/AVP 96
a=rtpmap:96 H264/90000

Connect (via SSH) to the Jetson Nano and start the video stream from the camera there.

# start video stream from csi camera
$ gst-launch-1.0 nvarguscamerasrc ! 'video/x-raw(memory:NVMM), format=NV12, width=1920, height=1080' ! nvvidconv flip-method=2 ! nvv4l2h264enc insert-sps-pps=true ! h264parse ! rtph264pay pt=96 ! udpsink host=(IP or Domain from macOS) port=1234 sync=false -e

Note: Depending on your camera position, you can change the value of flip-method=2 (1 to 4).

If there are no problems, leave this terminal connection and double click on the SDP file for the VLC player. Here, too, you should be able to watch the stream after a few seconds.

Notice

If you have already cloned/installed the repository dusty-nv/jetson-inference, you can view the different video streams in the same way on macOS!

# video viewer
$ video-viewer --bitrate=1000000 --output-codec=h264 csi://0 rtp://(IP or Domain from macOS):1234 --headless

# pose estimation
$ posenet --bitrate=1000000 --output-codec=h264 csi://0 rtp://(IP or Domain from macOS):1234 --headless

# image detection
$ imagenet --bitrate=1000000 --output-codec=h264 csi://0 rtp://(IP or Domain from macOS):1234 --headless

# object detection
$ detectnet --bitrate=1000000 --output-codec=h264 csi://0 rtp://(IP or Domain from macOS):1234 --headless

Hint: Don’t forget to re-enable the firewall (on your macOS) after you’r done!

OpenCV & SSD-Mobilenet-v2

The first steps with OpenCV and haarcascades are done and now it should really start. With other models you can detect easily more objects. In this tutorial I will show you therefore a different possibility with your Jetson Nano device. I recommend switching to desktop mode for performance reasons.

Requirements

  • Jetson Nano Developer Kit (2GB / 4GB)
  • 5V Fan installed (NF-A4x20 5V PWM)
  • CSI camera connected (Raspberry Pi Camera Module V2)

Note: You can also use any other compatible fan and camera.

Objective

The goal is to recognize objects as well to mark and label them directly in the live stream from CSI camera. OpenCV and SSD-Mobilenet-v2 with Python3.6 are used for in this tutorial.

Preparation

As always, it takes a few steps to prepare. This is very easy but can take a while.

# update (optional)
$ sudo apt update

# install needed packages
$ sudo apt install cmake libpython3-dev python3-numpy

# clone repository
$ git clone --recursive https://github.com/dusty-nv/jetson-inference.git

# change into cloned directory
$ cd jetson-inference/

# create and change into directory
$ mkdir build && cd build/

# configure build
$ cmake ../

# download only SSD-Mobilenet-v2
# all other you can download later
# PyTorch is also not needed yet

# build with specified job and install
$ make -j$(nproc)
$ sudo make install

# configure dynamic linker run-time bindings
$ sudo ldconfig

CSI Camera Object detection

When the preparation is successfully completed, you can create the first simple Python script.

# create file and edit
$ vim CSICamObjectDetection.py

Here is the content of the script. The important points are commented.

#!/usr/bin/env python3

import jetson.inference
import jetson.utils
import cv2

# set interference
net = jetson.inference.detectNet("ssd-mobilenet-v2", threshold=0.5)


def gstreamer_pipeline(cap_width=1280,
                       cap_height=720,
                       disp_width=800,
                       disp_height=600,
                       framerate=21,
                       flip_method=2):
    return (
        "nvarguscamerasrc ! "
        "video/x-raw(memory:NVMM), "
        "width=(int)%d, height=(int)%d, "
        "format=(string)NV12, framerate=(fraction)%d/1 ! "
        "nvvidconv flip-method=%d ! "
        "video/x-raw, width=(int)%d, height=(int)%d, format=(string)BGRx ! "
        "videoconvert ! "
        "video/x-raw, format=(string)BGR ! appsink" % (cap_width,
                                                       cap_height,
                                                       framerate,
                                                       flip_method,
                                                       disp_width,
                                                       disp_height)
    )


# process csi camera
video_file = cv2.VideoCapture(gstreamer_pipeline(), cv2.CAP_GSTREAMER)

if video_file.isOpened():
    cv2.namedWindow("Detection result", cv2.WINDOW_AUTOSIZE)

    print('CSI stream opened. Press ESC or Ctrl + c to stop application')

    while cv2.getWindowProperty("Detection result", 0) >= 0:
        ret, frame = video_file.read()

        # convert and detect
        imgCuda = jetson.utils.cudaFromNumpy(frame)
        detections = net.Detect(imgCuda)

        # draw rectangle and description
        for d in detections:
            x1, y1, x2, y2 = int(d.Left), int(d.Top), int(d.Right), int(d.Bottom)
            className = net.GetClassDesc(d.ClassID)
            cv2.rectangle(frame, (x1,y1), (x2, y2), (0, 0, 0), 2)
            cv2.putText(frame, className, (x1+5, y1+15), cv2.FONT_HERSHEY_DUPLEX, 0.75, (0, 0, 0), 2)

        # show frame
        cv2.imshow("Detection result", frame)

        # stop via ESC key
        keyCode = cv2.waitKey(30) & 0xFF
        if keyCode == 27 or not ret:
            break

    # close
    video_file.release()
    cv2.destroyAllWindows()
else:
    print('unable to open csi stream')

Now you can run the script. It will take a while the first time, so please be patient.

# execute
$ python3 CSICamObjectDetection.py

# or with executable permissions
$ ./CSICamObjectDetection.py

I was fascinated by the results! I hope you feel the same way.

First steps with Jetson Nano 2GB Developer Kit (Part 2)

In the first part I explained the initial setup of the Jetson Nano 2GB Developer Kit. This second part should help with additional (but required) hardware like the fan and csi camera.

Preparation

If you are still connected via SSH (or serial) and the Jetson Nano is still running, you have to shut it down now.

# shutdown
$ sudo shutdown -h 0

Connect the fan and the camera and make sure that all connections are made correctly! If you are not sure, look for the respective video on this very helpful website. As soon as you are done, you can restart the Jetson Nano and connect.

Note: The screws that come with the fan are too big. So I simply used cable ties. Otherwise I can really recommend this fan.

Fan

As soon as you have started and logged in again, you should check whether the fan is basically running.

# turn on fan
$ sudo sh -c 'echo 255 > /sys/devices/pwm-fan/target_pwm'

# turn off fan
$ sudo sh -c 'echo 0 > /sys/devices/pwm-fan/target_pwm'

If that worked, the easiest way use the code provided on GitHub to start/stop the fan on certain temperatures fully automatically.

# clone repository
$ git clone https://github.com/Pyrestone/jetson-fan-ctl.git

# change into cloned repository
$ cd jetson-fan-ctl

# start installation
$ sudo ./install.sh

# check service (optional)
$ sudo systemctl status automagic-fan

You can also change the values for your own needs.

# edit via vim
$ sudo vim / etc/automagic-fan/config.json

# restart service after changes
$ sudo systemctl restart automagic-fan

Note: The space between slash and etc is wrong! But my provider does not allow the correct information for security reasons.

From now on, your Jetson Nano should be protected against too quickly overheating. If you want to determine the current values ​​yourself, simply call up the following commands.

# show thermal zones
$ cat /sys/devices/virtual/thermal/thermal_zone*/type
$ cat /sys/devices/virtual/thermal/thermal_zone*/temp

Camera

The CSI camera don’t need any additional installation of packages, all you need is already installed. So after booting up, you can start right away.

Important: Do not attach the CSI camera while the device is running!

# list video devices
$ ls -l /dev/video0
crw-rw----+ 1 root video 81, 0 Jan  9 12:07 /dev/video0

An additional package allows you to find out the possibilities of the camera.

# install package (optional)
$ sudo apt install -y v4l-utils

# list information (optional)
$ v4l2-ctl --list-formats-ext

Take a picture

# take picture and save to disk
$ nvgstcapture-1.0 --orientation=2 --image-res=2

# Press j and ENTER to take a picture
# Press q and ENTER to exit

# list stored pictures
$ ls -lh nvcamtest_*
-rw-rw-r-- 1 lupin lupin 20K Jan  9 15:39 nvcamtest_7669_s00_00000.jpg

Now record a video. Be careful with your disk space!

# take video and save to disk
$ nvgstcapture-1.0 --orientation 2 --mode=2

# Press 1 and ENTER to start record
# Press 0 and ENTER to stop record
# Press q and ENTER to exit

$ ls -lh *.mp4
-rw-rw-r-- 1 lupin lupin 3,0M Jan  9 15:52 nvcamtest_8165_s00_00000.mp4

That’s it for this time.