Skip to content

Commit

Permalink
gst camera: add RTMP streaming and nvidia encoding (#727)
Browse files Browse the repository at this point in the history
* gst camera: add RTMP streaming and nvidia encoding

* disable GPU encoding by default

* completed nvh264enc installation instructions
  • Loading branch information
dayjaby authored Mar 18, 2021
1 parent b195315 commit 1b1afca
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 23 deletions.
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,34 @@ make install

When writing test it’s important to be careful which API functions of Gazebo are called. As no Gazebo server is running during the tests some functions can produce undefined behaviour (e.g. segfaults).

## CUDA Hardware Accelerated H264 encoding (optional)

1. Download CUDA 10.0 from https://developer.nvidia.com/cuda-toolkit-archive.
2. Download Video Codec SDK 9.0 from https://developer.nvidia.com/video-codec-sdk-archive.
3. Install both archives:

```bash
wget https://raw.githubusercontent.com/jackersson/env-setup/master/gst-nvidia-docker/install_video_codec_sdk.sh
chmod +x install_video_codec_sdk.sh
sudo ./install_video_codec_sdk.sh
sudo dpkg -i cuda-repo-ubuntu*.deb
sudo apt-key add /var/cuda-repo-<version>/7fa2af80.pub
sudo apt-get update
sudo apt-get install cuda
```

4. Reboot your system and run the command `nvidia-smi` to verify the successul installation of CUDA.
5. Install GStreamer 1.18.3:

```bash
git clone https://github.com/GStreamer/gst-build -b 1.18.3
cd gst-build
meson -Dbuildtype=release -Dstrip=true -Dgst-plugins-bad:introspection=enabled -Dgst-plugins-bad:nvcodec=enabled builddir
ninja -C builddir
sudo meson install -C builddir
```

6. Add `<useCuda>true</useCuda>` to any `gazebo_gst_camera_plugin` in a SDF file. For example `./models/fpv_cam/fpv_cam.sdf`.

#### *catkin tools*

Expand Down
8 changes: 6 additions & 2 deletions include/gazebo_gst_camera_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,12 @@ class GAZEBO_VISIBLE GstCameraPlugin : public SensorPlugin
float rate;
protected: std::string format;

protected: std::string udpHost;
protected: int udpPort;
protected:
std::string udpHost;
int udpPort;
bool useRtmp;
std::string rtmpLocation;
bool useCuda;

protected: sensors::CameraSensorPtr parentSensor;
protected: rendering::CameraPtr camera;
Expand Down
69 changes: 48 additions & 21 deletions src/gazebo_gst_camera_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,39 @@ void GstCameraPlugin::startGstThread() {
GstElement* dataSrc = gst_element_factory_make("appsrc", "AppSrc");
GstElement* testSrc = gst_element_factory_make("videotestsrc", "FileSrc");
GstElement* conv = gst_element_factory_make("videoconvert", "Convert");
GstElement* encoder = gst_element_factory_make("x264enc", "AvcEncoder");

GstElement* encoder;
if (useCuda) {
encoder = gst_element_factory_make("nvh264enc", "AvcEncoder");
g_object_set(G_OBJECT(encoder), "bitrate", 800, NULL);
g_object_set(G_OBJECT(encoder), "preset", 1, NULL); //lower = faster, 6=medium
} else {
encoder = gst_element_factory_make("x264enc", "AvcEncoder");
g_object_set(G_OBJECT(encoder), "bitrate", 800, NULL);
g_object_set(G_OBJECT(encoder), "speed-preset", 2, NULL); //lower = faster, 6=medium
//g_object_set(G_OBJECT(encoder), "tune", "zerolatency", NULL);
//g_object_set(G_OBJECT(encoder), "low-latency", 1, NULL);
//g_object_set(G_OBJECT(encoder), "control-rate", 2, NULL);
}
GstElement* parser = gst_element_factory_make("h264parse", "Parser");
GstElement* payload = gst_element_factory_make("rtph264pay", "PayLoad");
GstElement* sink = gst_element_factory_make("udpsink", "UdpSink");
GstElement* payload;
GstElement* sink;

if (useRtmp) {
g_object_set(G_OBJECT(parser), "config-interval", 1, NULL);
payload = gst_element_factory_make("flvmux", "FLVMux");
sink = gst_element_factory_make("rtmpsink", "RtmpSink");
g_object_set(G_OBJECT(sink), "location", this->rtmpLocation.c_str(), NULL);
} else {
payload = gst_element_factory_make("rtph264pay", "PayLoad");
g_object_set(G_OBJECT(payload), "config-interval", 1, NULL);
sink = gst_element_factory_make("udpsink", "UdpSink");
g_object_set(G_OBJECT(sink), "host", this->udpHost.c_str(), NULL);
g_object_set(G_OBJECT(sink), "port", this->udpPort, NULL);
//g_object_set(G_OBJECT(sink), "sync", false, NULL);
//g_object_set(G_OBJECT(sink), "async", false, NULL);
}

if (!dataSrc || !testSrc || !conv || !encoder || !parser || !payload || !sink) {
gzerr << "ERR: Create elements failed. \n";
return;
Expand All @@ -121,22 +150,6 @@ void GstCameraPlugin::startGstThread() {
"is-live", TRUE,
NULL);

// Config encoder
g_object_set(G_OBJECT(encoder), "bitrate", 800, NULL);
g_object_set(G_OBJECT(encoder), "speed-preset", 2, NULL); //lower = faster, 6=medium
//g_object_set(G_OBJECT(encoder), "tune", "zerolatency", NULL);
//g_object_set(G_OBJECT(encoder), "low-latency", 1, NULL);
//g_object_set(G_OBJECT(encoder), "control-rate", 2, NULL);

// Config payload
g_object_set(G_OBJECT(payload), "config-interval", 1, NULL);

// Config udpsink
g_object_set(G_OBJECT(sink), "host", this->udpHost.c_str(), NULL);
g_object_set(G_OBJECT(sink), "port", this->udpPort, NULL);
//g_object_set(G_OBJECT(sink), "sync", false, NULL);
//g_object_set(G_OBJECT(sink), "async", false, NULL);

// Connect all elements to pipeline
gst_bin_add_many(GST_BIN(pipeline), dataSrc, conv, encoder, parser, payload, sink, NULL);

Expand Down Expand Up @@ -253,12 +266,26 @@ void GstCameraPlugin::Load(sensors::SensorPtr sensor, sdf::ElementPtr sdf)

this->udpHost = "127.0.0.1";
if (sdf->HasElement("udpHost")) {
this->udpHost = sdf->GetElement("udpHost")->Get<string>();
this->udpHost = sdf->GetElement("udpHost")->Get<string>();
}

this->udpPort = 5600;
if (sdf->HasElement("udpPort")) {
this->udpPort = sdf->GetElement("udpPort")->Get<int>();
this->udpPort = sdf->GetElement("udpPort")->Get<int>();
}

if (sdf->HasElement("rtmpLocation")) {
this->rtmpLocation = sdf->GetElement("rtmpLocation")->Get<string>();
this->useRtmp = true;
} else {
this->useRtmp = false;
}

// Use CUDA for video encoding
if (sdf->HasElement("useCuda")) {
this->useCuda = sdf->GetElement("useCuda")->Get<bool>();
} else {
this->useCuda = false;
}

node_handle_ = transport::NodePtr(new transport::Node());
Expand Down

0 comments on commit 1b1afca

Please sign in to comment.