PipelineHandler::queueRequest() is asynchronously invoked in Camera::queueRequest(). Therefore the return value of PipelineHandler::queueRequest() is useless. This changes the function to a void function. Signed-off-by: Hirokazu Honda <hiroh@chromium.org> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
1112 lines
36 KiB
C++
1112 lines
36 KiB
C++
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
/*
|
|
* Copyright (C) 2018, Google Inc.
|
|
*
|
|
* camera.cpp - Camera device
|
|
*/
|
|
|
|
#include <libcamera/camera.h>
|
|
|
|
#include <array>
|
|
#include <atomic>
|
|
#include <iomanip>
|
|
|
|
#include <libcamera/framebuffer_allocator.h>
|
|
#include <libcamera/request.h>
|
|
#include <libcamera/stream.h>
|
|
|
|
#include "libcamera/internal/log.h"
|
|
#include "libcamera/internal/pipeline_handler.h"
|
|
#include "libcamera/internal/thread.h"
|
|
|
|
/**
|
|
* \file camera.h
|
|
* \brief Camera device handling
|
|
*
|
|
* \page camera-model Camera Model
|
|
*
|
|
* libcamera acts as a middleware between applications and camera hardware. It
|
|
* provides a solution to an unsolvable problem: reconciling applications,
|
|
* which need to run on different systems without dealing with device-specific
|
|
* details, and camera hardware, which exhibits a wide variety of features,
|
|
* limitations and architecture variations. In order to do so, it creates an
|
|
* abstract camera model that hides the camera hardware from applications. The
|
|
* model is designed to strike the right balance between genericity, to please
|
|
* generic applications, and flexibility, to expose even the most specific
|
|
* hardware features to the most demanding applications.
|
|
*
|
|
* In libcamera, a Camera is defined as a device that can capture frames
|
|
* continuously from a camera sensor and store them in memory. If supported by
|
|
* the device and desired by the application, the camera may store each
|
|
* captured frame in multiple copies, possibly in different formats and sizes.
|
|
* Each of these memory outputs of the camera is called a Stream.
|
|
*
|
|
* A camera contains a single image source, and separate camera instances
|
|
* relate to different image sources. For instance, a phone containing front
|
|
* and back image sensors will be modelled with two cameras, one for each
|
|
* sensor. When multiple streams can be produced from the same image source,
|
|
* all those streams are guaranteed to be part of the same camera.
|
|
*
|
|
* While not sharing image sources, separate cameras can share other system
|
|
* resources, such as ISPs. For this reason camera instances may not be fully
|
|
* independent, in which case usage restrictions may apply. For instance, a
|
|
* phone with a front and a back camera may not allow usage of the two cameras
|
|
* simultaneously.
|
|
*
|
|
* The camera model defines an implicit pipeline, whose input is the camera
|
|
* sensor, and whose outputs are the streams. Along the pipeline, the frames
|
|
* produced by the camera sensor are transformed by the camera into a format
|
|
* suitable for applications, with image processing that improves the quality
|
|
* of the captured frames. The camera exposes a set of controls that
|
|
* applications may use to manually control the processing steps. This
|
|
* high-level camera model is the minimum baseline that all cameras must
|
|
* conform to.
|
|
*
|
|
* \section camera-pipeline-model Pipeline Model
|
|
*
|
|
* Camera hardware differs in the supported image processing operations and the
|
|
* order in which they are applied. The libcamera pipelines abstract the
|
|
* hardware differences and expose a logical view of the processing operations
|
|
* with a fixed order. This offers low-level control of those operations to
|
|
* applications, while keeping application code generic.
|
|
*
|
|
* Starting from the camera sensor, a pipeline applies the following
|
|
* operations, in that order.
|
|
*
|
|
* - Pixel exposure
|
|
* - Analog to digital conversion and readout
|
|
* - Black level subtraction
|
|
* - Defective pixel correction
|
|
* - Lens shading correction
|
|
* - Spatial noise filtering
|
|
* - Per-channel gains (white balance)
|
|
* - Demosaicing (color filter array interpolation)
|
|
* - Color correction matrix (typically RGB to RGB)
|
|
* - Gamma correction
|
|
* - Color space transformation (typically RGB to YUV)
|
|
* - Cropping
|
|
* - Scaling
|
|
*
|
|
* Not all cameras implement all operations, and they are not necessarily
|
|
* implemented in the above order at the hardware level. The libcamera pipeline
|
|
* handlers translate the pipeline model to the real hardware configuration.
|
|
*
|
|
* \subsection digital-zoom Digital Zoom
|
|
*
|
|
* Digital zoom is implemented as a combination of the cropping and scaling
|
|
* stages of the pipeline. Cropping is controlled explicitly through the
|
|
* controls::ScalerCrop control, while scaling is controlled implicitly based
|
|
* on the crop rectangle and the output stream size. The crop rectangle is
|
|
* expressed relatively to the full pixel array size and indicates how the field
|
|
* of view is affected by the pipeline.
|
|
*/
|
|
|
|
namespace libcamera {
|
|
|
|
LOG_DECLARE_CATEGORY(Camera)
|
|
|
|
/**
|
|
* \class CameraConfiguration
|
|
* \brief Hold configuration for streams of the camera
|
|
|
|
* The CameraConfiguration holds an ordered list of stream configurations. It
|
|
* supports iterators and operates as a vector of StreamConfiguration instances.
|
|
* The stream configurations are inserted by addConfiguration(), and the
|
|
* operator[](int) returns a reference to the StreamConfiguration based on its
|
|
* insertion index. Accessing a stream configuration with an invalid index
|
|
* results in undefined behaviour.
|
|
*
|
|
* CameraConfiguration instances are retrieved from the camera with
|
|
* Camera::generateConfiguration(). Applications may then inspect the
|
|
* configuration, modify it, and possibly add new stream configuration entries
|
|
* with addConfiguration(). Once the camera configuration satisfies the
|
|
* application, it shall be validated by a call to validate(). The validation
|
|
* implements "try" semantics: it adjusts invalid configurations to the closest
|
|
* achievable parameters instead of rejecting them completely. Applications
|
|
* then decide whether to accept the modified configuration, or try again with
|
|
* a different set of parameters. Once the configuration is valid, it is passed
|
|
* to Camera::configure().
|
|
*/
|
|
|
|
/**
|
|
* \enum CameraConfiguration::Status
|
|
* \brief Validity of a camera configuration
|
|
* \var CameraConfiguration::Valid
|
|
* The configuration is fully valid
|
|
* \var CameraConfiguration::Adjusted
|
|
* The configuration has been adjusted to a valid configuration
|
|
* \var CameraConfiguration::Invalid
|
|
* The configuration is invalid and can't be adjusted automatically
|
|
*/
|
|
|
|
/**
|
|
* \typedef CameraConfiguration::iterator
|
|
* \brief Iterator for the stream configurations in the camera configuration
|
|
*/
|
|
|
|
/**
|
|
* \typedef CameraConfiguration::const_iterator
|
|
* \brief Const iterator for the stream configuration in the camera
|
|
* configuration
|
|
*/
|
|
|
|
/**
|
|
* \brief Create an empty camera configuration
|
|
*/
|
|
CameraConfiguration::CameraConfiguration()
|
|
: transform(Transform::Identity), config_({})
|
|
{
|
|
}
|
|
|
|
CameraConfiguration::~CameraConfiguration()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* \brief Add a stream configuration to the camera configuration
|
|
* \param[in] cfg The stream configuration
|
|
*/
|
|
void CameraConfiguration::addConfiguration(const StreamConfiguration &cfg)
|
|
{
|
|
config_.push_back(cfg);
|
|
}
|
|
|
|
/**
|
|
* \fn CameraConfiguration::validate()
|
|
* \brief Validate and possibly adjust the camera configuration
|
|
*
|
|
* This method adjusts the camera configuration to the closest valid
|
|
* configuration and returns the validation status.
|
|
*
|
|
* \todo: Define exactly when to return each status code. Should stream
|
|
* parameters set to 0 by the caller be adjusted without returning Adjusted ?
|
|
* This would potentially be useful for applications but would get in the way
|
|
* in Camera::configure(). Do we need an extra status code to signal this ?
|
|
*
|
|
* \todo: Handle validation of buffers count when refactoring the buffers API.
|
|
*
|
|
* \return A CameraConfiguration::Status value that describes the validation
|
|
* status.
|
|
* \retval CameraConfiguration::Invalid The configuration is invalid and can't
|
|
* be adjusted. This may only occur in extreme cases such as when the
|
|
* configuration is empty.
|
|
* \retval CameraConfigutation::Adjusted The configuration has been adjusted
|
|
* and is now valid. Parameters may have changed for any stream, and stream
|
|
* configurations may have been removed. The caller shall check the
|
|
* configuration carefully.
|
|
* \retval CameraConfiguration::Valid The configuration was already valid and
|
|
* hasn't been adjusted.
|
|
*/
|
|
|
|
/**
|
|
* \brief Retrieve a reference to a stream configuration
|
|
* \param[in] index Numerical index
|
|
*
|
|
* The \a index represents the zero based insertion order of stream
|
|
* configuration into the camera configuration with addConfiguration(). Calling
|
|
* this method with an invalid index results in undefined behaviour.
|
|
*
|
|
* \return The stream configuration
|
|
*/
|
|
StreamConfiguration &CameraConfiguration::at(unsigned int index)
|
|
{
|
|
return config_[index];
|
|
}
|
|
|
|
/**
|
|
* \brief Retrieve a const reference to a stream configuration
|
|
* \param[in] index Numerical index
|
|
*
|
|
* The \a index represents the zero based insertion order of stream
|
|
* configuration into the camera configuration with addConfiguration(). Calling
|
|
* this method with an invalid index results in undefined behaviour.
|
|
*
|
|
* \return The stream configuration
|
|
*/
|
|
const StreamConfiguration &CameraConfiguration::at(unsigned int index) const
|
|
{
|
|
return config_[index];
|
|
}
|
|
|
|
/**
|
|
* \fn StreamConfiguration &CameraConfiguration::operator[](unsigned int)
|
|
* \brief Retrieve a reference to a stream configuration
|
|
* \param[in] index Numerical index
|
|
*
|
|
* The \a index represents the zero based insertion order of stream
|
|
* configuration into the camera configuration with addConfiguration(). Calling
|
|
* this method with an invalid index results in undefined behaviour.
|
|
*
|
|
* \return The stream configuration
|
|
*/
|
|
|
|
/**
|
|
* \fn const StreamConfiguration &CameraConfiguration::operator[](unsigned int) const
|
|
* \brief Retrieve a const reference to a stream configuration
|
|
* \param[in] index Numerical index
|
|
*
|
|
* The \a index represents the zero based insertion order of stream
|
|
* configuration into the camera configuration with addConfiguration(). Calling
|
|
* this method with an invalid index results in undefined behaviour.
|
|
*
|
|
* \return The stream configuration
|
|
*/
|
|
|
|
/**
|
|
* \brief Retrieve an iterator to the first stream configuration in the
|
|
* sequence
|
|
* \return An iterator to the first stream configuration
|
|
*/
|
|
CameraConfiguration::iterator CameraConfiguration::begin()
|
|
{
|
|
return config_.begin();
|
|
}
|
|
|
|
/**
|
|
* \brief Retrieve a const iterator to the first element of the stream
|
|
* configurations
|
|
* \return A const iterator to the first stream configuration
|
|
*/
|
|
CameraConfiguration::const_iterator CameraConfiguration::begin() const
|
|
{
|
|
return config_.begin();
|
|
}
|
|
|
|
/**
|
|
* \brief Retrieve an iterator pointing to the past-the-end stream
|
|
* configuration in the sequence
|
|
* \return An iterator to the element following the last stream configuration
|
|
*/
|
|
CameraConfiguration::iterator CameraConfiguration::end()
|
|
{
|
|
return config_.end();
|
|
}
|
|
|
|
/**
|
|
* \brief Retrieve a const iterator pointing to the past-the-end stream
|
|
* configuration in the sequence
|
|
* \return A const iterator to the element following the last stream
|
|
* configuration
|
|
*/
|
|
CameraConfiguration::const_iterator CameraConfiguration::end() const
|
|
{
|
|
return config_.end();
|
|
}
|
|
|
|
/**
|
|
* \brief Check if the camera configuration is empty
|
|
* \return True if the configuration is empty
|
|
*/
|
|
bool CameraConfiguration::empty() const
|
|
{
|
|
return config_.empty();
|
|
}
|
|
|
|
/**
|
|
* \brief Retrieve the number of stream configurations
|
|
* \return Number of stream configurations
|
|
*/
|
|
std::size_t CameraConfiguration::size() const
|
|
{
|
|
return config_.size();
|
|
}
|
|
|
|
/**
|
|
* \var CameraConfiguration::transform
|
|
* \brief User-specified transform to be applied to the image
|
|
*
|
|
* The transform is a user-specified 2D plane transform that will be applied
|
|
* to the camera images by the processing pipeline before being handed to
|
|
* the application. This is subsequent to any transform that is already
|
|
* required to fix up any platform-defined rotation.
|
|
*
|
|
* The usual 2D plane transforms are allowed here (horizontal/vertical
|
|
* flips, multiple of 90-degree rotations etc.), but the validate() function
|
|
* may adjust this field at its discretion if the selection is not supported.
|
|
*/
|
|
|
|
/**
|
|
* \var CameraConfiguration::config_
|
|
* \brief The vector of stream configurations
|
|
*/
|
|
|
|
class Camera::Private : public Extensible::Private
|
|
{
|
|
LIBCAMERA_DECLARE_PUBLIC(Camera)
|
|
|
|
public:
|
|
enum State {
|
|
CameraAvailable,
|
|
CameraAcquired,
|
|
CameraConfigured,
|
|
CameraStopping,
|
|
CameraRunning,
|
|
};
|
|
|
|
Private(Camera *camera, PipelineHandler *pipe, const std::string &id,
|
|
const std::set<Stream *> &streams);
|
|
~Private();
|
|
|
|
int isAccessAllowed(State state, bool allowDisconnected = false,
|
|
const char *from = __builtin_FUNCTION()) const;
|
|
int isAccessAllowed(State low, State high,
|
|
bool allowDisconnected = false,
|
|
const char *from = __builtin_FUNCTION()) const;
|
|
|
|
void disconnect();
|
|
void setState(State state);
|
|
|
|
std::shared_ptr<PipelineHandler> pipe_;
|
|
std::string id_;
|
|
std::set<Stream *> streams_;
|
|
std::set<const Stream *> activeStreams_;
|
|
|
|
private:
|
|
bool disconnected_;
|
|
std::atomic<State> state_;
|
|
};
|
|
|
|
Camera::Private::Private(Camera *camera, PipelineHandler *pipe,
|
|
const std::string &id,
|
|
const std::set<Stream *> &streams)
|
|
: Extensible::Private(camera), pipe_(pipe->shared_from_this()), id_(id),
|
|
streams_(streams), disconnected_(false), state_(CameraAvailable)
|
|
{
|
|
}
|
|
|
|
Camera::Private::~Private()
|
|
{
|
|
if (state_.load(std::memory_order_acquire) != Private::CameraAvailable)
|
|
LOG(Camera, Error) << "Removing camera while still in use";
|
|
}
|
|
|
|
static const char *const camera_state_names[] = {
|
|
"Available",
|
|
"Acquired",
|
|
"Configured",
|
|
"Stopping",
|
|
"Running",
|
|
};
|
|
|
|
int Camera::Private::isAccessAllowed(State state, bool allowDisconnected,
|
|
const char *from) const
|
|
{
|
|
if (!allowDisconnected && disconnected_)
|
|
return -ENODEV;
|
|
|
|
State currentState = state_.load(std::memory_order_acquire);
|
|
if (currentState == state)
|
|
return 0;
|
|
|
|
ASSERT(static_cast<unsigned int>(state) < std::size(camera_state_names));
|
|
|
|
LOG(Camera, Error) << "Camera in " << camera_state_names[currentState]
|
|
<< " state trying " << from << "() requiring state "
|
|
<< camera_state_names[state];
|
|
|
|
return -EACCES;
|
|
}
|
|
|
|
int Camera::Private::isAccessAllowed(State low, State high,
|
|
bool allowDisconnected,
|
|
const char *from) const
|
|
{
|
|
if (!allowDisconnected && disconnected_)
|
|
return -ENODEV;
|
|
|
|
State currentState = state_.load(std::memory_order_acquire);
|
|
if (currentState >= low && currentState <= high)
|
|
return 0;
|
|
|
|
ASSERT(static_cast<unsigned int>(low) < std::size(camera_state_names) &&
|
|
static_cast<unsigned int>(high) < std::size(camera_state_names));
|
|
|
|
LOG(Camera, Error) << "Camera in " << camera_state_names[currentState]
|
|
<< " state trying " << from
|
|
<< "() requiring state between "
|
|
<< camera_state_names[low] << " and "
|
|
<< camera_state_names[high];
|
|
|
|
return -EACCES;
|
|
}
|
|
|
|
void Camera::Private::disconnect()
|
|
{
|
|
/*
|
|
* If the camera was running when the hardware was removed force the
|
|
* state to Configured state to allow applications to free resources
|
|
* and call release() before deleting the camera.
|
|
*/
|
|
if (state_.load(std::memory_order_acquire) == Private::CameraRunning)
|
|
state_.store(Private::CameraConfigured, std::memory_order_release);
|
|
|
|
disconnected_ = true;
|
|
}
|
|
|
|
void Camera::Private::setState(State state)
|
|
{
|
|
state_.store(state, std::memory_order_release);
|
|
}
|
|
|
|
/**
|
|
* \class Camera
|
|
* \brief Camera device
|
|
*
|
|
* \todo Add documentation for camera start timings. What exactly does the
|
|
* camera expect the pipeline handler to do when start() is called?
|
|
*
|
|
* The Camera class models a camera capable of producing one or more image
|
|
* streams from a single image source. It provides the main interface to
|
|
* configuring and controlling the device, and capturing image streams. It is
|
|
* the central object exposed by libcamera.
|
|
*
|
|
* To support the central nature of Camera objects, libcamera manages the
|
|
* lifetime of camera instances with std::shared_ptr<>. Instances shall be
|
|
* created with the create() function which returns a shared pointer. The
|
|
* Camera constructors and destructor are private, to prevent instances from
|
|
* being constructed and destroyed manually.
|
|
*
|
|
* \section camera_operation Operating the Camera
|
|
*
|
|
* An application needs to perform a sequence of operations on a camera before
|
|
* it is ready to process requests. The camera needs to be acquired and
|
|
* configured to prepare the camera for capture. Once started the camera can
|
|
* process requests until it is stopped. When an application is done with a
|
|
* camera, the camera needs to be released.
|
|
*
|
|
* An application may start and stop a camera multiple times as long as it is
|
|
* not released. The camera may also be reconfigured.
|
|
*
|
|
* Functions that affect the camera state as defined below are generally not
|
|
* synchronized with each other by the Camera class. The caller is responsible
|
|
* for ensuring their synchronization if necessary.
|
|
*
|
|
* \subsection Camera States
|
|
*
|
|
* To help manage the sequence of operations needed to control the camera a set
|
|
* of states are defined. Each state describes which operations may be performed
|
|
* on the camera. Performing an operation not allowed in the camera state
|
|
* results in undefined behaviour. Operations not listed at all in the state
|
|
* diagram are allowed in all states.
|
|
*
|
|
* \dot
|
|
* digraph camera_state_machine {
|
|
* node [shape = doublecircle ]; Available;
|
|
* node [shape = circle ]; Acquired;
|
|
* node [shape = circle ]; Configured;
|
|
* node [shape = circle ]; Stopping;
|
|
* node [shape = circle ]; Running;
|
|
*
|
|
* Available -> Available [label = "release()"];
|
|
* Available -> Acquired [label = "acquire()"];
|
|
*
|
|
* Acquired -> Available [label = "release()"];
|
|
* Acquired -> Configured [label = "configure()"];
|
|
*
|
|
* Configured -> Available [label = "release()"];
|
|
* Configured -> Configured [label = "configure(), createRequest()"];
|
|
* Configured -> Running [label = "start()"];
|
|
*
|
|
* Running -> Stopping [label = "stop()"];
|
|
* Stopping -> Configured;
|
|
* Running -> Running [label = "createRequest(), queueRequest()"];
|
|
* }
|
|
* \enddot
|
|
*
|
|
* \subsubsection Available
|
|
* The base state of a camera, an application can inspect the properties of the
|
|
* camera to determine if it wishes to use it. If an application wishes to use
|
|
* a camera it should acquire() it to proceed to the Acquired state.
|
|
*
|
|
* \subsubsection Acquired
|
|
* In the acquired state an application has exclusive access to the camera and
|
|
* may modify the camera's parameters to configure it and proceed to the
|
|
* Configured state.
|
|
*
|
|
* \subsubsection Configured
|
|
* The camera is configured and ready to be started. The application may
|
|
* release() the camera and to get back to the Available state or start()
|
|
* it to progress to the Running state.
|
|
*
|
|
* \subsubsection Stopping
|
|
* The camera has been asked to stop. Pending requests are being completed or
|
|
* cancelled, and no new requests are permitted to be queued. The camera will
|
|
* transition to the Configured state when all queued requests have been
|
|
* returned to the application.
|
|
*
|
|
* \subsubsection Running
|
|
* The camera is running and ready to process requests queued by the
|
|
* application. The camera remains in this state until it is stopped and moved
|
|
* to the Configured state.
|
|
*/
|
|
|
|
/**
|
|
* \brief Create a camera instance
|
|
* \param[in] pipe The pipeline handler responsible for the camera device
|
|
* \param[in] id The ID of the camera device
|
|
* \param[in] streams Array of streams the camera provides
|
|
*
|
|
* The caller is responsible for guaranteeing a stable and unique camera ID
|
|
* matching the constraints described by Camera::id(). Parameters that are
|
|
* allocated dynamically at system startup, such as bus numbers that may be
|
|
* enumerated differently, are therefore not suitable to use in the ID.
|
|
*
|
|
* Pipeline handlers that use a CameraSensor may use the CameraSensor::id() to
|
|
* generate an ID that satisfies the criteria of a stable and unique camera ID.
|
|
*
|
|
* \return A shared pointer to the newly created camera object
|
|
*/
|
|
std::shared_ptr<Camera> Camera::create(PipelineHandler *pipe,
|
|
const std::string &id,
|
|
const std::set<Stream *> &streams)
|
|
{
|
|
struct Deleter : std::default_delete<Camera> {
|
|
void operator()(Camera *camera)
|
|
{
|
|
if (Thread::current() == camera->thread())
|
|
delete camera;
|
|
else
|
|
camera->deleteLater();
|
|
}
|
|
};
|
|
|
|
Camera *camera = new Camera(pipe, id, streams);
|
|
|
|
return std::shared_ptr<Camera>(camera, Deleter());
|
|
}
|
|
|
|
/**
|
|
* \brief Retrieve the ID of the camera
|
|
*
|
|
* The camera ID is a free-form string that identifies a camera in the system.
|
|
* IDs are guaranteed to be unique and stable: the same camera, when connected
|
|
* to the system in the same way (e.g. in the same USB port), will have the same
|
|
* ID across both unplug/replug and system reboots.
|
|
*
|
|
* Applications may store the camera ID and use it later to acquire the same
|
|
* camera. They shall treat the ID as an opaque identifier, without interpreting
|
|
* its value.
|
|
*
|
|
* Camera IDs may change when the system hardware or firmware is modified, for
|
|
* instance when replacing a PCI USB controller or moving it to another PCI
|
|
* slot, or updating the ACPI tables or Device Tree.
|
|
*
|
|
* \context This function is \threadsafe.
|
|
*
|
|
* \return ID of the camera device
|
|
*/
|
|
const std::string &Camera::id() const
|
|
{
|
|
const Private *const d = LIBCAMERA_D_PTR();
|
|
return d->id_;
|
|
}
|
|
|
|
/**
|
|
* \var Camera::bufferCompleted
|
|
* \brief Signal emitted when a buffer for a request queued to the camera has
|
|
* completed
|
|
*/
|
|
|
|
/**
|
|
* \var Camera::requestCompleted
|
|
* \brief Signal emitted when a request queued to the camera has completed
|
|
*/
|
|
|
|
/**
|
|
* \var Camera::disconnected
|
|
* \brief Signal emitted when the camera is disconnected from the system
|
|
*
|
|
* This signal is emitted when libcamera detects that the camera has been
|
|
* removed from the system. For hot-pluggable devices this is usually caused by
|
|
* physical device disconnection. The media device is passed as a parameter.
|
|
*
|
|
* As soon as this signal is emitted the camera instance will refuse all new
|
|
* application API calls by returning errors immediately.
|
|
*/
|
|
|
|
Camera::Camera(PipelineHandler *pipe, const std::string &id,
|
|
const std::set<Stream *> &streams)
|
|
: Extensible(new Private(this, pipe, id, streams))
|
|
{
|
|
}
|
|
|
|
Camera::~Camera()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* \brief Notify camera disconnection
|
|
*
|
|
* This method is used to notify the camera instance that the underlying
|
|
* hardware has been unplugged. In response to the disconnection the camera
|
|
* instance notifies the application by emitting the #disconnected signal, and
|
|
* ensures that all new calls to the application-facing Camera API return an
|
|
* error immediately.
|
|
*
|
|
* \todo Deal with pending requests if the camera is disconnected in a
|
|
* running state.
|
|
*/
|
|
void Camera::disconnect()
|
|
{
|
|
Private *const d = LIBCAMERA_D_PTR();
|
|
|
|
LOG(Camera, Debug) << "Disconnecting camera " << id();
|
|
|
|
d->disconnect();
|
|
disconnected.emit(this);
|
|
}
|
|
|
|
int Camera::exportFrameBuffers(Stream *stream,
|
|
std::vector<std::unique_ptr<FrameBuffer>> *buffers)
|
|
{
|
|
Private *const d = LIBCAMERA_D_PTR();
|
|
|
|
int ret = d->isAccessAllowed(Private::CameraConfigured);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
if (streams().find(stream) == streams().end())
|
|
return -EINVAL;
|
|
|
|
if (d->activeStreams_.find(stream) == d->activeStreams_.end())
|
|
return -EINVAL;
|
|
|
|
return d->pipe_->invokeMethod(&PipelineHandler::exportFrameBuffers,
|
|
ConnectionTypeBlocking, this, stream,
|
|
buffers);
|
|
}
|
|
|
|
/**
|
|
* \brief Acquire the camera device for exclusive access
|
|
*
|
|
* After opening the device with open(), exclusive access must be obtained
|
|
* before performing operations that change the device state. This function is
|
|
* not blocking, if the device has already been acquired (by the same or another
|
|
* process) the -EBUSY error code is returned.
|
|
*
|
|
* Acquiring a camera will limit usage of any other camera(s) provided by the
|
|
* same pipeline handler to the same instance of libcamera. The limit is in
|
|
* effect until all cameras from the pipeline handler are released. Other
|
|
* instances of libcamera can still list and examine the cameras but will fail
|
|
* if they attempt to acquire() any of them.
|
|
*
|
|
* Once exclusive access isn't needed anymore, the device should be released
|
|
* with a call to the release() function.
|
|
*
|
|
* \context This function is \threadsafe. It may only be called when the camera
|
|
* is in the Available state as defined in \ref camera_operation.
|
|
*
|
|
* \return 0 on success or a negative error code otherwise
|
|
* \retval -ENODEV The camera has been disconnected from the system
|
|
* \retval -EBUSY The camera is not free and can't be acquired by the caller
|
|
*/
|
|
int Camera::acquire()
|
|
{
|
|
Private *const d = LIBCAMERA_D_PTR();
|
|
|
|
/*
|
|
* No manual locking is required as PipelineHandler::lock() is
|
|
* thread-safe.
|
|
*/
|
|
int ret = d->isAccessAllowed(Private::CameraAvailable);
|
|
if (ret < 0)
|
|
return ret == -EACCES ? -EBUSY : ret;
|
|
|
|
if (!d->pipe_->lock()) {
|
|
LOG(Camera, Info)
|
|
<< "Pipeline handler in use by another process";
|
|
return -EBUSY;
|
|
}
|
|
|
|
d->setState(Private::CameraAcquired);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* \brief Release exclusive access to the camera device
|
|
*
|
|
* Releasing the camera device allows other users to acquire exclusive access
|
|
* with the acquire() function.
|
|
*
|
|
* \context This function may only be called when the camera is in the
|
|
* Available or Configured state as defined in \ref camera_operation, and shall
|
|
* be synchronized by the caller with other functions that affect the camera
|
|
* state.
|
|
*
|
|
* \return 0 on success or a negative error code otherwise
|
|
* \retval -EBUSY The camera is running and can't be released
|
|
*/
|
|
int Camera::release()
|
|
{
|
|
Private *const d = LIBCAMERA_D_PTR();
|
|
|
|
int ret = d->isAccessAllowed(Private::CameraAvailable,
|
|
Private::CameraConfigured, true);
|
|
if (ret < 0)
|
|
return ret == -EACCES ? -EBUSY : ret;
|
|
|
|
d->pipe_->unlock();
|
|
|
|
d->setState(Private::CameraAvailable);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* \brief Retrieve the list of controls supported by the camera
|
|
*
|
|
* The list of controls supported by the camera and their associated
|
|
* constraints remain constant through the lifetime of the Camera object.
|
|
*
|
|
* \context This function is \threadsafe.
|
|
*
|
|
* \return A ControlInfoMap listing the controls supported by the camera
|
|
*/
|
|
const ControlInfoMap &Camera::controls() const
|
|
{
|
|
const Private *const d = LIBCAMERA_D_PTR();
|
|
return d->pipe_->controls(this);
|
|
}
|
|
|
|
/**
|
|
* \brief Retrieve the list of properties of the camera
|
|
*
|
|
* Camera properties are static information that describe the capabilities of
|
|
* the camera. They remain constant through the lifetime of the Camera object.
|
|
*
|
|
* \return A ControlList of properties supported by the camera
|
|
*/
|
|
const ControlList &Camera::properties() const
|
|
{
|
|
const Private *const d = LIBCAMERA_D_PTR();
|
|
return d->pipe_->properties(this);
|
|
}
|
|
|
|
/**
|
|
* \brief Retrieve all the camera's stream information
|
|
*
|
|
* Retrieve all of the camera's static stream information. The static
|
|
* information describes among other things how many streams the camera
|
|
* supports and the capabilities of each stream.
|
|
*
|
|
* \context This function is \threadsafe.
|
|
*
|
|
* \return An array of all the camera's streams
|
|
*/
|
|
const std::set<Stream *> &Camera::streams() const
|
|
{
|
|
const Private *const d = LIBCAMERA_D_PTR();
|
|
return d->streams_;
|
|
}
|
|
|
|
/**
|
|
* \brief Generate a default camera configuration according to stream roles
|
|
* \param[in] roles A list of stream roles
|
|
*
|
|
* Generate a camera configuration for a set of desired stream roles. The caller
|
|
* specifies a list of stream roles and the camera returns a configuration
|
|
* containing suitable streams and their suggested default configurations. An
|
|
* empty list of roles is valid, and will generate an empty configuration that
|
|
* can be filled by the caller.
|
|
*
|
|
* \context This function is \threadsafe.
|
|
*
|
|
* \return A CameraConfiguration if the requested roles can be satisfied, or a
|
|
* null pointer otherwise. The ownership of the returned configuration is
|
|
* passed to the caller.
|
|
*/
|
|
std::unique_ptr<CameraConfiguration> Camera::generateConfiguration(const StreamRoles &roles)
|
|
{
|
|
Private *const d = LIBCAMERA_D_PTR();
|
|
|
|
int ret = d->isAccessAllowed(Private::CameraAvailable,
|
|
Private::CameraRunning);
|
|
if (ret < 0)
|
|
return nullptr;
|
|
|
|
if (roles.size() > streams().size())
|
|
return nullptr;
|
|
|
|
CameraConfiguration *config = d->pipe_->generateConfiguration(this, roles);
|
|
if (!config) {
|
|
LOG(Camera, Debug)
|
|
<< "Pipeline handler failed to generate configuration";
|
|
return nullptr;
|
|
}
|
|
|
|
std::ostringstream msg("streams configuration:", std::ios_base::ate);
|
|
|
|
if (config->empty())
|
|
msg << " empty";
|
|
|
|
for (unsigned int index = 0; index < config->size(); ++index)
|
|
msg << " (" << index << ") " << config->at(index).toString();
|
|
|
|
LOG(Camera, Debug) << msg.str();
|
|
|
|
return std::unique_ptr<CameraConfiguration>(config);
|
|
}
|
|
|
|
/**
|
|
* \brief Configure the camera prior to capture
|
|
* \param[in] config The camera configurations to setup
|
|
*
|
|
* Prior to starting capture, the camera must be configured to select a
|
|
* group of streams to be involved in the capture and their configuration.
|
|
* The caller specifies which streams are to be involved and their configuration
|
|
* by populating \a config.
|
|
*
|
|
* The configuration is created by generateConfiguration(), and adjusted by the
|
|
* caller with CameraConfiguration::validate(). This method only accepts fully
|
|
* valid configurations and returns an error if \a config is not valid.
|
|
*
|
|
* Exclusive access to the camera shall be ensured by a call to acquire() prior
|
|
* to calling this function, otherwise an -EACCES error will be returned.
|
|
*
|
|
* \context This function may only be called when the camera is in the Acquired
|
|
* or Configured state as defined in \ref camera_operation, and shall be
|
|
* synchronized by the caller with other functions that affect the camera
|
|
* state.
|
|
*
|
|
* Upon return the StreamConfiguration entries in \a config are associated with
|
|
* Stream instances which can be retrieved with StreamConfiguration::stream().
|
|
*
|
|
* \return 0 on success or a negative error code otherwise
|
|
* \retval -ENODEV The camera has been disconnected from the system
|
|
* \retval -EACCES The camera is not in a state where it can be configured
|
|
* \retval -EINVAL The configuration is not valid
|
|
*/
|
|
int Camera::configure(CameraConfiguration *config)
|
|
{
|
|
Private *const d = LIBCAMERA_D_PTR();
|
|
|
|
int ret = d->isAccessAllowed(Private::CameraAcquired,
|
|
Private::CameraConfigured);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
for (auto it : *config)
|
|
it.setStream(nullptr);
|
|
|
|
if (config->validate() != CameraConfiguration::Valid) {
|
|
LOG(Camera, Error)
|
|
<< "Can't configure camera with invalid configuration";
|
|
return -EINVAL;
|
|
}
|
|
|
|
std::ostringstream msg("configuring streams:", std::ios_base::ate);
|
|
|
|
for (unsigned int index = 0; index < config->size(); ++index) {
|
|
StreamConfiguration &cfg = config->at(index);
|
|
msg << " (" << index << ") " << cfg.toString();
|
|
}
|
|
|
|
LOG(Camera, Info) << msg.str();
|
|
|
|
ret = d->pipe_->invokeMethod(&PipelineHandler::configure,
|
|
ConnectionTypeBlocking, this, config);
|
|
if (ret)
|
|
return ret;
|
|
|
|
d->activeStreams_.clear();
|
|
for (const StreamConfiguration &cfg : *config) {
|
|
Stream *stream = cfg.stream();
|
|
if (!stream) {
|
|
LOG(Camera, Fatal)
|
|
<< "Pipeline handler failed to update stream configuration";
|
|
d->activeStreams_.clear();
|
|
return -EINVAL;
|
|
}
|
|
|
|
stream->configuration_ = cfg;
|
|
d->activeStreams_.insert(stream);
|
|
}
|
|
|
|
d->setState(Private::CameraConfigured);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* \brief Create a request object for the camera
|
|
* \param[in] cookie Opaque cookie for application use
|
|
*
|
|
* This method creates an empty request for the application to fill with
|
|
* buffers and parameters, and queue for capture.
|
|
*
|
|
* The \a cookie is stored in the request and is accessible through the
|
|
* Request::cookie() method at any time. It is typically used by applications
|
|
* to map the request to an external resource in the request completion
|
|
* handler, and is completely opaque to libcamera.
|
|
*
|
|
* The ownership of the returned request is passed to the caller, which is
|
|
* responsible for deleting it. The request may be deleted in the completion
|
|
* handler, or reused after resetting its state with Request::reuse().
|
|
*
|
|
* \context This function is \threadsafe. It may only be called when the camera
|
|
* is in the Configured or Running state as defined in \ref camera_operation.
|
|
*
|
|
* \return A pointer to the newly created request, or nullptr on error
|
|
*/
|
|
std::unique_ptr<Request> Camera::createRequest(uint64_t cookie)
|
|
{
|
|
Private *const d = LIBCAMERA_D_PTR();
|
|
|
|
int ret = d->isAccessAllowed(Private::CameraConfigured,
|
|
Private::CameraRunning);
|
|
if (ret < 0)
|
|
return nullptr;
|
|
|
|
return std::make_unique<Request>(this, cookie);
|
|
}
|
|
|
|
/**
|
|
* \brief Queue a request to the camera
|
|
* \param[in] request The request to queue to the camera
|
|
*
|
|
* This method queues a \a request to the camera for capture.
|
|
*
|
|
* After allocating the request with createRequest(), the application shall
|
|
* fill it with at least one capture buffer before queuing it. Requests that
|
|
* contain no buffers are invalid and are rejected without being queued.
|
|
*
|
|
* Once the request has been queued, the camera will notify its completion
|
|
* through the \ref requestCompleted signal.
|
|
*
|
|
* \context This function is \threadsafe. It may only be called when the camera
|
|
* is in the Running state as defined in \ref camera_operation.
|
|
*
|
|
* \return 0 on success or a negative error code otherwise
|
|
* \retval -ENODEV The camera has been disconnected from the system
|
|
* \retval -EACCES The camera is not running so requests can't be queued
|
|
* \retval -EINVAL The request is invalid
|
|
* \retval -ENOMEM No buffer memory was available to handle the request
|
|
*/
|
|
int Camera::queueRequest(Request *request)
|
|
{
|
|
Private *const d = LIBCAMERA_D_PTR();
|
|
|
|
int ret = d->isAccessAllowed(Private::CameraRunning);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
/*
|
|
* The camera state may change until the end of the function. No locking
|
|
* is however needed as PipelineHandler::queueRequest() will handle
|
|
* this.
|
|
*/
|
|
|
|
if (request->buffers().empty()) {
|
|
LOG(Camera, Error) << "Request contains no buffers";
|
|
return -EINVAL;
|
|
}
|
|
|
|
for (auto const &it : request->buffers()) {
|
|
const Stream *stream = it.first;
|
|
|
|
if (d->activeStreams_.find(stream) == d->activeStreams_.end()) {
|
|
LOG(Camera, Error) << "Invalid request";
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
d->pipe_->invokeMethod(&PipelineHandler::queueRequest,
|
|
ConnectionTypeQueued, request);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* \brief Start capture from camera
|
|
* \param[in] controls Controls to be applied before starting the Camera
|
|
*
|
|
* Start the camera capture session, optionally providing a list of controls to
|
|
* apply before starting. Once the camera is started the application can queue
|
|
* requests to the camera to process and return to the application until the
|
|
* capture session is terminated with \a stop().
|
|
*
|
|
* \context This function may only be called when the camera is in the
|
|
* Configured state as defined in \ref camera_operation, and shall be
|
|
* synchronized by the caller with other functions that affect the camera
|
|
* state.
|
|
*
|
|
* \return 0 on success or a negative error code otherwise
|
|
* \retval -ENODEV The camera has been disconnected from the system
|
|
* \retval -EACCES The camera is not in a state where it can be started
|
|
*/
|
|
int Camera::start(const ControlList *controls)
|
|
{
|
|
Private *const d = LIBCAMERA_D_PTR();
|
|
|
|
int ret = d->isAccessAllowed(Private::CameraConfigured);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
LOG(Camera, Debug) << "Starting capture";
|
|
|
|
ret = d->pipe_->invokeMethod(&PipelineHandler::start,
|
|
ConnectionTypeBlocking, this, controls);
|
|
if (ret)
|
|
return ret;
|
|
|
|
d->setState(Private::CameraRunning);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* \brief Stop capture from camera
|
|
*
|
|
* This method stops capturing and processing requests immediately. All pending
|
|
* requests are cancelled and complete synchronously in an error state.
|
|
*
|
|
* \context This function may only be called when the camera is in the Running
|
|
* state as defined in \ref camera_operation, and shall be synchronized by the
|
|
* caller with other functions that affect the camera state.
|
|
*
|
|
* \return 0 on success or a negative error code otherwise
|
|
* \retval -ENODEV The camera has been disconnected from the system
|
|
* \retval -EACCES The camera is not running so can't be stopped
|
|
*/
|
|
int Camera::stop()
|
|
{
|
|
Private *const d = LIBCAMERA_D_PTR();
|
|
|
|
int ret = d->isAccessAllowed(Private::CameraRunning);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
LOG(Camera, Debug) << "Stopping capture";
|
|
|
|
d->setState(Private::CameraStopping);
|
|
|
|
d->pipe_->invokeMethod(&PipelineHandler::stop, ConnectionTypeBlocking,
|
|
this);
|
|
|
|
d->setState(Private::CameraConfigured);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* \brief Handle request completion and notify application
|
|
* \param[in] request The request that has completed
|
|
*
|
|
* This function is called by the pipeline handler to notify the camera that
|
|
* the request has completed. It emits the requestCompleted signal.
|
|
*/
|
|
void Camera::requestComplete(Request *request)
|
|
{
|
|
Private *const d = LIBCAMERA_D_PTR();
|
|
|
|
/* Disconnected cameras are still able to complete requests. */
|
|
if (d->isAccessAllowed(Private::CameraStopping, Private::CameraRunning,
|
|
true))
|
|
LOG(Camera, Fatal) << "Trying to complete a request when stopped";
|
|
|
|
requestCompleted.emit(request);
|
|
}
|
|
|
|
} /* namespace libcamera */
|