[libcamera-devel,v2,4/7] libcamera: FrameBuffer: Add a method to copy buffer content

Message ID 20200326225844.4117712-5-niklas.soderlund@ragnatech.se
State Accepted
Headers show
Series
  • libcamera: Add support for a RAW still capture
Related show

Commit Message

Niklas Söderlund March 26, 2020, 10:58 p.m. UTC
This method may be used to memory copy a whole FrameBuffer content
from another buffer. The operation is not fast and should not be used
without great care by pipelines.

The intended use-case is to have an option to copy out RAW buffers from
the middle of a pipeline.

Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
* Changes since v1
- Update documentation
- s/NULL/nullptr/

* Changes since RFC
- Make method member of FrameBuffer
- Add documentation
- s/out/dstmem/ and s/in/src/mem/
---
 include/libcamera/buffer.h |  1 +
 src/libcamera/buffer.cpp   | 68 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 69 insertions(+)

Patch

diff --git a/include/libcamera/buffer.h b/include/libcamera/buffer.h
index 8e5ec699e3925eee..ef3a3b36cd4e4e17 100644
--- a/include/libcamera/buffer.h
+++ b/include/libcamera/buffer.h
@@ -57,6 +57,7 @@  public:
 	unsigned int cookie() const { return cookie_; }
 	void setCookie(unsigned int cookie) { cookie_ = cookie; }
 
+	int copyFrom(const FrameBuffer *src);
 private:
 	friend class Request; /* Needed to update request_. */
 	friend class V4L2VideoDevice; /* Needed to update metadata_. */
diff --git a/src/libcamera/buffer.cpp b/src/libcamera/buffer.cpp
index 673a63d3d1658190..93057568fc56a6f5 100644
--- a/src/libcamera/buffer.cpp
+++ b/src/libcamera/buffer.cpp
@@ -211,4 +211,72 @@  FrameBuffer::FrameBuffer(const std::vector<Plane> &planes, unsigned int cookie)
  * core never modifies the buffer cookie.
  */
 
+/**
+ * \brief Copy the contents from another buffer
+ * \param[in] src Buffer to copy
+ *
+ * Copy the buffer contents and metadata from \a src to this buffer. The
+ * destination FrameBuffer shall have the same number of planes as the source
+ * buffer, and each destination plane shall be larger than or equal to the
+ * corresponding source plane.
+ *
+ * The complete metadata of the source buffer is copied to the destination
+ * buffer. If an error occurs during the copy, the destination buffer's metadata
+ * status is set to FrameMetadata::FrameError, and other metadata fields are not
+ * modified.
+ *
+ * The operation is performed using memcpy() so is very slow, users needs to
+ * consider this before copying buffers.
+ *
+ * \return 0 on success or a negative error code otherwise
+ */
+int FrameBuffer::copyFrom(const FrameBuffer *src)
+{
+	if (planes_.size() != src->planes_.size()) {
+		LOG(Buffer, Error) << "Different number of planes";
+		metadata_.status = FrameMetadata::FrameError;
+		return -EINVAL;
+	}
+
+	for (unsigned int i = 0; i < planes_.size(); i++) {
+		if (planes_[i].length < src->planes_[i].length) {
+			LOG(Buffer, Error) << "Plane " << i << " is too small";
+			metadata_.status = FrameMetadata::FrameError;
+			return -EINVAL;
+		}
+	}
+
+	for (unsigned int i = 0; i < planes_.size(); i++) {
+		void *dstmem = mmap(nullptr, planes_[i].length, PROT_WRITE,
+				    MAP_SHARED, planes_[i].fd.fd(), 0);
+
+		if (dstmem == MAP_FAILED) {
+			LOG(Buffer, Error)
+				<< "Failed to map destination plane " << i;
+			metadata_.status = FrameMetadata::FrameError;
+			return -EINVAL;
+		}
+
+		void *srcmem = mmap(nullptr, src->planes_[i].length, PROT_READ,
+				    MAP_SHARED, src->planes_[i].fd.fd(), 0);
+
+		if (srcmem == MAP_FAILED) {
+			munmap(dstmem, planes_[i].length);
+			LOG(Buffer, Error)
+				<< "Failed to map source plane " << i;
+			metadata_.status = FrameMetadata::FrameError;
+			return -EINVAL;
+		}
+
+		memcpy(dstmem, srcmem, src->planes_[i].length);
+
+		munmap(srcmem, src->planes_[i].length);
+		munmap(dstmem, planes_[i].length);
+	}
+
+	metadata_ = src->metadata_;
+
+	return 0;
+}
+
 } /* namespace libcamera */