/* 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.get();
		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.get();
		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];
}
tils?h=v0.1.0&amp;id=5e85157bcf156137259c57a2ebc5d5616dbb2e37'>utils</a>/<a href='/libcamera/libcamera.git/tree/utils/ipc?h=v0.1.0&amp;id=5e85157bcf156137259c57a2ebc5d5616dbb2e37'>ipc</a>/<a href='/libcamera/libcamera.git/tree/utils/ipc/mojo?h=v0.1.0&amp;id=5e85157bcf156137259c57a2ebc5d5616dbb2e37'>mojo</a>/<a href='/libcamera/libcamera.git/tree/utils/ipc/mojo/public?h=v0.1.0&amp;id=5e85157bcf156137259c57a2ebc5d5616dbb2e37'>public</a>/<a href='/libcamera/libcamera.git/tree/utils/ipc/mojo/public/LICENSE?h=v0.1.0&amp;id=5e85157bcf156137259c57a2ebc5d5616dbb2e37'>LICENSE</a></div><div class='content'>blob: 513e8a6a0a1d9a42818b02fd46b31fe88c653400 (<a href='/libcamera/libcamera.git/plain/utils/ipc/mojo/public/LICENSE?h=v0.1.0&amp;id=5e85157bcf156137259c57a2ebc5d5616dbb2e37'>plain</a>)
<table summary='blob content' class='blob'>
<tr><td class='linenumbers'><pre><a id='n1' href='#n1'>1</a>
<a id='n2' href='#n2'>2</a>
<a id='n3' href='#n3'>3</a>
<a id='n4' href='#n4'>4</a>
<a id='n5' href='#n5'>5</a>
<a id='n6' href='#n6'>6</a>
<a id='n7' href='#n7'>7</a>
<a id='n8' href='#n8'>8</a>
<a id='n9' href='#n9'>9</a>
<a id='n10' href='#n10'>10</a>
<a id='n11' href='#n11'>11</a>
<a id='n12' href='#n12'>12</a>
<a id='n13' href='#n13'>13</a>
<a id='n14' href='#n14'>14</a>
<a id='n15' href='#n15'>15</a>
<a id='n16' href='#n16'>16</a>
<a id='n17' href='#n17'>17</a>
<a id='n18' href='#n18'>18</a>
<a id='n19' href='#n19'>19</a>
<a id='n20' href='#n20'>20</a>
<a id='n21' href='#n21'>21</a>
<a id='n22' href='#n22'>22</a>
<a id='n23' href='#n23'>23</a>
<a id='n24' href='#n24'>24</a>
<a id='n25' href='#n25'>25</a>
<a id='n26' href='#n26'>26</a>
<a id='n27' href='#n27'>27</a>
</pre></td>
<td class='lines'><pre><code>// Copyright 2014 The Chromium Authors
//
// 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 Google Inc. 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
// &quot;AS IS&quot; 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.
</code></pre></td></tr></table>
</div> <!-- class=content -->
<div class='footer'>generated by <a href='https://git.zx2c4.com/cgit/about/'>cgit v1.2.1</a> (<a href='https://git-scm.com/'>git 2.18.0</a>) at 2025-03-25 17:28:09 +0000</div>
</div> <!-- id=cgit -->
</body>
</html>