blob: 75b2693281a74cdc818e390b923883968debb70c [file] [log] [blame]
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2019, Google Inc.
*
* buffer.cpp - Buffer handling
*/
#include <libcamera/buffer.h>
#include "libcamera/internal/buffer.h"
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include "libcamera/internal/log.h"
/**
* \file libcamera/buffer.h
* \brief Buffer handling
*
* \file libcamera/internal/buffer.h
* \brief Internal buffer handling support
*/
namespace libcamera {
LOG_DEFINE_CATEGORY(Buffer)
/**
* \struct FrameMetadata
* \brief Metadata related to a captured frame
*
* The FrameMetadata structure stores all metadata related to a captured frame,
* as stored in a FrameBuffer, such as capture status, timestamp and bytesused.
*/
/**
* \enum FrameMetadata::Status
* \brief Define the frame completion status
* \var FrameMetadata::FrameSuccess
* The frame has been captured with success and contains valid data. All fields
* of the FrameMetadata structure are valid.
* \var FrameMetadata::FrameError
* An error occurred during capture of the frame. The frame data may be partly
* or fully invalid. The sequence and timestamp fields of the FrameMetadata
* structure is valid, the other fields may be invalid.
* \var FrameMetadata::FrameCancelled
* Capture stopped before the frame completed. The frame data is not valid. All
* fields of the FrameMetadata structure but the status field are invalid.
*/
/**
* \struct FrameMetadata::Plane
* \brief Per-plane frame metadata
*
* Frames are stored in memory in one or multiple planes. The
* FrameMetadata::Plane structure stores per-plane metadata.
*/
/**
* \var FrameMetadata::Plane::bytesused
* \brief Number of bytes occupied by the data in the plane, including line
* padding
*
* This value may vary per frame for compressed formats. For uncompressed
* formats it will be constant for all frames, but may be smaller than the
* FrameBuffer size.
*/
/**
* \var FrameMetadata::status
* \brief Status of the frame
*
* The validity of other fields of the FrameMetadata structure depends on the
* status value.
*/
/**
* \var FrameMetadata::sequence
* \brief Frame sequence number
*
* The sequence number is a monotonically increasing number assigned to the
* frames captured by the stream. The value is increased by one for each frame.
* Gaps in the sequence numbers indicate dropped frames.
*/
/**
* \var FrameMetadata::timestamp
* \brief Time when the frame was captured
*
* The timestamp is expressed as a number of nanoseconds relative to the system
* clock since an unspecified time point.
*
* \todo Be more precise on what timestamps refer to.
*/
/**
* \var FrameMetadata::planes
* \brief Array of per-plane metadata
*/
/**
* \class FrameBuffer
* \brief Frame buffer data and its associated dynamic metadata
*
* The FrameBuffer class is the primary interface for applications, IPAs and
* pipeline handlers to interact with frame memory. It contains all the static
* and dynamic information to manage the whole life cycle of a frame capture,
* from buffer creation to consumption.
*
* The static information describes the memory planes that make a frame. The
* planes are specified when creating the FrameBuffer and are expressed as a set
* of dmabuf file descriptors and length.
*
* The dynamic information is grouped in a FrameMetadata instance. It is updated
* during the processing of a queued capture request, and is valid from the
* completion of the buffer as signaled by Camera::bufferComplete() until the
* FrameBuffer is either reused in a new request or deleted.
*
* The creator of a FrameBuffer (application, IPA or pipeline handler) may
* associate to it an integer cookie for any private purpose. The cookie may be
* set when creating the FrameBuffer, and updated at any time with setCookie().
* The cookie is transparent to the libcamera core and shall only be set by the
* creator of the FrameBuffer. This mechanism supplements the Request cookie.
*/
/**
* \struct FrameBuffer::Plane
* \brief A memory region to store a single plane of a frame
*
* Planar pixel formats use multiple memory regions to store the different
* colour components of a frame. The Plane structure describes such a memory
* region by a dmabuf file descriptor and a length. A FrameBuffer then
* contains one or multiple planes, depending on the pixel format of the
* frames it is meant to store.
*
* To support DMA access, planes are associated with dmabuf objects represented
* by FileDescriptor handles. The Plane class doesn't handle mapping of the
* memory to the CPU, but applications and IPAs may use the dmabuf file
* descriptors to map the plane memory with mmap() and access its contents.
*
* \todo Once we have a Kernel API which can express offsets within a plane
* this structure shall be extended to contain this information. See commit
* 83148ce8be55e for initial documentation of this feature.
*/
/**
* \var FrameBuffer::Plane::fd
* \brief The dmabuf file descriptor
*/
/**
* \var FrameBuffer::Plane::length
* \brief The plane length in bytes
*/
/**
* \brief Construct a FrameBuffer with an array of planes
* \param[in] planes The frame memory planes
* \param[in] cookie Cookie
*/
FrameBuffer::FrameBuffer(const std::vector<Plane> &planes, unsigned int cookie)
: planes_(planes), request_(nullptr), cookie_(cookie)
{
}
/**
* \fn FrameBuffer::planes()
* \brief Retrieve the static plane descriptors
* \return Array of plane descriptors
*/
/**
* \fn FrameBuffer::request()
* \brief Retrieve the request this buffer belongs to
*
* The intended callers of this method are buffer completion handlers that
* need to associate a buffer to the request it belongs to.
*
* A FrameBuffer is associated to a request by Request::addBuffer() and the
* association is valid until the buffer completes. The returned request
* pointer is valid only during that interval.
*
* \return The Request the FrameBuffer belongs to, or nullptr if the buffer is
* not associated with a request
*/
/**
* \fn FrameBuffer::setRequest()
* \brief Set the request this buffer belongs to
* \param[in] request Request to set
*
* The intended callers of this method are pipeline handlers and only for
* buffers that are internal to the pipeline.
*
* \todo Shall be hidden from applications with a d-pointer design.
*/
/**
* \fn FrameBuffer::metadata()
* \brief Retrieve the dynamic metadata
* \return Dynamic metadata for the frame contained in the buffer
*/
/**
* \fn FrameBuffer::cookie()
* \brief Retrieve the cookie
*
* The cookie belongs to the creator of the FrameBuffer, which controls its
* lifetime and value.
*
* \sa setCookie()
*
* \return The cookie
*/
/**
* \fn FrameBuffer::setCookie()
* \brief Set the cookie
* \param[in] cookie Cookie to set
*
* The cookie belongs to the creator of the FrameBuffer. Its value may be
* modified at any time with this method. Applications and IPAs shall not modify
* the cookie value of buffers they haven't created themselves. The libcamera
* core never modifies the buffer cookie.
*/
/**
* \class MappedBuffer
* \brief Provide an interface to support managing memory mapped buffers
*
* The MappedBuffer interface provides access to a set of MappedPlanes which
* are available for access by the CPU.
*
* This class is not meant to be constructed directly, but instead derived
* classes should be used to implement the correct mapping of a source buffer.
*
* This allows treating CPU accessible memory through a generic interface
* regardless of whether it originates from a libcamera FrameBuffer or other
* source.
*/
/**
* \typedef MappedBuffer::Plane
* \brief A mapped region of memory accessible to the CPU
*
* The MappedBuffer::Plane uses the Span interface to describe the mapped memory
* region.
*/
/**
* \brief Construct an empty MappedBuffer
*/
MappedBuffer::MappedBuffer()
: error_(0)
{
}
/**
* \brief Move constructor, construct the MappedBuffer with the contents of \a
* other using move semantics
* \param[in] other The other MappedBuffer
*
* Moving a MappedBuffer moves the mappings contained in the \a other to the new
* MappedBuffer and invalidates the \a other.
*
* No mappings are unmapped or destroyed in this process.
*/
MappedBuffer::MappedBuffer(MappedBuffer &&other)
{
*this = std::move(other);
}
/**
* \brief Move assignment operator, replace the mappings with those of \a other
* \param[in] other The other MappedBuffer
*
* Moving a MappedBuffer moves the mappings contained in the \a other to the new
* MappedBuffer and invalidates the \a other.
*
* No mappings are unmapped or destroyed in this process.
*/
MappedBuffer &MappedBuffer::operator=(MappedBuffer &&other)
{
error_ = other.error_;
maps_ = std::move(other.maps_);
other.error_ = -ENOENT;
return *this;
}
MappedBuffer::~MappedBuffer()
{
for (Plane &map : maps_)
munmap(map.data(), map.size());
}
/**
* \fn MappedBuffer::isValid()
* \brief Check if the MappedBuffer instance is valid
* \return True if the MappedBuffer has valid mappings, false otherwise
*/
/**
* \fn MappedBuffer::error()
* \brief Retrieve the map error status
*
* This function retrieves the error status from the MappedBuffer.
* The error status is a negative number as defined by errno.h. If
* no error occurred, this function returns 0.
*
* \return The map error code
*/
/**
* \fn MappedBuffer::maps()
* \brief Retrieve the mapped planes
*
* This function retrieves the successfully mapped planes stored as a vector
* of Span<uint8_t> to provide access to the mapped memory.
*
* \return A vector of the mapped planes
*/
/**
* \var MappedBuffer::error_
* \brief Stores the error value if present
*
* MappedBuffer derived classes shall set this to a negative value as defined
* by errno.h if an error occured during the mapping process.
*/
/**
* \var MappedBuffer::maps_
* \brief Stores the internal mapped planes
*
* MappedBuffer derived classes shall store the mappings they create in this
* vector which is parsed during destruct to unmap any memory mappings which
* completed successfully.
*/
/**
* \class MappedFrameBuffer
* \brief Map a FrameBuffer using the MappedBuffer interface
*/
/**
* \brief Map all planes of a FrameBuffer
* \param[in] buffer FrameBuffer to be mapped
* \param[in] flags Protection flags to apply to map
*
* Construct an object to map a frame buffer for CPU access.
* The flags are passed directly to mmap and should be either PROT_READ,
* PROT_WRITE, or a bitwise-or combination of both.
*/
MappedFrameBuffer::MappedFrameBuffer(const FrameBuffer *buffer, int flags)
{
maps_.reserve(buffer->planes().size());
for (const FrameBuffer::Plane &plane : buffer->planes()) {
void *address = mmap(nullptr, plane.length, flags,
MAP_SHARED, plane.fd.fd(), 0);
if (address == MAP_FAILED) {
error_ = -errno;
LOG(Buffer, Error) << "Failed to mmap plane";
break;
}
maps_.emplace_back(static_cast<uint8_t *>(address), plane.length);
}
}
} /* namespace libcamera */