From 8926fe6d74a272b4a3e83f12a2fb244a53305906 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 6 Sep 2021 00:32:19 +0300 Subject: cam: Add Image class The new Image class represents a multi-planar image with direct access to pixel data. It currently duplicates the function of the MappedFrameBuffer class which is internal to libcamera, and will serve as a design playground to improve the API until it is considered ready to be made part of the libcamera public API. Signed-off-by: Laurent Pinchart Reviewed-by: Hirokazu Honda Reviewed-by: Kieran Bingham --- src/cam/image.cpp | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/cam/image.h | 52 +++++++++++++++++++++++++ src/cam/meson.build | 1 + 3 files changed, 162 insertions(+) create mode 100644 src/cam/image.cpp create mode 100644 src/cam/image.h diff --git a/src/cam/image.cpp b/src/cam/image.cpp new file mode 100644 index 00000000..0180be78 --- /dev/null +++ b/src/cam/image.cpp @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Ideas on Board Oy + * + * image.cpp - Multi-planar image with access to pixel data + */ + +#include "image.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace libcamera; + +std::unique_ptr Image::fromFrameBuffer(const FrameBuffer *buffer, MapMode mode) +{ + std::unique_ptr image{ new Image() }; + + assert(!buffer->planes().empty()); + + int mmapFlags = 0; + + if (mode & MapMode::ReadOnly) + mmapFlags |= PROT_READ; + + if (mode & MapMode::WriteOnly) + mmapFlags |= PROT_WRITE; + + struct MappedBufferInfo { + uint8_t *address = nullptr; + size_t mapLength = 0; + size_t dmabufLength = 0; + }; + std::map mappedBuffers; + + for (const FrameBuffer::Plane &plane : buffer->planes()) { + const int fd = plane.fd.fd(); + if (mappedBuffers.find(fd) == mappedBuffers.end()) { + const size_t length = lseek(fd, 0, SEEK_END); + mappedBuffers[fd] = MappedBufferInfo{ nullptr, 0, length }; + } + + const size_t length = mappedBuffers[fd].dmabufLength; + + if (plane.offset > length || + plane.offset + plane.length > length) { + std::cerr << "plane is out of buffer: buffer length=" + << length << ", plane offset=" << plane.offset + << ", plane length=" << plane.length + << std::endl; + return nullptr; + } + size_t &mapLength = mappedBuffers[fd].mapLength; + mapLength = std::max(mapLength, + static_cast(plane.offset + plane.length)); + } + + for (const FrameBuffer::Plane &plane : buffer->planes()) { + const int fd = plane.fd.fd(); + auto &info = mappedBuffers[fd]; + if (!info.address) { + void *address = mmap(nullptr, info.mapLength, mmapFlags, + MAP_SHARED, fd, 0); + if (address == MAP_FAILED) { + int error = -errno; + std::cerr << "Failed to mmap plane: " + << strerror(-error) << std::endl; + return nullptr; + } + + info.address = static_cast(address); + image->maps_.emplace_back(info.address, info.mapLength); + } + + image->planes_.emplace_back(info.address + plane.offset, plane.length); + } + + return image; +} + +Image::Image() = default; + +Image::~Image() +{ + for (Span &map : maps_) + munmap(map.data(), map.size()); +} + +unsigned int Image::numPlanes() const +{ + return planes_.size(); +} + +Span Image::data(unsigned int plane) +{ + assert(plane <= planes_.size()); + return planes_[plane]; +} + +Span Image::data(unsigned int plane) const +{ + assert(plane <= planes_.size()); + return planes_[plane]; +} diff --git a/src/cam/image.h b/src/cam/image.h new file mode 100644 index 00000000..f7fc5b27 --- /dev/null +++ b/src/cam/image.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Ideas on Board Oy + * + * image.h - Multi-planar image with access to pixel data + */ +#ifndef __CAM_IMAGE_H__ +#define __CAM_IMAGE_H__ + +#include +#include +#include + +#include +#include +#include + +#include + +class Image +{ +public: + enum class MapMode { + ReadOnly = 1 << 0, + WriteOnly = 1 << 1, + ReadWrite = ReadOnly | WriteOnly, + }; + + static std::unique_ptr fromFrameBuffer(const libcamera::FrameBuffer *buffer, + MapMode mode); + + ~Image(); + + unsigned int numPlanes() const; + + libcamera::Span data(unsigned int plane); + libcamera::Span data(unsigned int plane) const; + +private: + LIBCAMERA_DISABLE_COPY(Image) + + Image(); + + std::vector> maps_; + std::vector> planes_; +}; + +namespace libcamera { +LIBCAMERA_FLAGS_ENABLE_OPERATORS(Image::MapMode) +} + +#endif /* __CAM_IMAGE_H__ */ diff --git a/src/cam/meson.build b/src/cam/meson.build index ea36aaa5..e8e2ae57 100644 --- a/src/cam/meson.build +++ b/src/cam/meson.build @@ -14,6 +14,7 @@ cam_sources = files([ 'event_loop.cpp', 'file_sink.cpp', 'frame_sink.cpp', + 'image.cpp', 'main.cpp', 'options.cpp', 'stream_options.cpp', -- cgit v1.2.1