summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2021-09-06 00:32:19 +0300
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2021-09-07 19:18:40 +0300
commit8926fe6d74a272b4a3e83f12a2fb244a53305906 (patch)
treefe72786440796561755a41cbb696910183804cc9
parent894ca69f60435e3402de5786682d621362979171 (diff)
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 <laurent.pinchart@ideasonboard.com> Reviewed-by: Hirokazu Honda <hiroh@chromium.org> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
-rw-r--r--src/cam/image.cpp109
-rw-r--r--src/cam/image.h52
-rw-r--r--src/cam/meson.build1
3 files changed, 162 insertions, 0 deletions
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 <assert.h>
+#include <errno.h>
+#include <iostream>
+#include <map>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+using namespace libcamera;
+
+std::unique_ptr<Image> Image::fromFrameBuffer(const FrameBuffer *buffer, MapMode mode)
+{
+ std::unique_ptr<Image> 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<int, MappedBufferInfo> 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<size_t>(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<uint8_t *>(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<uint8_t> &map : maps_)
+ munmap(map.data(), map.size());
+}
+
+unsigned int Image::numPlanes() const
+{
+ return planes_.size();
+}
+
+Span<uint8_t> Image::data(unsigned int plane)
+{
+ assert(plane <= planes_.size());
+ return planes_[plane];
+}
+
+Span<const uint8_t> 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 <memory>
+#include <stdint.h>
+#include <vector>
+
+#include <libcamera/base/class.h>
+#include <libcamera/base/flags.h>
+#include <libcamera/base/span.h>
+
+#include <libcamera/framebuffer.h>
+
+class Image
+{
+public:
+ enum class MapMode {
+ ReadOnly = 1 << 0,
+ WriteOnly = 1 << 1,
+ ReadWrite = ReadOnly | WriteOnly,
+ };
+
+ static std::unique_ptr<Image> fromFrameBuffer(const libcamera::FrameBuffer *buffer,
+ MapMode mode);
+
+ ~Image();
+
+ unsigned int numPlanes() const;
+
+ libcamera::Span<uint8_t> data(unsigned int plane);
+ libcamera::Span<const uint8_t> data(unsigned int plane) const;
+
+private:
+ LIBCAMERA_DISABLE_COPY(Image)
+
+ Image();
+
+ std::vector<libcamera::Span<uint8_t>> maps_;
+ std::vector<libcamera::Span<uint8_t>> 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',