From dfdfcbd41aeae7ff1e227944512940f8a000383b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Hern=C3=A1ndez=20Cordero?= Date: Tue, 10 Oct 2023 19:16:55 +0200 Subject: [PATCH 1/3] Added AVIF image transport plugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alejandro Hernández Cordero --- avif_image_transport/CMakeLists.txt | 55 ++++ avif_image_transport/avif_plugins.xml | 19 ++ .../avif_image_transport/avif_common.hpp | 51 ++++ .../avif_image_transport/avif_publisher.hpp | 101 +++++++ .../avif_image_transport/avif_subscriber.hpp | 87 ++++++ avif_image_transport/package.xml | 25 ++ avif_image_transport/src/avif_publisher.cpp | 250 ++++++++++++++++++ avif_image_transport/src/avif_subscriber.cpp | 109 ++++++++ avif_image_transport/src/manifest.cpp | 38 +++ 9 files changed, 735 insertions(+) create mode 100644 avif_image_transport/CMakeLists.txt create mode 100644 avif_image_transport/avif_plugins.xml create mode 100644 avif_image_transport/include/avif_image_transport/avif_common.hpp create mode 100644 avif_image_transport/include/avif_image_transport/avif_publisher.hpp create mode 100644 avif_image_transport/include/avif_image_transport/avif_subscriber.hpp create mode 100644 avif_image_transport/package.xml create mode 100644 avif_image_transport/src/avif_publisher.cpp create mode 100644 avif_image_transport/src/avif_subscriber.cpp create mode 100644 avif_image_transport/src/manifest.cpp diff --git a/avif_image_transport/CMakeLists.txt b/avif_image_transport/CMakeLists.txt new file mode 100644 index 0000000..0a625ab --- /dev/null +++ b/avif_image_transport/CMakeLists.txt @@ -0,0 +1,55 @@ +cmake_minimum_required(VERSION 3.5) + +project(avif_image_transport) + +# Default to C++14 +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 14) +endif() + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +find_package(ament_cmake REQUIRED) +find_package(image_transport REQUIRED) +find_package(pluginlib REQUIRED) +find_package(rclcpp REQUIRED) +find_package(sensor_msgs REQUIRED) + +include_directories(include) + +add_library( + ${PROJECT_NAME} SHARED + src/avif_publisher.cpp + src/avif_subscriber.cpp + src/manifest.cpp +) + +target_link_libraries(${PROJECT_NAME} avif) + +ament_target_dependencies(${PROJECT_NAME} + "image_transport" + "rclcpp" + "pluginlib" + "sensor_msgs" +) + +install(TARGETS ${PROJECT_NAME} + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin +) + +install( + DIRECTORY "include/" + DESTINATION include +) +pluginlib_export_plugin_description_file(image_transport avif_plugins.xml) + +if(BUILD_TESTING) + find_package(ament_lint_auto REQUIRED) + ament_lint_auto_find_test_dependencies() +endif() + +ament_package() diff --git a/avif_image_transport/avif_plugins.xml b/avif_image_transport/avif_plugins.xml new file mode 100644 index 0000000..6b33653 --- /dev/null +++ b/avif_image_transport/avif_plugins.xml @@ -0,0 +1,19 @@ + + + + This plugin publishes a AVIF image + + + + + + This plugin decompresses a AVIF Image. + + + diff --git a/avif_image_transport/include/avif_image_transport/avif_common.hpp b/avif_image_transport/include/avif_image_transport/avif_common.hpp new file mode 100644 index 0000000..d4c4ae6 --- /dev/null +++ b/avif_image_transport/include/avif_image_transport/avif_common.hpp @@ -0,0 +1,51 @@ +// Copyright (c) 2023, Open Source Robotics Foundation, Inc. +// All rights reserved. +// +// Software License Agreement (BSD License 2.0) +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#ifndef AVIF_IMAGE_TRANSPORT__AVIF_COMMON_HPP_ +#define AVIF_IMAGE_TRANSPORT__AVIF_COMMON_HPP_ + +#include +#include + +namespace avif_image_transport +{ +using ParameterDescriptor = rcl_interfaces::msg::ParameterDescriptor; +using ParameterValue = rclcpp::ParameterValue; + +struct ParameterDefinition +{ + const ParameterValue defaultValue; + const ParameterDescriptor descriptor; +}; +} // namespace avif_image_transport + +#endif // AVIF_IMAGE_TRANSPORT__AVIF_COMMON_HPP_ diff --git a/avif_image_transport/include/avif_image_transport/avif_publisher.hpp b/avif_image_transport/include/avif_image_transport/avif_publisher.hpp new file mode 100644 index 0000000..9b16684 --- /dev/null +++ b/avif_image_transport/include/avif_image_transport/avif_publisher.hpp @@ -0,0 +1,101 @@ +// Copyright (c) 2023, Open Source Robotics Foundation, Inc. +// All rights reserved. +// +// Software License Agreement (BSD License 2.0) +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#ifndef AVIF_IMAGE_TRANSPORT__AVIF_PUBLISHER_HPP_ +#define AVIF_IMAGE_TRANSPORT__AVIF_PUBLISHER_HPP_ + +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include "avif_image_transport/avif_common.hpp" + +namespace avif_image_transport +{ +using CompressedImage = sensor_msgs::msg::CompressedImage; +using ParameterEvent = rcl_interfaces::msg::ParameterEvent; + +struct AvifImageDeleter +{ + void operator()(avifImage * image) {avifImageDestroy(image);} +}; + +using AvifImageUniquePtr = std::unique_ptr; + +class AVIFPublisher : public image_transport::SimplePublisherPlugin +{ +public: + AVIFPublisher(); + ~AVIFPublisher() override; + std::string getTransportName() const override; + +protected: + // Overridden to set up reconfigure server + void advertiseImpl( + rclcpp::Node * node, + const std::string & base_topic, + rmw_qos_profile_t custom_qos, + rclcpp::PublisherOptions options) override; + + void publish( + const sensor_msgs::msg::Image & message, + const PublishFn & publish_fn) const override; + + rclcpp::Logger logger_; + rclcpp::Node * node_; + +private: + AvifImageUniquePtr ConvertToAvif( + const sensor_msgs::msg::Image & message, + bool lossless, + int bit_depth) const; + + std::vector parameters_; + + avifEncoder * encoder_ = NULL; + + void declareParameter( + const std::string & base_name, + const ParameterDefinition & definition); +}; + +} // namespace avif_image_transport + +#endif // AVIF_IMAGE_TRANSPORT__AVIF_PUBLISHER_HPP_ diff --git a/avif_image_transport/include/avif_image_transport/avif_subscriber.hpp b/avif_image_transport/include/avif_image_transport/avif_subscriber.hpp new file mode 100644 index 0000000..7033a57 --- /dev/null +++ b/avif_image_transport/include/avif_image_transport/avif_subscriber.hpp @@ -0,0 +1,87 @@ +// Copyright (c) 2023, Open Source Robotics Foundation, Inc. +// All rights reserved. +// +// Software License Agreement (BSD License 2.0) +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#ifndef AVIF_IMAGE_TRANSPORT__AVIF_SUBSCRIBER_HPP_ +#define AVIF_IMAGE_TRANSPORT__AVIF_SUBSCRIBER_HPP_ + +#include + +#include +#include + +#include +#include + +#include +#include +#include + +#include "avif_image_transport/avif_common.hpp" + + +namespace avif_image_transport +{ +using CompressedImage = sensor_msgs::msg::CompressedImage; +using ParameterEvent = rcl_interfaces::msg::ParameterEvent; + +class AVIFSubscriber final + : public image_transport::SimpleSubscriberPlugin +{ +public: + AVIFSubscriber(); + virtual ~AVIFSubscriber() = default; + + std::string getTransportName() const override; + +protected: + void subscribeImpl( + rclcpp::Node *, + const std::string & base_topic, + const Callback & callback, + rmw_qos_profile_t custom_qos, + rclcpp::SubscriptionOptions options) override; + + void internalCallback( + const sensor_msgs::msg::CompressedImage::ConstSharedPtr & message, + const Callback & user_cb) override; + + rclcpp::Logger logger_; + rclcpp::Node * node_; + +private: + avifDecoder * decoder_; +}; + +} // namespace avif_image_transport + +#endif // AVIF_IMAGE_TRANSPORT__AVIF_SUBSCRIBER_HPP_ diff --git a/avif_image_transport/package.xml b/avif_image_transport/package.xml new file mode 100644 index 0000000..8c269d3 --- /dev/null +++ b/avif_image_transport/package.xml @@ -0,0 +1,25 @@ + + avif_image_transport + 3.2.0 + + avif_image_transport provides a plugin to image_transport for transparently sending images + encoded as avif + + Alejandro Hernandez Cordero + BSD + + http://www.ros.org/wiki/image_transport_plugins + Alejandro Hernandez Cordero + + ament_cmake + + image_transport + + ament_lint_auto + ament_lint_common + + + ament_cmake + + + diff --git a/avif_image_transport/src/avif_publisher.cpp b/avif_image_transport/src/avif_publisher.cpp new file mode 100644 index 0000000..417d0af --- /dev/null +++ b/avif_image_transport/src/avif_publisher.cpp @@ -0,0 +1,250 @@ +// Copyright (c) 2023, Open Source Robotics Foundation, Inc. +// All rights reserved. +// +// Software License Agreement (BSD License 2.0) +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include "avif_image_transport/avif_publisher.hpp" + +#include + +#include + +namespace avif_image_transport +{ + +enum avifParameters +{ + AVIF_QUALITY = 0, + AVIF_SPEED = 0, +}; + +const struct ParameterDefinition kParameters[] = +{ + { + // Quality - AVIF Compression Level from 0 to 100. A higher value means a smaller size. + ParameterValue(static_cast(75)), + ParameterDescriptor() + .set__name("quality") + .set__type(rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER) + .set__description("Quality") + .set__read_only(false) + .set__integer_range( + {rcl_interfaces::msg::IntegerRange() + .set__from_value(0) + .set__to_value(100) + .set__step(1)}) + }, + { + // Speed - 10 - Fastest, 0 - slowest + ParameterValue(static_cast(5)), + ParameterDescriptor() + .set__name("speed") + .set__type(rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER) + .set__description("Speed") + .set__read_only(false) + .set__integer_range( + {rcl_interfaces::msg::IntegerRange() + .set__from_value(0) + .set__to_value(10) + .set__step(1)}) + }, +}; + +AVIFPublisher::AVIFPublisher() +: logger_(rclcpp::get_logger("AVIFPublisher")) +{ + this->encoder_ = avifEncoderCreate(); +} + +AVIFPublisher::~AVIFPublisher() +{ + if (this->encoder_) {avifEncoderDestroy(this->encoder_);} +} + +std::string AVIFPublisher::getTransportName() const +{ + return "avif"; +} + +void AVIFPublisher::advertiseImpl( + rclcpp::Node * node, + const std::string & base_topic, + rmw_qos_profile_t custom_qos, + rclcpp::PublisherOptions options) +{ + node_ = node; + typedef image_transport::SimplePublisherPlugin Base; + Base::advertiseImpl(node, base_topic, custom_qos, options); + + // Declare Parameters + uint ns_len = node->get_effective_namespace().length(); + std::string param_base_name = base_topic.substr(ns_len); + std::replace(param_base_name.begin(), param_base_name.end(), '/', '.'); + + for (const ParameterDefinition & pd : kParameters) { + declareParameter(param_base_name, pd); + } +} + +AvifImageUniquePtr AVIFPublisher::ConvertToAvif( + const sensor_msgs::msg::Image & message, + bool lossless, + int bit_depth) const +{ + avifImage * result; + + const int width = message.width; + const int height = message.height; + if (message.encoding == "mono8") { + result = avifImageCreateEmpty(); + if (result == nullptr) { + RCLCPP_DEBUG(logger_, "Not able to create an empty image"); + return nullptr; + } + + result->width = width; + result->height = height; + result->depth = bit_depth; + result->yuvFormat = AVIF_PIXEL_FORMAT_YUV400; + result->colorPrimaries = AVIF_COLOR_PRIMARIES_UNSPECIFIED; + result->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED; + result->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_IDENTITY; + result->yuvRange = AVIF_RANGE_FULL; + memcpy(&result->yuvPlanes[0], &message.data[0], message.data.size()); + + // result->yuvPlanes[0] = message.data; + result->yuvRowBytes[0] = message.step; + result->imageOwnsYUVPlanes = AVIF_FALSE; + return AvifImageUniquePtr(result); + } + + if (lossless) { + result = + avifImageCreate(width, height, bit_depth, AVIF_PIXEL_FORMAT_YUV444); + if (result == nullptr) {return nullptr;} + result->colorPrimaries = AVIF_COLOR_PRIMARIES_UNSPECIFIED; + result->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED; + result->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_IDENTITY; + result->yuvRange = AVIF_RANGE_FULL; + } else { + result = + avifImageCreate(width, height, bit_depth, AVIF_PIXEL_FORMAT_YUV420); + if (result == nullptr) {return nullptr;} + result->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709; + result->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB; + result->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT601; + result->yuvRange = AVIF_RANGE_FULL; + } + + avifRGBImage rgba; + avifRGBImageSetDefaults(&rgba, result); + if (message.encoding == "bgr8") { + rgba.format = AVIF_RGB_FORMAT_BGR; + } else if (message.encoding == "bgra8") { + rgba.format = AVIF_RGB_FORMAT_BGRA; + } + + rgba.rowBytes = message.step; + rgba.depth = bit_depth; + + rgba.pixels = reinterpret_cast(const_cast(&message.data[0])); + + if (avifImageRGBToYUV(result, &rgba) != AVIF_RESULT_OK) { + avifImageDestroy(result); + return nullptr; + } + return AvifImageUniquePtr(result); +} + +void AVIFPublisher::publish( + const sensor_msgs::msg::Image & message, + const PublishFn & publish_fn) const +{ + int bit_depth = 8; + int speed = node_->get_parameter(parameters_[AVIF_SPEED]).get_value(); + this->encoder_->speed = speed; + + int quality = node_->get_parameter(parameters_[AVIF_QUALITY]).get_value(); + this->encoder_->minQuantizer = encoder_->maxQuantizer = + (AVIF_QUANTIZER_BEST_QUALITY - AVIF_QUANTIZER_WORST_QUALITY) * + quality / (100 - 0) + + AVIF_QUANTIZER_WORST_QUALITY; + + auto avif_image = ConvertToAvif(message, false, bit_depth); + if (avif_image == nullptr) { + return; + } + avifEncoderAddImage( + this->encoder_, avif_image.get(), /*durationInTimescale=*/ 1, + AVIF_ADD_IMAGE_FLAG_SINGLE); + + avifRWData encoded_data = AVIF_DATA_EMPTY; + + avifResult addImageResult = avifEncoderAddImage( + encoder_, + avif_image.get(), 1, AVIF_ADD_IMAGE_FLAG_SINGLE); + if (addImageResult != AVIF_RESULT_OK) { + // std::cout << "error encoding addImageResult: " << addImageResult << std::endl; + } + + avifResult finishResult = avifEncoderFinish(encoder_, &encoded_data); + if (finishResult != AVIF_RESULT_OK) { + // std::cout << "error encoding finishResult: " << finishResult << std::endl; + } + + sensor_msgs::msg::CompressedImage compressed; + compressed.data.resize(encoded_data.size); + memcpy(&compressed.data[0], encoded_data.data, encoded_data.size); + + publish_fn(compressed); +} + +void AVIFPublisher::declareParameter( + const std::string & base_name, + const ParameterDefinition & definition) +{ + // transport scoped parameter (e.g. image_raw.compressed.format) + const std::string transport_name = getTransportName(); + const std::string param_name = base_name + "." + transport_name + "." + + definition.descriptor.name; + parameters_.push_back(param_name); + + rclcpp::ParameterValue param_value; + + try { + param_value = node_->declare_parameter( + param_name, definition.defaultValue, + definition.descriptor); + } catch (const rclcpp::exceptions::ParameterAlreadyDeclaredException &) { + RCLCPP_DEBUG(logger_, "%s was previously declared", definition.descriptor.name.c_str()); + param_value = node_->get_parameter(param_name).get_parameter_value(); + } +} +} // namespace avif_image_transport diff --git a/avif_image_transport/src/avif_subscriber.cpp b/avif_image_transport/src/avif_subscriber.cpp new file mode 100644 index 0000000..c92ac7e --- /dev/null +++ b/avif_image_transport/src/avif_subscriber.cpp @@ -0,0 +1,109 @@ +// Copyright (c) 2023, Open Source Robotics Foundation, Inc. +// All rights reserved. +// +// Software License Agreement (BSD License 2.0) +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#include "avif_image_transport/avif_subscriber.hpp" + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include + + +namespace avif_image_transport +{ +AVIFSubscriber::AVIFSubscriber() +: logger_(rclcpp::get_logger("AVIFSubscriber")) +{ + this->decoder_ = avifDecoderCreate(); + + RCLCPP_DEBUG(logger_, "AVIFSubscriber"); +} + +std::string AVIFSubscriber::getTransportName() const +{ + return "avif"; +} + +void AVIFSubscriber::subscribeImpl( + rclcpp::Node * node, + const std::string & base_topic, + const Callback & callback, + rmw_qos_profile_t custom_qos, + rclcpp::SubscriptionOptions options) +{ + node_ = node; + logger_ = node->get_logger(); + typedef image_transport::SimpleSubscriberPlugin Base; + Base::subscribeImpl(node, base_topic, callback, custom_qos, options); +} + +void AVIFSubscriber::internalCallback( + const sensor_msgs::msg::CompressedImage::ConstSharedPtr & msg, + const Callback & user_cb) +{ + avifDecoderSetIOMemory( + this->decoder_, &msg->data[0], + msg->data.size()); + avifImage * avif_image = avifImageCreateEmpty(); + avifDecoderReadMemory( + this->decoder_, avif_image, &msg->data[0], + msg->data.size()); + + auto result = std::make_shared(); + result->height = avif_image->height; + result->width = avif_image->width; + result->is_bigendian = false; + result->step = avif_image->yuvRowBytes[0] * 3; + result->encoding = "rgb8"; + result->data.resize(result->height * result->width * 3); + + avifRGBImage rgba; + avifRGBImageSetDefaults(&rgba, avif_image); + rgba.format = AVIF_RGB_FORMAT_BGR; + rgba.rowBytes = result->step; + rgba.depth = 8; + rgba.pixels = reinterpret_cast(const_cast(&result->data[0])); + avifImageYUVToRGB(avif_image, &rgba); + + user_cb(result); + avifImageDestroy(avif_image); +} +} // namespace avif_image_transport diff --git a/avif_image_transport/src/manifest.cpp b/avif_image_transport/src/manifest.cpp new file mode 100644 index 0000000..5940f40 --- /dev/null +++ b/avif_image_transport/src/manifest.cpp @@ -0,0 +1,38 @@ +// Copyright (c) 2023, Open Source Robotics Foundation, Inc. +// All rights reserved. +// +// Software License Agreement (BSD License 2.0) +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include +#include "avif_image_transport/avif_publisher.hpp" +#include "avif_image_transport/avif_subscriber.hpp" + +PLUGINLIB_EXPORT_CLASS(avif_image_transport::AVIFPublisher, image_transport::PublisherPlugin) +PLUGINLIB_EXPORT_CLASS(avif_image_transport::AVIFSubscriber, image_transport::SubscriberPlugin) From 4ae9a12e3b23a641166e5b96cb837abe6854c23e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Hern=C3=A1ndez=20Cordero?= Date: Wed, 11 Oct 2023 13:14:55 +0200 Subject: [PATCH 2/3] Fixed reentrant callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alejandro Hernández Cordero --- .../include/avif_image_transport/avif_subscriber.hpp | 3 +++ avif_image_transport/src/avif_subscriber.cpp | 12 +++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/avif_image_transport/include/avif_image_transport/avif_subscriber.hpp b/avif_image_transport/include/avif_image_transport/avif_subscriber.hpp index 7033a57..330c076 100644 --- a/avif_image_transport/include/avif_image_transport/avif_subscriber.hpp +++ b/avif_image_transport/include/avif_image_transport/avif_subscriber.hpp @@ -36,6 +36,8 @@ #include +#include +#include #include #include @@ -80,6 +82,7 @@ class AVIFSubscriber final private: avifDecoder * decoder_; + std::mutex mutex; }; } // namespace avif_image_transport diff --git a/avif_image_transport/src/avif_subscriber.cpp b/avif_image_transport/src/avif_subscriber.cpp index c92ac7e..c5b0ac3 100644 --- a/avif_image_transport/src/avif_subscriber.cpp +++ b/avif_image_transport/src/avif_subscriber.cpp @@ -35,10 +35,8 @@ #include -#include -#include -#include -#include +#include +#include #include @@ -79,9 +77,9 @@ void AVIFSubscriber::internalCallback( const sensor_msgs::msg::CompressedImage::ConstSharedPtr & msg, const Callback & user_cb) { - avifDecoderSetIOMemory( - this->decoder_, &msg->data[0], - msg->data.size()); + // if the reentract callback is configure this mutex is required + std::unique_lock guard(this->mutex); + avifImage * avif_image = avifImageCreateEmpty(); avifDecoderReadMemory( this->decoder_, avif_image, &msg->data[0], From b3515ba07680297a0b06ed31690c0d2e5cbf06d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Hern=C3=A1ndez=20Cordero?= Date: Thu, 12 Oct 2023 12:16:54 +0200 Subject: [PATCH 3/3] fixed enum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alejandro Hernández Cordero --- avif_image_transport/src/avif_publisher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avif_image_transport/src/avif_publisher.cpp b/avif_image_transport/src/avif_publisher.cpp index 417d0af..6797f58 100644 --- a/avif_image_transport/src/avif_publisher.cpp +++ b/avif_image_transport/src/avif_publisher.cpp @@ -42,7 +42,7 @@ namespace avif_image_transport enum avifParameters { AVIF_QUALITY = 0, - AVIF_SPEED = 0, + AVIF_SPEED = 1, }; const struct ParameterDefinition kParameters[] =