33 int main(
int argc,
char** argv) {
34 (void)fprintf(stderr,
"The raspicam_node for the x86/64 architecture is a fake!\n");
40 #if defined(__arm__) || defined(__aarch64__) 50 #define VCOS_ALWAYS_WANT_LOGGING 51 #define VERSION_STRING "v1.2" 54 #include "interface/vcos/vcos.h" 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" 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" 77 #include <dynamic_reconfigure/server.h> 78 #include <raspicam_node/CameraConfig.h> 82 static constexpr
int IMG_BUFFER_SIZE = 10 * 1024 * 1024;
85 static constexpr
int VIDEO_FRAME_RATE_DEN = 1;
88 static constexpr
int VIDEO_OUTPUT_BUFFERS_NUM = 3;
92 struct 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)
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];
141 RASPIVID_STATE& pstate;
147 int frames_skipped = 0;
156 struct DiagnosedMsgPublisher {
157 std::unique_ptr<DiagnosedPublisher<T>> pub;
161 static DiagnosedMsgPublisher<sensor_msgs::Image> image;
162 static DiagnosedMsgPublisher<sensor_msgs::CompressedImage> compressed_image;
163 static DiagnosedMsgPublisher<raspicam_node::MotionVectors> motion_vectors;
166 sensor_msgs::CameraInfo c_info;
167 std::string camera_frame_id;
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);
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;
190 nh.
param<std::string>(
"camera_frame_id", camera_frame_id,
"");
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);
200 nh.
param<
bool>(
"hFlip", temp,
false);
201 state.camera_parameters.hflip = temp;
202 nh.
param<
bool>(
"vFlip", temp,
false);
203 state.camera_parameters.vflip = temp;
204 nh.
param<
int>(
"shutter_speed", state.camera_parameters.shutter_speed, 0);
205 nh.
param<
int>(
"contrast", state.camera_parameters.contrast, 1);
207 state.isInit =
false;
218 static void image_encoder_buffer_callback(MMAL_PORT_T* port, MMAL_BUFFER_HEADER_T* buffer) {
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);
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);
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);
245 bool complete =
false;
246 if (buffer->flags & (MMAL_BUFFER_HEADER_FLAG_FRAME_END | MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED))
250 if (pData->id != INT_MAX) {
252 if (skip_frames > 0 && pData->frames_skipped < skip_frames) {
253 pData->frames_skipped++;
255 pData->frames_skipped = 0;
257 compressed_image.msg.header.seq = pData->frame;
258 compressed_image.msg.header.frame_id = camera_frame_id;
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);
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);
274 pData->pstate.updater.update();
282 mmal_buffer_header_release(buffer);
285 if (port->is_enabled) {
286 MMAL_STATUS_T status;
288 MMAL_BUFFER_HEADER_T* new_buffer = mmal_queue_get(pData->pstate.image_encoder_pool->queue);
291 status = mmal_port_send_buffer(port, new_buffer);
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");
308 static void video_encoder_buffer_callback(MMAL_PORT_T* port, MMAL_BUFFER_HEADER_T* buffer) {
310 PORT_USERDATA* pData = port->userdata;
312 if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO) {
314 motion_vectors.msg.header.seq = pData->frame;
315 motion_vectors.msg.header.frame_id = camera_frame_id;
319 motion_vectors.msg.mbx = pData->pstate.width / 16;
320 if (pData->pstate.width % 16)
321 motion_vectors.msg.mbx++;
323 motion_vectors.msg.mby = pData->pstate.height / 16;
324 if (pData->pstate.height % 16)
325 motion_vectors.msg.mby++;
327 mmal_buffer_header_mem_lock(buffer);
330 struct __attribute__((__packed__)) imv {
334 }* imv =
reinterpret_cast<struct imv*
>(buffer->data);
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);
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;
348 mmal_buffer_header_mem_unlock(buffer);
350 motion_vectors.pub->publish(motion_vectors.msg);
355 mmal_buffer_header_release(buffer);
358 if (port->is_enabled) {
359 MMAL_STATUS_T status;
361 MMAL_BUFFER_HEADER_T* new_buffer = mmal_queue_get(pData->pstate.video_encoder_pool->queue);
364 status = mmal_port_send_buffer(port, new_buffer);
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");
373 static void splitter_buffer_callback(MMAL_PORT_T* port, MMAL_BUFFER_HEADER_T* buffer) {
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);
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);
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);
400 int complete =
false;
401 if (buffer->flags & (MMAL_BUFFER_HEADER_FLAG_FRAME_END | MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED))
405 if (pData->id != INT_MAX) {
407 if (skip_frames > 0 && pData->frames_skipped < skip_frames) {
408 pData->frames_skipped++;
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);
432 mmal_buffer_header_release(buffer);
435 if (port->is_enabled) {
436 MMAL_STATUS_T status;
438 MMAL_BUFFER_HEADER_T* new_buffer = mmal_queue_get(pData->pstate.splitter_pool->queue);
441 status = mmal_port_send_buffer(port, new_buffer);
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");
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;
465 status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera);
467 if (status != MMAL_SUCCESS) {
468 vcos_log_error(
"Failed to create camera component");
469 ROS_ERROR(
"Failed to create camera component");
473 if (!camera->output_num) {
474 vcos_log_error(
"Camera doesn't have output ports");
475 ROS_ERROR(
"Camera doesn't have output ports");
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;
499 mmal_port_parameter_set(camera->control, &cam_config.hdr);
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;
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);
520 format = video_port->format;
521 format->encoding_variant = MMAL_ENCODING_I420;
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;
533 status = mmal_port_format_commit(video_port);
536 vcos_log_error(
"camera video format couldn't be set");
537 ROS_ERROR(
"camera video format couldn't be set");
542 if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
543 video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
547 format = preview_port->format;
548 format->encoding_variant = MMAL_ENCODING_I420;
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;
560 status = mmal_port_format_commit(preview_port);
563 vcos_log_error(
"camera preview format couldn't be set");
564 ROS_ERROR(
"camera preview format couldn't be set");
569 if (preview_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
570 preview_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
574 format = still_port->format;
576 format->encoding = MMAL_ENCODING_OPAQUE;
577 format->encoding_variant = MMAL_ENCODING_I420;
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;
588 status = mmal_port_format_commit(still_port);
591 vcos_log_error(
"camera still format couldn't be set");
592 ROS_ERROR(
"camera still format couldn't be set");
596 video_port->buffer_num = video_port->buffer_num_recommended;
598 if (still_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
599 still_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
602 status = mmal_component_enable(camera);
605 vcos_log_error(
"camera component couldn't be enabled");
606 ROS_ERROR(
"camera component couldn't be enabled");
612 state.camera_component.reset(camera);
621 mmal_component_destroy(camera);
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;
639 status = mmal_component_create(MMAL_COMPONENT_DEFAULT_IMAGE_ENCODER, &encoder);
641 if (status != MMAL_SUCCESS) {
642 vcos_log_error(
"Unable to create image encoder component");
643 ROS_ERROR(
"Unable to create image encoder component");
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");
654 encoder_input = encoder->input[0];
655 encoder_output = encoder->output[0];
658 mmal_format_copy(encoder_output->format, encoder_input->format);
661 encoder_output->format->encoding = MMAL_ENCODING_JPEG;
663 encoder_output->buffer_size = encoder_output->buffer_size_recommended;
665 if (encoder_output->buffer_size < encoder_output->buffer_size_min)
666 encoder_output->buffer_size = encoder_output->buffer_size_min;
668 encoder_output->buffer_num = encoder_output->buffer_num_recommended;
670 if (encoder_output->buffer_num < encoder_output->buffer_num_min)
671 encoder_output->buffer_num = encoder_output->buffer_num_min;
674 status = mmal_port_format_commit(encoder_output);
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");
683 status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_JPEG_Q_FACTOR, state.quality);
685 if (status != MMAL_SUCCESS) {
686 vcos_log_error(
"Unable to set JPEG quality");
692 status = mmal_component_enable(encoder);
694 if (status != MMAL_SUCCESS) {
695 vcos_log_error(
"Unable to enable image encoder component");
696 ROS_ERROR(
"Unable to enable image encoder component");
701 pool = mmal_port_pool_create(encoder_output, encoder_output->buffer_num, encoder_output->buffer_size);
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);
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]);
712 mmal_port_pool_destroy(encoder->output[0], ptr);
714 state.image_encoder_component.reset(encoder);
716 ROS_DEBUG(
"Image encoder component done\n");
722 mmal_component_destroy(encoder);
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;
741 status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_ENCODER, &encoder);
743 if (status != MMAL_SUCCESS) {
744 vcos_log_error(
"Unable to create video encoder component");
745 ROS_ERROR(
"Unable to create video encoder component");
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");
756 encoder_input = encoder->input[0];
757 encoder_output = encoder->output[0];
760 mmal_format_copy(encoder_output->format, encoder_input->format);
763 encoder_output->format->encoding = MMAL_ENCODING_H264;
765 encoder_output->buffer_size = encoder_output->buffer_size_recommended;
767 if (encoder_output->buffer_size < encoder_output->buffer_size_min)
768 encoder_output->buffer_size = encoder_output->buffer_size_min;
770 encoder_output->buffer_num = encoder_output->buffer_num_recommended;
772 if (encoder_output->buffer_num < encoder_output->buffer_num_min)
773 encoder_output->buffer_num = encoder_output->buffer_num_min;
776 encoder_output->format->bitrate = 17000000;
780 encoder_output->format->es->video.frame_rate.num = 0;
781 encoder_output->format->es->video.frame_rate.den = 1;
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");
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, ¶m.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");
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");
812 status = mmal_component_enable(encoder);
814 if (status != MMAL_SUCCESS) {
815 vcos_log_error(
"Unable to enable video encoder component");
816 ROS_ERROR(
"Unable to enable video encoder component");
821 pool = mmal_port_pool_create(encoder_output, encoder_output->buffer_num, encoder_output->buffer_size);
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);
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]);
832 mmal_port_pool_destroy(encoder->output[0], ptr);
834 state.video_encoder_component.reset(encoder);
836 ROS_DEBUG(
"Video encoder component done\n");
842 mmal_component_destroy(encoder);
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;
861 MMAL_ES_FORMAT_T* format;
863 status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_SPLITTER, &splitter);
865 if (status != MMAL_SUCCESS) {
866 vcos_log_error(
"Unable to create image encoder component");
867 ROS_ERROR(
"Unable to create image encoder component");
871 if (!splitter->input_num) {
872 status = MMAL_ENOSYS;
873 ROS_ERROR(
"Video splitter doesn't have input ports");
877 if (splitter->output_num < 2) {
878 status = MMAL_ENOSYS;
879 ROS_ERROR(
"Video splitter doesn't have enough output ports");
885 splitter_input = splitter->input[0];
890 if (splitter->input[0]->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
891 splitter->input[0]->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
894 status = mmal_port_format_commit(splitter_input);
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");
904 splitter_output_enc = splitter->output[0];
907 mmal_format_copy(splitter_output_enc->format, splitter_input->format);
909 status = mmal_port_format_commit(splitter_output_enc);
911 if (status != MMAL_SUCCESS) {
912 vcos_log_error(
"Unable to set format on splitter output port for image encoder");
918 splitter_output_raw = splitter->output[1];
921 mmal_format_copy(splitter_output_raw->format, splitter_input->format);
924 format = splitter_output_raw->format;
925 format->encoding = MMAL_ENCODING_BGR24;
926 format->encoding_variant = 0;
928 status = mmal_port_format_commit(splitter_output_raw);
930 if (status != MMAL_SUCCESS) {
931 vcos_log_error(
"Unable to set format on splitter output port for raw");
938 for (
unsigned int i = 2; i < splitter->output_num; i++) {
939 mmal_format_copy(splitter->output[i]->format, splitter_input->format);
941 status = mmal_port_format_commit(splitter->output[i]);
943 if (status != MMAL_SUCCESS) {
944 vcos_log_error(
"Unable to set format on splitter output port %d", i);
951 status = mmal_component_enable(splitter);
953 if (status != MMAL_SUCCESS) {
954 vcos_log_error(
"Unable to enable splitter component");
955 ROS_ERROR(
"Unable to enable splitter component");
962 pool = mmal_port_pool_create(splitter_output_raw, splitter_output_raw->buffer_num, splitter_output_raw->buffer_size);
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);
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]);
975 mmal_port_pool_destroy(splitter->output[1], ptr);
978 state.splitter_component.reset(splitter);
980 ROS_INFO(
"splitter component done\n");
986 mmal_component_destroy(splitter);
1001 static MMAL_STATUS_T connect_ports(MMAL_PORT_T* output_port, MMAL_PORT_T* input_port,
1003 MMAL_STATUS_T status;
1005 MMAL_CONNECTION_T* new_connection =
nullptr;
1007 status = mmal_connection_create(&new_connection, output_port, input_port,
1008 MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT);
1010 if (status == MMAL_SUCCESS) {
1011 status = mmal_connection_enable(new_connection);
1012 if (status != MMAL_SUCCESS)
1013 mmal_connection_destroy(new_connection);
1016 connection.reset(new_connection);
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;
1039 vcos_log_register(
"RaspiVid", VCOS_LOG_CATEGORY);
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);
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];
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__);
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__);
1078 image_encoder_output_port = state.image_encoder_component->output[0];
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);
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;
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");
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__);
1103 video_encoder_output_port = state.video_encoder_component->output[0];
1104 PORT_USERDATA* h264_callback_data_enc =
new PORT_USERDATA(state);
1107 video_encoder_output_port->userdata = h264_callback_data_enc;
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");
1116 if (state.enable_raw_pub) {
1117 splitter_output_raw = state.splitter_component->output[1];
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);
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;
1129 status = mmal_port_enable(splitter_output_raw, splitter_buffer_callback);
1130 if (status != MMAL_SUCCESS) {
1131 ROS_ERROR(
"Failed to setup splitter output");
1135 state.isInit =
true;
1140 int start_capture(RASPIVID_STATE& state) {
1141 if (!(state.isInit))
1142 ROS_FATAL(
"Tried to start capture before camera is inited");
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);
1150 if (mmal_port_parameter_set_boolean(camera_video_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS) {
1155 int num = mmal_queue_length(state.image_encoder_pool->queue);
1157 for (q = 0; q < num; q++) {
1158 MMAL_BUFFER_HEADER_T* buffer = mmal_queue_get(state.image_encoder_pool->queue);
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);
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);
1172 if (state.enable_imv_pub) {
1173 int num = mmal_queue_length(state.video_encoder_pool->queue);
1175 for (q = 0; q < num; q++) {
1176 MMAL_BUFFER_HEADER_T* buffer = mmal_queue_get(state.video_encoder_pool->queue);
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);
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);
1190 if (state.enable_raw_pub) {
1191 int num = mmal_queue_length(state.splitter_pool->queue);
1193 for (q = 0; q < num; q++) {
1194 MMAL_BUFFER_HEADER_T* buffer = mmal_queue_get(state.splitter_pool->queue);
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);
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);
1207 ROS_INFO(
"Video capture started\n");
1211 int close_cam(RASPIVID_STATE& state) {
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();
1220 state.image_encoder_connection.reset(
nullptr);
1223 state.video_encoder_connection.reset(
nullptr);
1226 state.splitter_connection.reset(
nullptr);
1229 if (image_encoder) {
1231 state.image_encoder_pool.reset(
nullptr);
1233 delete image_encoder->output[0]->userdata;
1234 state.image_encoder_component.reset(
nullptr);
1238 if (video_encoder) {
1240 state.video_encoder_pool.reset(
nullptr);
1242 delete video_encoder->output[0]->userdata;
1243 state.video_encoder_component.reset(
nullptr);
1249 state.splitter_pool.reset(
nullptr);
1251 if (splitter->output[1]->userdata) {
1252 delete splitter->output[1]->userdata;
1254 state.splitter_component.reset(
nullptr);
1259 state.camera_component.reset(
nullptr);
1261 ROS_INFO(
"Video capture stopped\n");
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);
1276 if (!state.camera_component.get()) {
1277 ROS_WARN(
"reconfiguring, but camera_component not initialized");
1281 if (config.zoom < 1.0) {
1282 ROS_ERROR(
"Zoom value %f too small (must be at least 1.0)", config.zoom);
1284 const double size = 1.0 / config.zoom;
1285 const double offset = (1.0 - size) / 2.0;
1287 roi.
x = roi.
y = offset;
1288 roi.
w = roi.
h = size;
1309 int main(
int argc,
char** argv) {
1313 bool private_topics;
1314 nh_params.param<
bool>(
"private_topics", private_topics,
true);
1317 ros::NodeHandle nh_topics(private_topics ? std::string(
"~") : std::string());
1319 nh_params.param(
"skip_frames", skip_frames, 0);
1321 std::string camera_info_url;
1322 std::string camera_name;
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"));
1329 RASPIVID_STATE state_srv;
1331 configure_parameters(state_srv, nh_params);
1332 init_cam(state_srv);
1334 if (!c_info_man.loadCameraInfo(camera_info_url)) {
1335 ROS_INFO(
"Calibration file missing. Camera not calibrated");
1337 c_info = c_info_man.getCameraInfo();
1338 ROS_INFO(
"Camera successfully calibrated from default file");
1341 if (!c_info_man.loadCameraInfo(
"")) {
1342 ROS_INFO(
"No device specifc calibration found");
1344 c_info = c_info_man.getCameraInfo();
1345 ROS_INFO(
"Camera successfully calibrated from device specifc file");
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;
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)));
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)));
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)));
1370 camera_info_pub = nh_topics.advertise<sensor_msgs::CameraInfo>(
"camera_info", 1);
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);
1377 start_capture(state_srv);
1379 close_cam(state_srv);
1383 #endif // __arm__ || __aarch64__
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val)
int raspicamcontrol_set_sharpness(MMAL_COMPONENT_T &camera, int sharpness)
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)
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)
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)
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
void raspicamcontrol_set_defaults(RASPICAM_CAMERA_PARAMETERS ¶ms)
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)
int raspicamcontrol_set_all_parameters(MMAL_COMPONENT_T &camera, const RASPICAM_CAMERA_PARAMETERS ¶ms)
ROSCPP_DECL void shutdown()
int raspicamcontrol_set_contrast(MMAL_COMPONENT_T &camera, int contrast)
int raspicamcontrol_set_saturation(MMAL_COMPONENT_T &camera, int saturation)