gazebo_gst_camera_plugin.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012-2016 Open Source Robotics Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16 */
17 #ifdef _WIN32
18  // Ensure that Winsock2.h is included before Windows.h, which can get
19  // pulled in by anybody (e.g., Boost).
20 #include <Winsock2.h>
21 #endif
22 
23 #include "gazebo/sensors/DepthCameraSensor.hh"
25 
26 #include <math.h>
27 #include <string>
28 #include <iostream>
29 #include <thread>
30 #include <time.h>
31 
32 using namespace std;
33 using namespace gazebo;
34 
36 
37 
38 static void cb_need_data(GstElement *appsrc, guint unused_size, gpointer user_data) {
39  GstCameraPlugin *plugin = (GstCameraPlugin*)user_data;
40  plugin->gstCallback(appsrc);
41 }
42 
43 void GstCameraPlugin::gstCallback(GstElement *appsrc) {
44 
45  frameBufferMutex.lock();
46 
47  while (!frameBuffer) {
48  /* can happen if not initialized yet */
49  frameBufferMutex.unlock();
50  usleep(10000);
51  frameBufferMutex.lock();
52  }
53 
54  GST_BUFFER_PTS(frameBuffer) = gstTimestamp;
55  GST_BUFFER_DURATION(frameBuffer) = gst_util_uint64_scale_int (1, GST_SECOND, (int)rate);
56  gstTimestamp += GST_BUFFER_DURATION(frameBuffer);
57 
58  GstFlowReturn ret;
59  g_signal_emit_by_name(appsrc, "push-buffer", frameBuffer, &ret);
60 
61  frameBufferMutex.unlock();
62 
63  if (ret != GST_FLOW_OK) {
64  /* something wrong, stop pushing */
65  gzerr << "g_signal_emit_by_name failed" << endl;
66  g_main_loop_quit(mainLoop);
67  }
68 }
69 
70 static void* start_thread(void* param) {
71  GstCameraPlugin* plugin = (GstCameraPlugin*)param;
72  plugin->startGstThread();
73  return nullptr;
74 }
75 
76 void GstCameraPlugin::startGstThread() {
77 
78  gst_init(0, 0);
79 
80  mainLoop = g_main_loop_new(NULL, FALSE);
81  if (!mainLoop) {
82  gzerr << "Create loop failed. \n";
83  return;
84  }
85 
86  GstElement* pipeline = gst_pipeline_new("sender");
87  if (!pipeline) {
88  gzerr << "ERR: Create pipeline failed. \n";
89  return;
90  }
91 
92  GstElement* dataSrc = gst_element_factory_make("appsrc", "AppSrc");
93  GstElement* testSrc = gst_element_factory_make("videotestsrc", "FileSrc");
94  GstElement* conv = gst_element_factory_make("videoconvert", "Convert");
95  GstElement* encoder = gst_element_factory_make("x264enc", "AvcEncoder");
96  GstElement* parser = gst_element_factory_make("h264parse", "Parser");
97  GstElement* payload = gst_element_factory_make("rtph264pay", "PayLoad");
98  GstElement* sink = gst_element_factory_make("udpsink", "UdpSink");
99  if (!dataSrc || !testSrc || !conv || !encoder || !parser || !payload || !sink) {
100  gzerr << "ERR: Create elements failed. \n";
101  return;
102  }
103 
104 // gzerr <<"width"<< this->width<<"\n";
105 // gzerr <<"height"<< this->height<<"\n";
106 // gzerr <<"rate"<< this->rate<<"\n";
107 
108  // Config src
109  g_object_set(G_OBJECT(dataSrc), "caps",
110  gst_caps_new_simple ("video/x-raw",
111  "format", G_TYPE_STRING, "RGB",
112  "width", G_TYPE_INT, this->width,
113  "height", G_TYPE_INT, this->height,
114  "framerate", GST_TYPE_FRACTION, (unsigned int)this->rate, 1,
115  NULL),
116  "is-live", TRUE,
117  NULL);
118 
119  // Config encoder
120  g_object_set(G_OBJECT(encoder), "bitrate", 800, NULL);
121  g_object_set(G_OBJECT(encoder), "speed-preset", 2, NULL); //lower = faster, 6=medium
122  //g_object_set(G_OBJECT(encoder), "tune", "zerolatency", NULL);
123  //g_object_set(G_OBJECT(encoder), "low-latency", 1, NULL);
124  //g_object_set(G_OBJECT(encoder), "control-rate", 2, NULL);
125 
126  // Config payload
127  g_object_set(G_OBJECT(payload), "config-interval", 1, NULL);
128 
129  // Config udpsink
130  g_object_set(G_OBJECT(sink), "host", "127.0.0.1", NULL);
131  g_object_set(G_OBJECT(sink), "port", this->udpPort, NULL);
132  //g_object_set(G_OBJECT(sink), "sync", false, NULL);
133  //g_object_set(G_OBJECT(sink), "async", false, NULL);
134 
135  // Connect all elements to pipeline
136  gst_bin_add_many(GST_BIN(pipeline), dataSrc, conv, encoder, parser, payload, sink, NULL);
137 
138  // Link all elements
139  if (gst_element_link_many(dataSrc, conv, encoder, parser, payload, sink, NULL) != TRUE) {
140  gzerr << "ERR: Link all the elements failed. \n";
141  return;
142  }
143 
144  // Set up appsrc
145  g_object_set(G_OBJECT(dataSrc), "stream-type", 0, "format", GST_FORMAT_TIME, NULL);
146  g_signal_connect(dataSrc, "need-data", G_CALLBACK(cb_need_data), this);
147 
148  // Start
149  gst_element_set_state(pipeline, GST_STATE_PLAYING);
150  g_main_loop_run(mainLoop);
151 
152  // Clean up
153  gst_element_set_state(pipeline, GST_STATE_NULL);
154  gst_object_unref(GST_OBJECT(pipeline));
155  g_main_loop_unref(mainLoop);
156  mainLoop = nullptr;
157 
158 }
159 
161 GstCameraPlugin::GstCameraPlugin()
162 : SensorPlugin(), width(0), height(0), depth(0), frameBuffer(nullptr), mainLoop(nullptr),
163  gstTimestamp(0)
164 {
165 }
166 
169 {
170  this->parentSensor.reset();
171  this->camera.reset();
172  if (mainLoop) {
173  g_main_loop_quit(mainLoop);
174  }
175  std::lock_guard<std::mutex> guard(frameBufferMutex);
176  if (frameBuffer) {
177  gst_buffer_unref(frameBuffer);
178  frameBuffer = nullptr;
179  }
180 }
181 
183 void GstCameraPlugin::Load(sensors::SensorPtr sensor, sdf::ElementPtr sdf)
184 {
185  if(kPrintOnPluginLoad) {
186  gzdbg << __FUNCTION__ << "() called." << std::endl;
187  }
188 
189  if (!sensor)
190  gzerr << "Invalid sensor pointer.\n";
191 
192  this->parentSensor =
193  std::dynamic_pointer_cast<sensors::CameraSensor>(sensor);
194 
195  if (!this->parentSensor)
196  {
197  gzerr << "GstCameraPlugin requires a CameraSensor.\n";
198 
199  if (std::dynamic_pointer_cast<sensors::DepthCameraSensor>(sensor))
200  gzmsg << "It is a depth camera sensor\n";
201  }
202 
203  this->camera = this->parentSensor->Camera();
204 
205  if (!this->parentSensor)
206  {
207  gzerr << "GstCameraPlugin not attached to a camera sensor\n";
208  return;
209  }
210 
211  this->width = this->camera->ImageWidth();
212  this->height = this->camera->ImageHeight();
213  this->depth = this->camera->ImageDepth();
214  this->format = this->camera->ImageFormat();
215  this->rate = this->camera->RenderRate();
216 
217  if (!isfinite(this->rate)) {
218  this->rate = 60.0;
219  }
220 
221  if (sdf->HasElement("robotNamespace"))
222  namespace_ = sdf->GetElement("robotNamespace")->Get<std::string>();
223  else
224  gzwarn << "[gazebo_gst_camera_plugin] Please specify a robotNamespace.\n";
225 
226  this->udpPort = 5600;
227  if (sdf->HasElement("udpPort")) {
228  this->udpPort = sdf->GetElement("udpPort")->Get<int>();
229  }
230 
231  node_handle_ = transport::NodePtr(new transport::Node());
232  node_handle_->Init(namespace_);
233 
234 
235  this->newFrameConnection = this->camera->ConnectNewImageFrame(
236  boost::bind(&GstCameraPlugin::OnNewFrame, this, _1, this->width, this->height, this->depth, this->format));
237 
238  this->parentSensor->SetActive(true);
239 
240  /* start the gstreamer event loop */
241  pthread_t threadId;
242  pthread_create(&threadId, NULL, start_thread, this);
243 }
244 
246 void GstCameraPlugin::OnNewFrame(const unsigned char * image,
247  unsigned int width,
248  unsigned int height,
249  unsigned int depth,
250  const std::string &format)
251 {
252 
253  image = this->camera->ImageData(0);
254 
255  std::lock_guard<std::mutex> guard(frameBufferMutex);
256 
257  if (frameBuffer) {
258  gst_buffer_unref(frameBuffer);
259  }
260 
261  // Alloc buffer
262  guint size = width * height * 3;
263  frameBuffer = gst_buffer_new_allocate(NULL, size, NULL);
264 
265  GstMapInfo mapInfo;
266  if (gst_buffer_map(frameBuffer, &mapInfo, GST_MAP_WRITE)) {
267  memcpy(mapInfo.data, image, size);
268  gst_buffer_unmap(frameBuffer, &mapInfo);
269  } else {
270  gzerr << "gst_buffer_map failed"<<endl;
271  }
272 }
A Gazebo plugin that can be attached to a camera and then streams the video data using gstreamer...
GZ_REGISTER_SENSOR_PLUGIN(GazeboGpsPlugin)
#define FALSE
sensors::CameraSensorPtr parentSensor
virtual void Load(sensors::SensorPtr sensor, sdf::ElementPtr sdf)
Parameter param
static void cb_need_data(GstElement *appsrc, guint unused_size, gpointer user_data)
void gstCallback(GstElement *appsrc)
event::ConnectionPtr newFrameConnection
#define TRUE
static const bool kPrintOnPluginLoad
Definition: common.h:41
uint8_t size
static void * start_thread(void *param)
virtual void OnNewFrame(const unsigned char *image, unsigned int width, unsigned int height, unsigned int depth, const std::string &format)


rotors_gazebo_plugins
Author(s): Fadri Furrer, Michael Burri, Mina Kamel, Janosch Nikolic, Markus Achtelik
autogenerated on Mon Feb 28 2022 23:39:03