raspicam_node.cpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2013, Broadcom Europe Ltd
3 Copyright (c) 2013, James Hughes
4 All rights reserved.
5 
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8  * Redistributions of source code must retain the above copyright
9  notice, this list of conditions and the following disclaimer.
10  * Redistributions in binary form must reproduce the above copyright
11  notice, this list of conditions and the following disclaimer in the
12  documentation and/or other materials provided with the distribution.
13  * Neither the name of the copyright holder nor the
14  names of its contributors may be used to endorse or promote products
15  derived from this software without specific prior written permission.
16 
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
21 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 #ifdef __x86_64__
30 
31 #include <stdio.h>
32 
33 int main(int argc, char** argv) {
34  (void)fprintf(stderr, "The raspicam_node for the x86/64 architecture is a fake!\n");
35  return 1;
36 }
37 
38 #endif // __x86_64__
39 
40 #if defined(__arm__) || defined(__aarch64__)
41 
42 // We use some GNU extensions (basename)
43 #include <memory.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 
48 #include <memory>
49 
50 #define VCOS_ALWAYS_WANT_LOGGING
51 #define VERSION_STRING "v1.2"
52 
53 #include "bcm_host.h"
54 #include "interface/vcos/vcos.h"
55 
56 #include "interface/mmal/mmal.h"
57 #include "interface/mmal/mmal_buffer.h"
58 #include "interface/mmal/mmal_logging.h"
59 #include "interface/mmal/util/mmal_connection.h"
60 #include "interface/mmal/util/mmal_default_components.h"
61 #include "interface/mmal/util/mmal_util.h"
62 #include "interface/mmal/util/mmal_util_params.h"
63 
65 #include "ros/ros.h"
66 #include "sensor_msgs/CameraInfo.h"
67 #include "sensor_msgs/CompressedImage.h"
68 #include "sensor_msgs/Image.h"
69 #include "sensor_msgs/SetCameraInfo.h"
70 #include "std_srvs/Empty.h"
71 #include "raspicam_node/MotionVectors.h"
74 
75 #include "RaspiCamControl.h"
76 
77 #include <dynamic_reconfigure/server.h>
78 #include <raspicam_node/CameraConfig.h>
79 
80 #include "mmal_cxx_helper.h"
81 
82 static constexpr int IMG_BUFFER_SIZE = 10 * 1024 * 1024; // 10 MB
83 
84 // Video format information
85 static constexpr int VIDEO_FRAME_RATE_DEN = 1;
86 
87 // Video render needs at least 2 buffers.
88 static constexpr int VIDEO_OUTPUT_BUFFERS_NUM = 3;
89 
92 struct RASPIVID_STATE {
93  RASPIVID_STATE()
94  : camera_component(nullptr)
95  , splitter_component(nullptr)
96  , image_encoder_component(nullptr)
97  , video_encoder_component(nullptr)
98  , splitter_connection(nullptr)
99  , image_encoder_connection(nullptr)
100  , video_encoder_connection(nullptr)
101  , splitter_pool(nullptr, mmal::default_delete_pool)
102  , image_encoder_pool(nullptr, mmal::default_delete_pool)
103  , video_encoder_pool(nullptr, mmal::default_delete_pool){};
104 
105  bool isInit;
106  int width;
107  int height;
108  int framerate;
109  int quality;
110  bool enable_raw_pub; // Enable Raw publishing
111  bool enable_imv_pub; // Enable publishing of inline motion vectors
112 
113  int camera_id = 0;
114 
115  RASPICAM_CAMERA_PARAMETERS camera_parameters;
116 
117  mmal::component_ptr camera_component;
118  mmal::component_ptr splitter_component;
119  mmal::component_ptr image_encoder_component;
120  mmal::component_ptr video_encoder_component;
121 
122  mmal::connection_ptr splitter_connection;
123  mmal::connection_ptr image_encoder_connection;
124  mmal::connection_ptr video_encoder_connection;
125 
126  mmal::pool_ptr splitter_pool; // Pointer buffer pool used by splitter (raw) output
127  mmal::pool_ptr image_encoder_pool; // Pointer buffer pool used by encoder (jpg) output
128  mmal::pool_ptr video_encoder_pool; // Pointer buffer pool used by encoder (h264) output
129 
130  // The Updater class advertises to /diagnostics, and has a
131  // ~diagnostic_period parameter that says how often the diagnostics
132  // should be published.
134 };
135 
138 typedef struct MMAL_PORT_USERDATA_T {
139  MMAL_PORT_USERDATA_T(RASPIVID_STATE& state) : pstate(state){};
140  std::unique_ptr<uint8_t[]> buffer[2]; // Memory to write buffer data to.
141  RASPIVID_STATE& pstate; // pointer to our state for use by callback
142  bool abort; // Set to 1 in callback if an error occurs to attempt to abort
143  // the capture
144  int frame;
145  int id;
146 
147  int frames_skipped = 0;
148 } PORT_USERDATA;
149 
153 
154 // Helper template
155 template<typename T>
156 struct DiagnosedMsgPublisher {
157  std::unique_ptr<DiagnosedPublisher<T>> pub;
158  T msg;
159 };
160 
161 static DiagnosedMsgPublisher<sensor_msgs::Image> image;
162 static DiagnosedMsgPublisher<sensor_msgs::CompressedImage> compressed_image;
163 static DiagnosedMsgPublisher<raspicam_node::MotionVectors> motion_vectors;
164 
165 ros::Publisher camera_info_pub;
166 sensor_msgs::CameraInfo c_info;
167 std::string camera_frame_id;
168 int skip_frames = 0;
169 
176 static void configure_parameters(RASPIVID_STATE& state, ros::NodeHandle& nh) {
177  nh.param<int>("width", state.width, 640);
178  nh.param<int>("height", state.height, 480);
179  nh.param<int>("quality", state.quality, 80);
180  if (state.quality < 0 && state.quality > 100) {
181  ROS_WARN("quality: %d is outside valid range 0-100, defaulting to 80", state.quality);
182  state.quality = 80;
183  }
184  nh.param<int>("framerate", state.framerate, 30);
185  if (state.framerate < 0 && state.framerate > 90) {
186  ROS_WARN("framerate: %d is outside valid range 0-90, defaulting to 30", state.framerate);
187  state.framerate = 30;
188  }
189 
190  nh.param<std::string>("camera_frame_id", camera_frame_id, "");
191 
192  nh.param<bool>("enable_raw", state.enable_raw_pub, false);
193  nh.param<bool>("enable_imv", state.enable_imv_pub, false);
194  nh.param<int>("camera_id", state.camera_id, 0);
195 
196  // Set up the camera_parameters to default
197  raspicamcontrol_set_defaults(state.camera_parameters);
198 
199  bool temp;
200  nh.param<bool>("hFlip", temp, false);
201  state.camera_parameters.hflip = temp; // Hack for bool param => int variable
202  nh.param<bool>("vFlip", temp, false);
203  state.camera_parameters.vflip = temp; // Hack for bool param => int variable
204  nh.param<int>("shutter_speed", state.camera_parameters.shutter_speed, 0);
205  nh.param<int>("contrast", state.camera_parameters.contrast, 1);
206 
207  state.isInit = false;
208 }
209 
218 static void image_encoder_buffer_callback(MMAL_PORT_T* port, MMAL_BUFFER_HEADER_T* buffer) {
219  // We pass our own memory and other stuff in via the userdata field.
220  PORT_USERDATA* pData = port->userdata;
221  if (pData && pData->pstate.isInit) {
222  size_t bytes_written = buffer->length;
223  if (buffer->length) {
224  if (pData->id != INT_MAX) {
225  if (pData->id + buffer->length > IMG_BUFFER_SIZE) {
226  ROS_ERROR("pData->id (%d) + buffer->length (%d) > "
227  "IMG_BUFFER_SIZE (%d), skipping the frame",
228  pData->id, buffer->length, IMG_BUFFER_SIZE);
229  pData->id = INT_MAX; // mark this frame corrupted
230  } else {
231  mmal_buffer_header_mem_lock(buffer);
232  memcpy(&(pData->buffer[pData->frame & 1].get()[pData->id]), buffer->data, buffer->length);
233  pData->id += bytes_written;
234  mmal_buffer_header_mem_unlock(buffer);
235  }
236  }
237  }
238 
239  if (bytes_written != buffer->length) {
240  vcos_log_error("Failed to write buffer data (%d from %d)- aborting", bytes_written, buffer->length);
241  ROS_ERROR("Failed to write buffer data (%d from %d)- aborting", bytes_written, buffer->length);
242  pData->abort = true;
243  }
244 
245  bool complete = false;
246  if (buffer->flags & (MMAL_BUFFER_HEADER_FLAG_FRAME_END | MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED))
247  complete = true;
248 
249  if (complete) {
250  if (pData->id != INT_MAX) {
251  // ROS_INFO("Frame size %d", pData->id);
252  if (skip_frames > 0 && pData->frames_skipped < skip_frames) {
253  pData->frames_skipped++;
254  } else {
255  pData->frames_skipped = 0;
256 
257  compressed_image.msg.header.seq = pData->frame;
258  compressed_image.msg.header.frame_id = camera_frame_id;
259  compressed_image.msg.header.stamp = ros::Time::now();
260  compressed_image.msg.format = "jpeg";
261  auto start = pData->buffer[pData->frame & 1].get();
262  auto end = &(pData->buffer[pData->frame & 1].get()[pData->id]);
263  compressed_image.msg.data.resize(pData->id);
264  std::copy(start, end, compressed_image.msg.data.begin());
265  compressed_image.pub->publish(compressed_image.msg);
266 
267  c_info.header.seq = pData->frame;
268  c_info.header.stamp = compressed_image.msg.header.stamp;
269  c_info.header.frame_id = compressed_image.msg.header.frame_id;
270  camera_info_pub.publish(c_info);
271  pData->frame++;
272 
273  // Update diagnosics if needed
274  pData->pstate.updater.update();
275  }
276  }
277  pData->id = 0;
278  }
279  }
280 
281  // release buffer back to the pool
282  mmal_buffer_header_release(buffer);
283 
284  // and send one back to the port (if still open)
285  if (port->is_enabled) {
286  MMAL_STATUS_T status;
287 
288  MMAL_BUFFER_HEADER_T* new_buffer = mmal_queue_get(pData->pstate.image_encoder_pool->queue);
289 
290  if (new_buffer)
291  status = mmal_port_send_buffer(port, new_buffer);
292 
293  if (!new_buffer || status != MMAL_SUCCESS) {
294  vcos_log_error("Unable to return a buffer to the image encoder port");
295  ROS_ERROR("Unable to return a buffer to the image encoder port");
296  }
297  }
298 }
299 
308 static void video_encoder_buffer_callback(MMAL_PORT_T* port, MMAL_BUFFER_HEADER_T* buffer) {
309  // We pass our own memory and other stuff in via the userdata field.
310  PORT_USERDATA* pData = port->userdata;
311 
312  if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO) {
313  // Frame information
314  motion_vectors.msg.header.seq = pData->frame;
315  motion_vectors.msg.header.frame_id = camera_frame_id;
316  motion_vectors.msg.header.stamp = ros::Time::now();
317 
318  // Number of 16*16px macroblocks
319  motion_vectors.msg.mbx = pData->pstate.width / 16;
320  if (pData->pstate.width % 16)
321  motion_vectors.msg.mbx++;
322 
323  motion_vectors.msg.mby = pData->pstate.height / 16;
324  if (pData->pstate.height % 16)
325  motion_vectors.msg.mby++;
326 
327  mmal_buffer_header_mem_lock(buffer);
328 
329  // Motion vector data
330  struct __attribute__((__packed__)) imv {
331  int8_t x;
332  int8_t y;
333  uint16_t sad;
334  }* imv = reinterpret_cast<struct imv*>(buffer->data);
335 
336  size_t num_elements = buffer->length / sizeof(struct imv);
337  motion_vectors.msg.x.resize(num_elements);
338  motion_vectors.msg.y.resize(num_elements);
339  motion_vectors.msg.sad.resize(num_elements);
340 
341  for (size_t i = 0; i < num_elements; i++) {
342  motion_vectors.msg.x[i] = imv->x;
343  motion_vectors.msg.y[i] = imv->y;
344  motion_vectors.msg.sad[i] = imv->sad;
345  imv++;
346  }
347 
348  mmal_buffer_header_mem_unlock(buffer);
349 
350  motion_vectors.pub->publish(motion_vectors.msg);
351  pData->frame++;
352  }
353 
354  // release buffer back to the pool
355  mmal_buffer_header_release(buffer);
356 
357  // and send one back to the port (if still open)
358  if (port->is_enabled) {
359  MMAL_STATUS_T status;
360 
361  MMAL_BUFFER_HEADER_T* new_buffer = mmal_queue_get(pData->pstate.video_encoder_pool->queue);
362 
363  if (new_buffer)
364  status = mmal_port_send_buffer(port, new_buffer);
365 
366  if (!new_buffer || status != MMAL_SUCCESS) {
367  vcos_log_error("Unable to return a buffer to the video encoder port");
368  ROS_ERROR("Unable to return a buffer to the video encoder port");
369  }
370  }
371 }
372 
373 static void splitter_buffer_callback(MMAL_PORT_T* port, MMAL_BUFFER_HEADER_T* buffer) {
374  // We pass our file handle and other stuff in via the userdata field.
375  PORT_USERDATA* pData = port->userdata;
376  if (pData && pData->pstate.isInit) {
377  size_t bytes_written = buffer->length;
378  if (buffer->length) {
379  if (pData->id != INT_MAX) {
380  if (pData->id + buffer->length > IMG_BUFFER_SIZE) {
381  ROS_ERROR("pData->id (%d) + buffer->length (%d) > "
382  "IMG_BUFFER_SIZE (%d), skipping the frame",
383  pData->id, buffer->length, IMG_BUFFER_SIZE);
384  pData->id = INT_MAX; // mark this frame corrupted
385  } else {
386  mmal_buffer_header_mem_lock(buffer);
387  memcpy(&(pData->buffer[pData->frame & 1].get()[pData->id]), buffer->data, buffer->length);
388  pData->id += bytes_written;
389  mmal_buffer_header_mem_unlock(buffer);
390  }
391  }
392  }
393 
394  if (bytes_written != buffer->length) {
395  vcos_log_error("Failed to write buffer data (%d from %d)- aborting", bytes_written, buffer->length);
396  ROS_ERROR("Failed to write buffer data (%d from %d)- aborting", bytes_written, buffer->length);
397  pData->abort = true;
398  }
399 
400  int complete = false;
401  if (buffer->flags & (MMAL_BUFFER_HEADER_FLAG_FRAME_END | MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED))
402  complete = true;
403 
404  if (complete) {
405  if (pData->id != INT_MAX) {
406  // ROS_INFO("Frame size %d", pData->id);
407  if (skip_frames > 0 && pData->frames_skipped < skip_frames) {
408  pData->frames_skipped++;
409  } else {
410  pData->frames_skipped = 0;
411  image.msg.header.seq = pData->frame;
412  image.msg.header.frame_id = camera_frame_id;
413  image.msg.header.stamp = c_info.header.stamp;
414  image.msg.encoding = "bgr8";
415  image.msg.is_bigendian = false;
416  image.msg.height = pData->pstate.height;
417  image.msg.width = pData->pstate.width;
418  image.msg.step = (pData->pstate.width * 3);
419  auto start = pData->buffer[pData->frame & 1].get();
420  auto end = &(pData->buffer[pData->frame & 1].get()[pData->id]);
421  image.msg.data.resize(pData->id);
422  std::copy(start, end, image.msg.data.begin());
423  image.pub->publish(image.msg);
424  }
425  }
426  pData->frame++;
427  pData->id = 0;
428  }
429  }
430 
431  // release buffer back to the pool
432  mmal_buffer_header_release(buffer);
433 
434  // and send one back to the port (if still open)
435  if (port->is_enabled) {
436  MMAL_STATUS_T status;
437 
438  MMAL_BUFFER_HEADER_T* new_buffer = mmal_queue_get(pData->pstate.splitter_pool->queue);
439 
440  if (new_buffer)
441  status = mmal_port_send_buffer(port, new_buffer);
442 
443  if (!new_buffer || status != MMAL_SUCCESS) {
444  vcos_log_error("Unable to return a buffer to the splitter port");
445  ROS_ERROR("Unable to return a buffer to the splitter port");
446  }
447  }
448 }
449 
458 static MMAL_COMPONENT_T* create_camera_component(RASPIVID_STATE& state) {
459  MMAL_COMPONENT_T* camera = 0;
460  MMAL_ES_FORMAT_T* format;
461  MMAL_PORT_T *video_port = nullptr, *preview_port = nullptr, *still_port = nullptr;
462  MMAL_STATUS_T status;
463 
464  /* Create the component */
465  status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera);
466 
467  if (status != MMAL_SUCCESS) {
468  vcos_log_error("Failed to create camera component");
469  ROS_ERROR("Failed to create camera component");
470  goto error;
471  }
472 
473  if (!camera->output_num) {
474  vcos_log_error("Camera doesn't have output ports");
475  ROS_ERROR("Camera doesn't have output ports");
476  goto error;
477  }
478 
479  video_port = camera->output[mmal::camera_port::video];
480  preview_port = camera->output[mmal::camera_port::preview];
481  still_port = camera->output[mmal::camera_port::capture];
482 
483  // set up the camera configuration
484  {
485  MMAL_PARAMETER_CAMERA_CONFIG_T cam_config;
486  cam_config.hdr.id = MMAL_PARAMETER_CAMERA_CONFIG;
487  cam_config.hdr.size = sizeof(cam_config);
488  cam_config.max_stills_w = state.width;
489  cam_config.max_stills_h = state.height;
490  cam_config.stills_yuv422 = 0;
491  cam_config.one_shot_stills = 0;
492  cam_config.max_preview_video_w = state.width;
493  cam_config.max_preview_video_h = state.height;
494  cam_config.num_preview_video_frames = 3;
495  cam_config.stills_capture_circular_buffer_height = 0;
496  cam_config.fast_preview_resume = 0;
497  cam_config.use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RESET_STC;
498 
499  mmal_port_parameter_set(camera->control, &cam_config.hdr);
500  }
501 
502  // Select the camera to use
503  {
504  MMAL_PARAMETER_INT32_T camera_num;
505  camera_num.hdr.id = MMAL_PARAMETER_CAMERA_NUM;
506  camera_num.hdr.size = sizeof(camera_num);
507  camera_num.value = state.camera_id;
508 
509  status = mmal_port_parameter_set(camera->control, &camera_num.hdr);
510  if (status != MMAL_SUCCESS) {
511  ROS_ERROR("Could not select camera : error %d", status);
512  goto error;
513  }
514  }
515 
516  // Now set up the port formats
517 
518  // Set the encode format on the video port
519 
520  format = video_port->format;
521  format->encoding_variant = MMAL_ENCODING_I420;
522 
523  format->encoding = MMAL_ENCODING_I420;
524  format->es->video.width = state.width;
525  format->es->video.height = state.height;
526  format->es->video.crop.x = 0;
527  format->es->video.crop.y = 0;
528  format->es->video.crop.width = state.width;
529  format->es->video.crop.height = state.height;
530  format->es->video.frame_rate.num = state.framerate;
531  format->es->video.frame_rate.den = VIDEO_FRAME_RATE_DEN;
532 
533  status = mmal_port_format_commit(video_port);
534 
535  if (status) {
536  vcos_log_error("camera video format couldn't be set");
537  ROS_ERROR("camera video format couldn't be set");
538  goto error;
539  }
540 
541  // Ensure there are enough buffers to avoid dropping frames
542  if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
543  video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
544 
545  // Set the encode format on the preview port
546 
547  format = preview_port->format;
548  format->encoding_variant = MMAL_ENCODING_I420;
549 
550  format->encoding = MMAL_ENCODING_I420;
551  format->es->video.width = state.width;
552  format->es->video.height = state.height;
553  format->es->video.crop.x = 0;
554  format->es->video.crop.y = 0;
555  format->es->video.crop.width = state.width;
556  format->es->video.crop.height = state.height;
557  format->es->video.frame_rate.num = state.framerate;
558  format->es->video.frame_rate.den = VIDEO_FRAME_RATE_DEN;
559 
560  status = mmal_port_format_commit(preview_port);
561 
562  if (status) {
563  vcos_log_error("camera preview format couldn't be set");
564  ROS_ERROR("camera preview format couldn't be set");
565  goto error;
566  }
567 
568  // Ensure there are enough buffers to avoid dropping frames
569  if (preview_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
570  preview_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
571 
572  // Set the encode format on the still port
573 
574  format = still_port->format;
575 
576  format->encoding = MMAL_ENCODING_OPAQUE;
577  format->encoding_variant = MMAL_ENCODING_I420;
578 
579  format->es->video.width = state.width;
580  format->es->video.height = state.height;
581  format->es->video.crop.x = 0;
582  format->es->video.crop.y = 0;
583  format->es->video.crop.width = state.width;
584  format->es->video.crop.height = state.height;
585  format->es->video.frame_rate.num = 1;
586  format->es->video.frame_rate.den = 1;
587 
588  status = mmal_port_format_commit(still_port);
589 
590  if (status) {
591  vcos_log_error("camera still format couldn't be set");
592  ROS_ERROR("camera still format couldn't be set");
593  goto error;
594  }
595 
596  video_port->buffer_num = video_port->buffer_num_recommended;
597  /* Ensure there are enough buffers to avoid dropping frames */
598  if (still_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
599  still_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
600 
601  /* Enable component */
602  status = mmal_component_enable(camera);
603 
604  if (status) {
605  vcos_log_error("camera component couldn't be enabled");
606  ROS_ERROR("camera component couldn't be enabled");
607  goto error;
608  }
609 
610  raspicamcontrol_set_all_parameters(*camera, state.camera_parameters);
611 
612  state.camera_component.reset(camera);
613 
614  ROS_DEBUG("Camera component done\n");
615 
616  return camera;
617 
618 error:
619 
620  if (camera)
621  mmal_component_destroy(camera);
622  return 0;
623 }
624 
633 static MMAL_STATUS_T create_image_encoder_component(RASPIVID_STATE& state) {
634  MMAL_COMPONENT_T* encoder = 0;
635  MMAL_PORT_T *encoder_input = nullptr, *encoder_output = nullptr;
636  MMAL_STATUS_T status;
637  MMAL_POOL_T* pool;
638 
639  status = mmal_component_create(MMAL_COMPONENT_DEFAULT_IMAGE_ENCODER, &encoder);
640 
641  if (status != MMAL_SUCCESS) {
642  vcos_log_error("Unable to create image encoder component");
643  ROS_ERROR("Unable to create image encoder component");
644  goto error;
645  }
646 
647  if (!encoder->input_num || !encoder->output_num) {
648  status = MMAL_ENOSYS;
649  vcos_log_error("Image encoder doesn't have input/output ports");
650  ROS_ERROR("Image encoder doesn't have input/output ports");
651  goto error;
652  }
653 
654  encoder_input = encoder->input[0];
655  encoder_output = encoder->output[0];
656 
657  // We want same format on input and output
658  mmal_format_copy(encoder_output->format, encoder_input->format);
659 
660  // Only supporting H264 at the moment
661  encoder_output->format->encoding = MMAL_ENCODING_JPEG;
662 
663  encoder_output->buffer_size = encoder_output->buffer_size_recommended;
664 
665  if (encoder_output->buffer_size < encoder_output->buffer_size_min)
666  encoder_output->buffer_size = encoder_output->buffer_size_min;
667 
668  encoder_output->buffer_num = encoder_output->buffer_num_recommended;
669 
670  if (encoder_output->buffer_num < encoder_output->buffer_num_min)
671  encoder_output->buffer_num = encoder_output->buffer_num_min;
672 
673  // Commit the port changes to the output port
674  status = mmal_port_format_commit(encoder_output);
675 
676  if (status != MMAL_SUCCESS) {
677  vcos_log_error("Unable to set format on image encoder output port");
678  ROS_ERROR("Unable to set format on image encoder output port");
679  goto error;
680  }
681 
682  // Set the JPEG quality level
683  status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_JPEG_Q_FACTOR, state.quality);
684 
685  if (status != MMAL_SUCCESS) {
686  vcos_log_error("Unable to set JPEG quality");
687  ROS_ERROR("Unable to set JPEG quality");
688  goto error;
689  }
690 
691  // Enable component
692  status = mmal_component_enable(encoder);
693 
694  if (status != MMAL_SUCCESS) {
695  vcos_log_error("Unable to enable image encoder component");
696  ROS_ERROR("Unable to enable image encoder component");
697  goto error;
698  }
699 
700  /* Create pool of buffer headers for the output port to consume */
701  pool = mmal_port_pool_create(encoder_output, encoder_output->buffer_num, encoder_output->buffer_size);
702 
703  if (!pool) {
704  vcos_log_error("Failed to create buffer header pool for image encoder output port %s", encoder_output->name);
705  ROS_ERROR("Failed to create buffer header pool for image encoder output port %s", encoder_output->name);
706  }
707 
708  state.image_encoder_pool = mmal::pool_ptr(pool, [encoder](MMAL_POOL_T* ptr) {
709  if (encoder->output[0] && encoder->output[0]->is_enabled) {
710  mmal_port_disable(encoder->output[0]);
711  }
712  mmal_port_pool_destroy(encoder->output[0], ptr);
713  });
714  state.image_encoder_component.reset(encoder);
715 
716  ROS_DEBUG("Image encoder component done\n");
717 
718  return status;
719 
720 error:
721  if (encoder)
722  mmal_component_destroy(encoder);
723 
724  return status;
725 }
726 
735 static MMAL_STATUS_T create_video_encoder_component(RASPIVID_STATE& state) {
736  MMAL_COMPONENT_T* encoder = 0;
737  MMAL_PORT_T *encoder_input = nullptr, *encoder_output = nullptr;
738  MMAL_STATUS_T status;
739  MMAL_POOL_T* pool;
740 
741  status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_ENCODER, &encoder);
742 
743  if (status != MMAL_SUCCESS) {
744  vcos_log_error("Unable to create video encoder component");
745  ROS_ERROR("Unable to create video encoder component");
746  goto error;
747  }
748 
749  if (!encoder->input_num || !encoder->output_num) {
750  status = MMAL_ENOSYS;
751  vcos_log_error("Video encoder doesn't have input/output ports");
752  ROS_ERROR("Video encoder doesn't have input/output ports");
753  goto error;
754  }
755 
756  encoder_input = encoder->input[0];
757  encoder_output = encoder->output[0];
758 
759  // We want same format on input and output
760  mmal_format_copy(encoder_output->format, encoder_input->format);
761 
762  // Only supporting H264 at the moment
763  encoder_output->format->encoding = MMAL_ENCODING_H264;
764 
765  encoder_output->buffer_size = encoder_output->buffer_size_recommended;
766 
767  if (encoder_output->buffer_size < encoder_output->buffer_size_min)
768  encoder_output->buffer_size = encoder_output->buffer_size_min;
769 
770  encoder_output->buffer_num = encoder_output->buffer_num_recommended;
771 
772  if (encoder_output->buffer_num < encoder_output->buffer_num_min)
773  encoder_output->buffer_num = encoder_output->buffer_num_min;
774 
775  // This is a decent default bitrate for 1080p
776  encoder_output->format->bitrate = 17000000;
777 
778  // We need to set the frame rate on output to 0, to ensure it gets
779  // updated correctly from the input framerate when port connected
780  encoder_output->format->es->video.frame_rate.num = 0;
781  encoder_output->format->es->video.frame_rate.den = 1;
782 
783  // Commit the port changes to the output port
784  status = mmal_port_format_commit(encoder_output);
785  if (status != MMAL_SUCCESS) {
786  vcos_log_error("Unable to set format on video encoder output port");
787  ROS_ERROR("Unable to set format on video encoder output port");
788  goto error;
789  }
790 
791  // Set H.264 parameters
792  MMAL_PARAMETER_VIDEO_PROFILE_T param;
793  param.hdr.id = MMAL_PARAMETER_PROFILE;
794  param.hdr.size = sizeof(param);
795  param.profile[0].profile = MMAL_VIDEO_PROFILE_H264_HIGH;
796  param.profile[0].level = MMAL_VIDEO_LEVEL_H264_4;
797  status = mmal_port_parameter_set(encoder_output, &param.hdr);
798  if (status != MMAL_SUCCESS) {
799  vcos_log_error("Unable to set H264 profile on video encoder output port");
800  ROS_ERROR("Unable to set H264 profile on video encoder output port");
801  goto error;
802  }
803 
804  status = mmal_port_parameter_set_boolean(encoder_output, MMAL_PARAMETER_VIDEO_ENCODE_INLINE_VECTORS, 1);
805  if (status != MMAL_SUCCESS) {
806  vcos_log_error("failed to set INLINE VECTORS parameters");
807  ROS_ERROR("failed to set INLINE VECTORS parameters");
808  goto error;
809  }
810 
811  // Enable component
812  status = mmal_component_enable(encoder);
813 
814  if (status != MMAL_SUCCESS) {
815  vcos_log_error("Unable to enable video encoder component");
816  ROS_ERROR("Unable to enable video encoder component");
817  goto error;
818  }
819 
820  /* Create pool of buffer headers for the output port to consume */
821  pool = mmal_port_pool_create(encoder_output, encoder_output->buffer_num, encoder_output->buffer_size);
822 
823  if (!pool) {
824  vcos_log_error("Failed to create buffer header pool for video encoder output port %s", encoder_output->name);
825  ROS_ERROR("Failed to create buffer header pool for video encoder output port %s", encoder_output->name);
826  }
827 
828  state.video_encoder_pool = mmal::pool_ptr(pool, [encoder](MMAL_POOL_T* ptr) {
829  if (encoder->output[0] && encoder->output[0]->is_enabled) {
830  mmal_port_disable(encoder->output[0]);
831  }
832  mmal_port_pool_destroy(encoder->output[0], ptr);
833  });
834  state.video_encoder_component.reset(encoder);
835 
836  ROS_DEBUG("Video encoder component done\n");
837 
838  return status;
839 
840 error:
841  if (encoder)
842  mmal_component_destroy(encoder);
843 
844  return status;
845 }
846 
855 static MMAL_STATUS_T create_splitter_component(RASPIVID_STATE& state) {
856  MMAL_COMPONENT_T* splitter = 0;
857  MMAL_PORT_T* splitter_input = nullptr;
858  MMAL_PORT_T *splitter_output_enc = nullptr, *splitter_output_raw = nullptr;
859  MMAL_STATUS_T status;
860  MMAL_POOL_T* pool;
861  MMAL_ES_FORMAT_T* format;
862 
863  status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_SPLITTER, &splitter);
864 
865  if (status != MMAL_SUCCESS) {
866  vcos_log_error("Unable to create image encoder component");
867  ROS_ERROR("Unable to create image encoder component");
868  goto error;
869  }
870 
871  if (!splitter->input_num) {
872  status = MMAL_ENOSYS;
873  ROS_ERROR("Video splitter doesn't have input ports");
874  goto error;
875  }
876 
877  if (splitter->output_num < 2) {
878  status = MMAL_ENOSYS;
879  ROS_ERROR("Video splitter doesn't have enough output ports");
880  goto error;
881  }
882 
883  /*** Input Port setup ***/
884 
885  splitter_input = splitter->input[0];
886 
887  // We want same format on input as camera output
888  mmal_format_copy(splitter_input->format, state.camera_component->output[mmal::camera_port::video]->format);
889 
890  if (splitter->input[0]->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
891  splitter->input[0]->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
892 
893  // Commit the port changes to the output port
894  status = mmal_port_format_commit(splitter_input);
895 
896  if (status != MMAL_SUCCESS) {
897  vcos_log_error("Unable to set format on splitter input port");
898  ROS_ERROR("Unable to set format on splitter input port");
899  goto error;
900  }
901 
902  /*** Output to image encoder setup ***/
903 
904  splitter_output_enc = splitter->output[0];
905 
906  // Copy the format from the splitter input
907  mmal_format_copy(splitter_output_enc->format, splitter_input->format);
908 
909  status = mmal_port_format_commit(splitter_output_enc);
910 
911  if (status != MMAL_SUCCESS) {
912  vcos_log_error("Unable to set format on splitter output port for image encoder");
913  goto error;
914  }
915 
916  /*** Output for raw ***/
917 
918  splitter_output_raw = splitter->output[1];
919 
920  // Copy the format from the splitter input
921  mmal_format_copy(splitter_output_raw->format, splitter_input->format);
922 
923  // Use BGR24 (bgr8 in ROS)
924  format = splitter_output_raw->format;
925  format->encoding = MMAL_ENCODING_BGR24;
926  format->encoding_variant = 0; /* Irrelevant when not in opaque mode */
927 
928  status = mmal_port_format_commit(splitter_output_raw);
929 
930  if (status != MMAL_SUCCESS) {
931  vcos_log_error("Unable to set format on splitter output port for raw");
932  goto error;
933  }
934 
935  /*** Setup all other output ports ***/
936 
937  // start from 2
938  for (unsigned int i = 2; i < splitter->output_num; i++) {
939  mmal_format_copy(splitter->output[i]->format, splitter_input->format);
940 
941  status = mmal_port_format_commit(splitter->output[i]);
942 
943  if (status != MMAL_SUCCESS) {
944  vcos_log_error("Unable to set format on splitter output port %d", i);
945  goto error;
946  }
947  }
948 
949  /*** Enable component ***/
950 
951  status = mmal_component_enable(splitter);
952 
953  if (status != MMAL_SUCCESS) {
954  vcos_log_error("Unable to enable splitter component");
955  ROS_ERROR("Unable to enable splitter component");
956  goto error;
957  }
958 
959  /*** Create Pool ***/
960 
961  // Create pool of buffer headers for the raw output port to consume
962  pool = mmal_port_pool_create(splitter_output_raw, splitter_output_raw->buffer_num, splitter_output_raw->buffer_size);
963 
964  if (!pool) {
965  vcos_log_error("Failed to create buffer header pool for image encoder output port %s", splitter_output_raw->name);
966  ROS_ERROR("Failed to create buffer header pool for image encoder output port %s", splitter_output_raw->name);
967  }
968 
969  /*** Push to state struct ***/
970 
971  state.splitter_pool = mmal::pool_ptr(pool, [splitter](MMAL_POOL_T* ptr) {
972  if (splitter->output[1] && splitter->output[1]->is_enabled) {
973  mmal_port_disable(splitter->output[1]);
974  }
975  mmal_port_pool_destroy(splitter->output[1], ptr);
976  });
977 
978  state.splitter_component.reset(splitter);
979 
980  ROS_INFO("splitter component done\n");
981 
982  return status;
983 
984 error:
985  if (splitter)
986  mmal_component_destroy(splitter);
987 
988  return status;
989 }
990 
1001 static MMAL_STATUS_T connect_ports(MMAL_PORT_T* output_port, MMAL_PORT_T* input_port,
1002  mmal::connection_ptr& connection) {
1003  MMAL_STATUS_T status;
1004 
1005  MMAL_CONNECTION_T* new_connection = nullptr;
1006 
1007  status = mmal_connection_create(&new_connection, output_port, input_port,
1008  MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT);
1009 
1010  if (status == MMAL_SUCCESS) {
1011  status = mmal_connection_enable(new_connection);
1012  if (status != MMAL_SUCCESS)
1013  mmal_connection_destroy(new_connection);
1014  }
1015 
1016  connection.reset(new_connection);
1017 
1018  return status;
1019 }
1020 
1025 int init_cam(RASPIVID_STATE& state) {
1026  MMAL_STATUS_T status;
1027  MMAL_PORT_T* camera_video_port = nullptr;
1028  MMAL_PORT_T* camera_preview_port = nullptr;
1029  MMAL_PORT_T* splitter_input_port = nullptr;
1030  MMAL_PORT_T* splitter_output_enc = nullptr;
1031  MMAL_PORT_T* splitter_output_raw = nullptr;
1032  MMAL_PORT_T* image_encoder_input_port = nullptr;
1033  MMAL_PORT_T* image_encoder_output_port = nullptr;
1034  MMAL_PORT_T* video_encoder_input_port = nullptr;
1035  MMAL_PORT_T* video_encoder_output_port = nullptr;
1036 
1037  bcm_host_init();
1038  // Register our application with the logging system
1039  vcos_log_register("RaspiVid", VCOS_LOG_CATEGORY);
1040 
1041  // OK, we have a nice set of parameters. Now set up our components
1042  // We have three components. Camera, splitter and encoder.
1043 
1044  if (!create_camera_component(state)) {
1045  ROS_ERROR("%s: Failed to create camera component", __func__);
1046  } else if ((status = create_image_encoder_component(state)) != MMAL_SUCCESS) {
1047  ROS_ERROR("%s: Failed to create image encoder component", __func__);
1048  state.camera_component.reset(nullptr);
1049  } else if ((status = create_video_encoder_component(state)) != MMAL_SUCCESS) {
1050  ROS_ERROR("%s: Failed to create H264 encoder component", __func__);
1051  state.image_encoder_component.reset(nullptr);
1052  state.camera_component.reset(nullptr);
1053  } else if ((status = create_splitter_component(state)) != MMAL_SUCCESS) {
1054  ROS_ERROR("%s: Failed to create splitter component", __func__);
1055  state.image_encoder_component.reset(nullptr);
1056  state.video_encoder_component.reset(nullptr);
1057  state.camera_component.reset(nullptr);
1058  } else {
1059  camera_video_port = state.camera_component->output[mmal::camera_port::video];
1060  camera_preview_port = state.camera_component->output[mmal::camera_port::preview];
1061  splitter_input_port = state.splitter_component->input[0];
1062  splitter_output_enc = state.splitter_component->output[0];
1063  image_encoder_input_port = state.image_encoder_component->input[0];
1064  video_encoder_input_port = state.video_encoder_component->input[0];
1065 
1066  status = connect_ports(camera_video_port, splitter_input_port, state.splitter_connection);
1067  if (status != MMAL_SUCCESS) {
1068  ROS_ERROR("%s: Failed to connect camera video port to splitter input", __func__);
1069  return 1;
1070  }
1071 
1072  status = connect_ports(splitter_output_enc, image_encoder_input_port, state.image_encoder_connection);
1073  if (status != MMAL_SUCCESS) {
1074  ROS_ERROR("%s: Failed to connect camera splitter port to image encoder input", __func__);
1075  return 1;
1076  }
1077 
1078  image_encoder_output_port = state.image_encoder_component->output[0];
1079 
1080  PORT_USERDATA* callback_data_enc = new PORT_USERDATA(state);
1081  callback_data_enc->buffer[0] = std::make_unique<uint8_t[]>(IMG_BUFFER_SIZE);
1082  callback_data_enc->buffer[1] = std::make_unique<uint8_t[]>(IMG_BUFFER_SIZE);
1083  // Set up our userdata - this is passed though to the callback where we
1084  // need the information.
1085  callback_data_enc->abort = false;
1086  callback_data_enc->id = 0;
1087  callback_data_enc->frame = 0;
1088  image_encoder_output_port->userdata = callback_data_enc;
1089  // Enable the image encoder output port and tell it its callback function
1090  status = mmal_port_enable(image_encoder_output_port, image_encoder_buffer_callback);
1091  if (status != MMAL_SUCCESS) {
1092  ROS_ERROR("Failed to setup image encoder output");
1093  return 1;
1094  }
1095 
1096  if (state.enable_imv_pub) {
1097  status = connect_ports(camera_preview_port, video_encoder_input_port, state.video_encoder_connection);
1098  if (status != MMAL_SUCCESS) {
1099  ROS_ERROR("%s: Failed to connect camera preview port to encoder input", __func__);
1100  return 1;
1101  }
1102 
1103  video_encoder_output_port = state.video_encoder_component->output[0];
1104  PORT_USERDATA* h264_callback_data_enc = new PORT_USERDATA(state);
1105  // Set up our userdata - this is passed though to the callback where we
1106  // need the information.
1107  video_encoder_output_port->userdata = h264_callback_data_enc;
1108  // Enable the encoder output port and tell it its callback function
1109  status = mmal_port_enable(video_encoder_output_port, video_encoder_buffer_callback);
1110  if (status != MMAL_SUCCESS) {
1111  ROS_ERROR("Failed to setup video encoder output");
1112  return 1;
1113  }
1114  }
1115 
1116  if (state.enable_raw_pub) {
1117  splitter_output_raw = state.splitter_component->output[1];
1118 
1119  PORT_USERDATA* callback_data_raw = new PORT_USERDATA(state);
1120  callback_data_raw->buffer[0] = std::make_unique<uint8_t[]>(IMG_BUFFER_SIZE);
1121  callback_data_raw->buffer[1] = std::make_unique<uint8_t[]>(IMG_BUFFER_SIZE);
1122  // Set up our userdata - this is passed though to the callback where we
1123  // need the information.
1124  callback_data_raw->abort = false;
1125  callback_data_raw->id = 0;
1126  callback_data_raw->frame = 0;
1127  splitter_output_raw->userdata = callback_data_raw;
1128  // Enable the splitter output port and tell it its callback function
1129  status = mmal_port_enable(splitter_output_raw, splitter_buffer_callback);
1130  if (status != MMAL_SUCCESS) {
1131  ROS_ERROR("Failed to setup splitter output");
1132  return 1;
1133  }
1134  }
1135  state.isInit = true;
1136  }
1137  return 0;
1138 }
1139 
1140 int start_capture(RASPIVID_STATE& state) {
1141  if (!(state.isInit))
1142  ROS_FATAL("Tried to start capture before camera is inited");
1143 
1144  MMAL_PORT_T* camera_video_port = state.camera_component->output[mmal::camera_port::video];
1145  MMAL_PORT_T* image_encoder_output_port = state.image_encoder_component->output[0];
1146  MMAL_PORT_T* video_encoder_output_port = state.video_encoder_component->output[0];
1147  MMAL_PORT_T* splitter_output_raw = state.splitter_component->output[1];
1148  ROS_INFO("Starting video capture (%d, %d, %d, %d)\n", state.width, state.height, state.quality, state.framerate);
1149 
1150  if (mmal_port_parameter_set_boolean(camera_video_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS) {
1151  return 1;
1152  }
1153  // Send all the buffers to the image encoder output port
1154  {
1155  int num = mmal_queue_length(state.image_encoder_pool->queue);
1156  int q;
1157  for (q = 0; q < num; q++) {
1158  MMAL_BUFFER_HEADER_T* buffer = mmal_queue_get(state.image_encoder_pool->queue);
1159 
1160  if (!buffer) {
1161  vcos_log_error("Unable to get a required buffer %d from pool queue", q);
1162  ROS_ERROR("Unable to get a required buffer %d from pool queue", q);
1163  }
1164 
1165  if (mmal_port_send_buffer(image_encoder_output_port, buffer) != MMAL_SUCCESS) {
1166  vcos_log_error("Unable to send a buffer to image encoder output port (%d)", q);
1167  ROS_ERROR("Unable to send a buffer to image encoder output port (%d)", q);
1168  }
1169  }
1170  }
1171  // Send all the buffers to the video encoder output port
1172  if (state.enable_imv_pub) {
1173  int num = mmal_queue_length(state.video_encoder_pool->queue);
1174  int q;
1175  for (q = 0; q < num; q++) {
1176  MMAL_BUFFER_HEADER_T* buffer = mmal_queue_get(state.video_encoder_pool->queue);
1177 
1178  if (!buffer) {
1179  vcos_log_error("Unable to get a required buffer %d from pool queue", q);
1180  ROS_ERROR("Unable to get a required buffer %d from pool queue", q);
1181  }
1182 
1183  if (mmal_port_send_buffer(video_encoder_output_port, buffer) != MMAL_SUCCESS) {
1184  vcos_log_error("Unable to send a buffer to video encoder output port (%d)", q);
1185  ROS_ERROR("Unable to send a buffer to video encoder output port (%d)", q);
1186  }
1187  }
1188  }
1189  // Send all the buffers to the splitter output port
1190  if (state.enable_raw_pub) {
1191  int num = mmal_queue_length(state.splitter_pool->queue);
1192  int q;
1193  for (q = 0; q < num; q++) {
1194  MMAL_BUFFER_HEADER_T* buffer = mmal_queue_get(state.splitter_pool->queue);
1195 
1196  if (!buffer) {
1197  vcos_log_error("Unable to get a required buffer %d from pool queue", q);
1198  ROS_ERROR("Unable to get a required buffer %d from pool queue", q);
1199  }
1200 
1201  if (mmal_port_send_buffer(splitter_output_raw, buffer) != MMAL_SUCCESS) {
1202  vcos_log_error("Unable to send a buffer to splitter output port (%d)", q);
1203  ROS_ERROR("Unable to send a buffer to splitter output port (%d)", q);
1204  }
1205  }
1206  }
1207  ROS_INFO("Video capture started\n");
1208  return 0;
1209 }
1210 
1211 int close_cam(RASPIVID_STATE& state) {
1212  if (state.isInit) {
1213  state.isInit = false;
1214  MMAL_COMPONENT_T* camera = state.camera_component.get();
1215  MMAL_COMPONENT_T* image_encoder = state.image_encoder_component.get();
1216  MMAL_COMPONENT_T* video_encoder = state.video_encoder_component.get();
1217  MMAL_COMPONENT_T* splitter = state.splitter_component.get();
1218 
1219  // Destroy image encoder port connection
1220  state.image_encoder_connection.reset(nullptr);
1221 
1222  // Destroy video encoder port connection
1223  state.video_encoder_connection.reset(nullptr);
1224 
1225  // Destroy splitter port connection
1226  state.splitter_connection.reset(nullptr);
1227 
1228  // Destroy image encoder component
1229  if (image_encoder) {
1230  // Get rid of any port buffers first
1231  state.image_encoder_pool.reset(nullptr);
1232  // Delete callback structure
1233  delete image_encoder->output[0]->userdata;
1234  state.image_encoder_component.reset(nullptr);
1235  }
1236 
1237  // Destroy video encoder component
1238  if (video_encoder) {
1239  // Get rid of any port buffers first
1240  state.video_encoder_pool.reset(nullptr);
1241  // Delete callback structure
1242  delete video_encoder->output[0]->userdata;
1243  state.video_encoder_component.reset(nullptr);
1244  }
1245 
1246  // Destroy splitter component
1247  if (splitter) {
1248  // Get rid of any port buffers first
1249  state.splitter_pool.reset(nullptr);
1250  // Delete callback structure
1251  if (splitter->output[1]->userdata) {
1252  delete splitter->output[1]->userdata;
1253  }
1254  state.splitter_component.reset(nullptr);
1255  }
1256 
1257  // destroy camera component
1258  if (camera) {
1259  state.camera_component.reset(nullptr);
1260  }
1261  ROS_INFO("Video capture stopped\n");
1262  return 0;
1263  } else
1264  return 1;
1265 }
1266 
1267 void reconfigure_callback(raspicam_node::CameraConfig& config, uint32_t level, RASPIVID_STATE& state) {
1268  ROS_DEBUG("figure Request: contrast %d, sharpness %d, brightness %d, "
1269  "saturation %d, ISO %d, exposureCompensation %d,"
1270  " videoStabilisation %d, vFlip %d, hFlip %d,"
1271  " zoom %.2f, exposure_mode %s, awb_mode %s, shutter_speed %d",
1272  config.contrast, config.sharpness, config.brightness, config.saturation, config.ISO,
1273  config.exposure_compensation, config.video_stabilisation, config.vFlip, config.hFlip, config.zoom,
1274  config.exposure_mode.c_str(), config.awb_mode.c_str(), config.shutter_speed);
1275 
1276  if (!state.camera_component.get()) {
1277  ROS_WARN("reconfiguring, but camera_component not initialized");
1278  return;
1279  }
1280 
1281  if (config.zoom < 1.0) {
1282  ROS_ERROR("Zoom value %f too small (must be at least 1.0)", config.zoom);
1283  } else {
1284  const double size = 1.0 / config.zoom;
1285  const double offset = (1.0 - size) / 2.0;
1286  PARAM_FLOAT_RECT_T roi;
1287  roi.x = roi.y = offset;
1288  roi.w = roi.h = size;
1289  raspicamcontrol_set_ROI(*state.camera_component, roi);
1290  }
1291 
1292  raspicamcontrol_set_exposure_mode(*state.camera_component, exposure_mode_from_string(config.exposure_mode.c_str()));
1293 
1294  raspicamcontrol_set_awb_mode(*state.camera_component, awb_mode_from_string(config.awb_mode.c_str()));
1295 
1296  raspicamcontrol_set_contrast(*state.camera_component, config.contrast);
1297  raspicamcontrol_set_sharpness(*state.camera_component, config.sharpness);
1298  raspicamcontrol_set_brightness(*state.camera_component, config.brightness);
1299  raspicamcontrol_set_saturation(*state.camera_component, config.saturation);
1300  raspicamcontrol_set_ISO(*state.camera_component, config.ISO);
1301  raspicamcontrol_set_exposure_compensation(*state.camera_component, config.exposure_compensation);
1302  raspicamcontrol_set_video_stabilisation(*state.camera_component, config.video_stabilisation);
1303  raspicamcontrol_set_flips(*state.camera_component, config.hFlip, config.vFlip);
1304  raspicamcontrol_set_shutter_speed(*state.camera_component, config.shutter_speed);
1305 
1306  ROS_DEBUG("Reconfigure done");
1307 }
1308 
1309 int main(int argc, char** argv) {
1310  ros::init(argc, argv, "raspicam_node");
1311  ros::NodeHandle nh_params("~");
1312 
1313  bool private_topics;
1314  nh_params.param<bool>("private_topics", private_topics, true);
1315 
1316  // The node handle used for topics will be private or public depending on the value of the ~private_topics parameter
1317  ros::NodeHandle nh_topics(private_topics ? std::string("~") : std::string());
1318 
1319  nh_params.param("skip_frames", skip_frames, 0);
1320 
1321  std::string camera_info_url;
1322  std::string camera_name;
1323 
1324  nh_params.param("camera_info_url", camera_info_url, std::string("package://raspicam_node/camera_info/camera.yaml"));
1325  nh_params.param("camera_name", camera_name, std::string("camera"));
1326 
1327  camera_info_manager::CameraInfoManager c_info_man(nh_params, camera_name, camera_info_url);
1328 
1329  RASPIVID_STATE state_srv;
1330 
1331  configure_parameters(state_srv, nh_params);
1332  init_cam(state_srv);
1333 
1334  if (!c_info_man.loadCameraInfo(camera_info_url)) {
1335  ROS_INFO("Calibration file missing. Camera not calibrated");
1336  } else {
1337  c_info = c_info_man.getCameraInfo();
1338  ROS_INFO("Camera successfully calibrated from default file");
1339  }
1340 
1341  if (!c_info_man.loadCameraInfo("")) {
1342  ROS_INFO("No device specifc calibration found");
1343  } else {
1344  c_info = c_info_man.getCameraInfo();
1345  ROS_INFO("Camera successfully calibrated from device specifc file");
1346  }
1347 
1348 
1349 
1350  // diagnostics parameters
1351  state_srv.updater.setHardwareID("raspicam");
1352  double desired_freq = state_srv.framerate;
1353  double min_freq = desired_freq * 0.95;
1354  double max_freq = desired_freq * 1.05;
1355 
1356  if (state_srv.enable_raw_pub){
1357  auto image_pub = nh_topics.advertise<sensor_msgs::Image>("image", 1);
1358  image.pub.reset(new DiagnosedPublisher<sensor_msgs::Image>(
1359  image_pub, state_srv.updater, FrequencyStatusParam(&min_freq, &max_freq, 0.1, 10), TimeStampStatusParam(0, 0.2)));
1360  }
1361  if (state_srv.enable_imv_pub) {
1362  auto imv_pub = nh_topics.advertise<raspicam_node::MotionVectors>("motion_vectors", 1);
1363  motion_vectors.pub.reset(new DiagnosedPublisher<raspicam_node::MotionVectors>(
1364  imv_pub, state_srv.updater, FrequencyStatusParam(&min_freq, &max_freq, 0.1, 10), TimeStampStatusParam(0, 0.2)));
1365  }
1366  auto cimage_pub = nh_topics.advertise<sensor_msgs::CompressedImage>("image/compressed", 1);
1367  compressed_image.pub.reset(new DiagnosedPublisher<sensor_msgs::CompressedImage>(
1368  cimage_pub, state_srv.updater, FrequencyStatusParam(&min_freq, &max_freq, 0.1, 10), TimeStampStatusParam(0, 0.2)));
1369 
1370  camera_info_pub = nh_topics.advertise<sensor_msgs::CameraInfo>("camera_info", 1);
1371 
1372  dynamic_reconfigure::Server<raspicam_node::CameraConfig> server;
1373  dynamic_reconfigure::Server<raspicam_node::CameraConfig>::CallbackType f;
1374  f = boost::bind(&reconfigure_callback, _1, _2, boost::ref(state_srv));
1375  server.setCallback(f);
1376 
1377  start_capture(state_srv);
1378  ros::spin();
1379  close_cam(state_srv);
1380  ros::shutdown();
1381 }
1382 
1383 #endif // __arm__ || __aarch64__
msg
bool param(const std::string &param_name, T &param_val, const T &default_val)
int raspicamcontrol_set_sharpness(MMAL_COMPONENT_T &camera, int sharpness)
#define ROS_FATAL(...)
ROSCPP_DECL void start()
int raspicamcontrol_set_exposure_compensation(MMAL_COMPONENT_T &camera, int exp_comp)
void publish(const boost::shared_ptr< M > &message) const
int raspicamcontrol_set_shutter_speed(MMAL_COMPONENT_T &camera, int shutter_speed)
f
int raspicamcontrol_set_brightness(MMAL_COMPONENT_T &camera, int brightness)
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
std::unique_ptr< MMAL_CONNECTION_T, connection_deleter > connection_ptr
int raspicamcontrol_set_video_stabilisation(MMAL_COMPONENT_T &camera, int vstabilisation)
updater
#define ROS_WARN(...)
std::unique_ptr< MMAL_COMPONENT_T, component_deleter > component_ptr
ROSCPP_DECL void spin(Spinner &spinner)
MMAL_PARAM_EXPOSUREMODE_T exposure_mode_from_string(const char *str)
std::unique_ptr< MMAL_POOL_T, std::function< void(MMAL_POOL_T *)> > pool_ptr
int raspicamcontrol_set_exposure_mode(MMAL_COMPONENT_T &camera, MMAL_PARAM_EXPOSUREMODE_T mode)
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
void raspicamcontrol_set_defaults(RASPICAM_CAMERA_PARAMETERS &params)
int raspicamcontrol_set_ROI(MMAL_COMPONENT_T &camera, PARAM_FLOAT_RECT_T rect)
int raspicamcontrol_set_flips(MMAL_COMPONENT_T &camera, int hflip, int vflip)
int raspicamcontrol_set_awb_mode(MMAL_COMPONENT_T &camera, MMAL_PARAM_AWBMODE_T awb_mode)
void default_delete_pool(MMAL_POOL_T *ptr)
int raspicamcontrol_set_ISO(MMAL_COMPONENT_T &camera, int ISO)
struct contain camera settings
MMAL_PARAM_AWBMODE_T awb_mode_from_string(const char *str)
def main()
Definition: imv_view.py:70
int raspicamcontrol_set_all_parameters(MMAL_COMPONENT_T &camera, const RASPICAM_CAMERA_PARAMETERS &params)
static Time now()
ROSCPP_DECL void shutdown()
int raspicamcontrol_set_contrast(MMAL_COMPONENT_T &camera, int contrast)
#define ROS_ERROR(...)
#define ROS_DEBUG(...)
int raspicamcontrol_set_saturation(MMAL_COMPONENT_T &camera, int saturation)


raspicam_node
Author(s):
autogenerated on Sun Jul 5 2020 03:45:18