[libcamera-devel] [PATCH/RFC 04/12] libcamera: Refactor the camera configuration storage and API
Niklas Söderlund
niklas.soderlund at ragnatech.se
Sat May 18 18:05:01 CEST 2019
Hi Laurent,
Thanks for your patch.
On 2019-05-18 02:06:13 +0300, Laurent Pinchart wrote:
> Refactor the CameraConfiguration structure to not rely on Stream
> instances. This is a step towards making the camera configuration object
> more powerful with configuration validation using "try" semantics.
>
> As applications need access to the Stream instances associated with the
> configuration entries in order to associate buffers with streams when
> creating requests, expose the stream selected by the pipeline handler
> through a new StreamConfiguration::stream().
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>
> ---
> include/libcamera/camera.h | 19 ++-
> include/libcamera/stream.h | 7 +
> src/cam/main.cpp | 35 ++---
> src/libcamera/camera.cpp | 174 +++++++++--------------
> src/libcamera/include/pipeline_handler.h | 2 +-
> src/libcamera/pipeline/ipu3/ipu3.cpp | 32 ++---
> src/libcamera/pipeline/rkisp1/rkisp1.cpp | 12 +-
> src/libcamera/pipeline/uvcvideo.cpp | 23 ++-
> src/libcamera/pipeline/vimc.cpp | 23 ++-
> src/libcamera/pipeline_handler.cpp | 4 +
> src/libcamera/stream.cpp | 22 +++
> src/qcam/main_window.cpp | 4 +-
> test/camera/capture.cpp | 4 +-
> test/camera/configuration_set.cpp | 2 +-
> 14 files changed, 179 insertions(+), 184 deletions(-)
>
> diff --git a/include/libcamera/camera.h b/include/libcamera/camera.h
> index 42ba5201eabc..e2759405f497 100644
> --- a/include/libcamera/camera.h
> +++ b/include/libcamera/camera.h
> @@ -25,11 +25,13 @@ class Request;
> class CameraConfiguration
> {
> public:
> - using iterator = std::vector<Stream *>::iterator;
> - using const_iterator = std::vector<Stream *>::const_iterator;
> + using iterator = std::vector<StreamConfiguration>::iterator;
> + using const_iterator = std::vector<StreamConfiguration>::const_iterator;
>
> CameraConfiguration();
>
> + void addConfiguration(const StreamConfiguration &cfg);
> +
> iterator begin();
> iterator end();
> const_iterator begin() const;
> @@ -39,16 +41,11 @@ public:
> bool isEmpty() const;
> std::size_t size() const;
>
> - Stream *front();
> - const Stream *front() const;
> -
> - Stream *operator[](unsigned int index) const;
> - StreamConfiguration &operator[](Stream *stream);
> - const StreamConfiguration &operator[](Stream *stream) const;
> + StreamConfiguration &operator[](unsigned int index);
> + const StreamConfiguration &operator[](unsigned int index) const;
>
> private:
> - std::vector<Stream *> order_;
> - std::map<Stream *, StreamConfiguration> config_;
> + std::vector<StreamConfiguration> config_;
> };
>
> class Camera final
> @@ -72,7 +69,7 @@ public:
>
> const std::set<Stream *> &streams() const;
> CameraConfiguration generateConfiguration(const StreamRoles &roles);
> - int configure(const CameraConfiguration &config);
> + int configure(CameraConfiguration &config);
>
> int allocateBuffers();
> int freeBuffers();
> diff --git a/include/libcamera/stream.h b/include/libcamera/stream.h
> index 59bdf217eb31..47c007ed52e2 100644
> --- a/include/libcamera/stream.h
> +++ b/include/libcamera/stream.h
> @@ -16,6 +16,7 @@
> namespace libcamera {
>
> class Camera;
> +class Stream;
>
> struct StreamConfiguration {
> unsigned int pixelFormat;
> @@ -23,7 +24,13 @@ struct StreamConfiguration {
>
> unsigned int bufferCount;
>
> + Stream *stream() const { return stream_; }
> + void setStream(Stream *stream) { stream_ = stream; }
> +
> std::string toString() const;
> +
> +private:
> + Stream *stream_;
> };
>
> enum StreamRole {
> diff --git a/src/cam/main.cpp b/src/cam/main.cpp
> index d603228c0116..cd165bea34cd 100644
> --- a/src/cam/main.cpp
> +++ b/src/cam/main.cpp
> @@ -89,12 +89,9 @@ static int prepareCameraConfig(CameraConfiguration *config)
> {
> StreamRoles roles;
>
> - streamInfo.clear();
> -
> /* If no configuration is provided assume a single video stream. */
> if (!options.isSet(OptStream)) {
> *config = camera->generateConfiguration({ StreamRole::VideoRecording });
> - streamInfo[config->front()] = "stream0";
> return 0;
> }
>
> @@ -129,27 +126,20 @@ static int prepareCameraConfig(CameraConfiguration *config)
> }
>
> /* Apply configuration explicitly requested. */
> - CameraConfiguration::iterator it = config->begin();
> + unsigned int i = 0;
> for (auto const &value : streamOptions) {
> KeyValueParser::Options conf = value.toKeyValues();
> - Stream *stream = *it;
> - it++;
> + StreamConfiguration &cfg = (*config)[i++];
>
> if (conf.isSet("width"))
> - (*config)[stream].size.width = conf["width"];
> + cfg.size.width = conf["width"];
>
> if (conf.isSet("height"))
> - (*config)[stream].size.height = conf["height"];
> + cfg.size.height = conf["height"];
>
> /* TODO: Translate 4CC string to ID. */
> if (conf.isSet("pixelformat"))
> - (*config)[stream].pixelFormat = conf["pixelformat"];
> - }
> -
> - unsigned int index = 0;
> - for (Stream *stream : *config) {
> - streamInfo[stream] = "stream" + std::to_string(index);
> - index++;
> + cfg.pixelFormat = conf["pixelformat"];
> }
>
> return 0;
> @@ -216,6 +206,13 @@ static int capture()
> return ret;
> }
>
> + streamInfo.clear();
> +
> + for (unsigned int index = 0; index < config.size(); ++index) {
> + StreamConfiguration &cfg = config[index];
> + streamInfo[cfg.stream()] = "stream" + std::to_string(index);
> + }
> +
> ret = camera->allocateBuffers();
> if (ret) {
> std::cerr << "Failed to allocate buffers"
> @@ -227,8 +224,10 @@ static int capture()
>
> /* Identify the stream with the least number of buffers. */
> unsigned int nbuffers = UINT_MAX;
> - for (Stream *stream : config)
> + for (StreamConfiguration &cfg : config) {
> + Stream *stream = cfg.stream();
> nbuffers = std::min(nbuffers, stream->bufferPool().count());
> + }
>
> /*
> * TODO: make cam tool smarter to support still capture by for
> @@ -245,8 +244,10 @@ static int capture()
> }
>
> std::map<Stream *, Buffer *> map;
> - for (Stream *stream : config)
> + for (StreamConfiguration &cfg : config) {
> + Stream *stream = cfg.stream();
> map[stream] = &stream->bufferPool().buffers()[i];
> + }
>
> ret = request->setBuffers(map);
> if (ret < 0) {
> diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp
> index a3921f91f1c9..f8a4946b4a6a 100644
> --- a/src/libcamera/camera.cpp
> +++ b/src/libcamera/camera.cpp
> @@ -46,72 +46,81 @@ LOG_DECLARE_CATEGORY(Camera)
> * \class CameraConfiguration
> * \brief Hold configuration for streams of the camera
>
> - * The CameraConfiguration holds an ordered list of streams and their associated
> - * StreamConfiguration. From a data storage point of view, the class operates as
> - * a map of Stream pointers to StreamConfiguration, with entries accessed with
> - * operator[](Stream *). Accessing an entry for a Stream pointer not yet stored
> - * in the configuration inserts a new empty entry.
> - *
> - * The class also suppors iterators, and from that point of view operates as a
> - * vector of Stream pointers. The streams are iterated in insertion order, and
> - * the operator[](int) returns the Stream pointer based on its insertion index.
> - * Accessing a stream with an invalid index returns a null pointer.
> + * 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.
> */
>
> /**
> * \typedef CameraConfiguration::iterator
> - * \brief Iterator for the streams in the configuration
> + * \brief Iterator for the stream configurations in the camera configuration
> */
>
> /**
> * \typedef CameraConfiguration::const_iterator
> - * \brief Const iterator for the streams in the configuration
> + * \brief Const iterator for the stream configuration in the camera
> + * configuration
> */
>
> /**
> * \brief Create an empty camera configuration
> */
> CameraConfiguration::CameraConfiguration()
> - : order_({}), config_({})
> + : config_({})
> {
> }
>
> /**
> - * \brief Retrieve an iterator to the first stream in the sequence
> - * \return An iterator to the first stream
> + * \brief Add a stream configuration to the camera configuration
> + * \param[in] cfg The stream configuration
> */
> -std::vector<Stream *>::iterator CameraConfiguration::begin()
> +void CameraConfiguration::addConfiguration(const StreamConfiguration &cfg)
> {
> - return order_.begin();
> + config_.push_back(cfg);
> }
>
> /**
> - * \brief Retrieve an iterator pointing to the past-the-end stream in the
> + * \brief Retrieve an iterator to the first stream configuration in the
> * sequence
> - * \return An iterator to the element following the last stream
> + * \return An iterator to the first stream configuration
> */
> -std::vector<Stream *>::iterator CameraConfiguration::end()
> +CameraConfiguration::iterator CameraConfiguration::begin()
> {
> - return order_.end();
> + return config_.begin();
> }
>
> /**
> - * \brief Retrieve a const iterator to the first element of the streams
> - * \return A const iterator to the first stream
> + * \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
> */
> -std::vector<Stream *>::const_iterator CameraConfiguration::begin() const
> +CameraConfiguration::iterator CameraConfiguration::end()
> {
> - return order_.begin();
> + return config_.end();
> }
>
> /**
> - * \brief Retrieve a const iterator pointing to the past-the-end stream in the
> - * sequence
> + * \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 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
> */
> -std::vector<Stream *>::const_iterator CameraConfiguration::end() const
> +CameraConfiguration::const_iterator CameraConfiguration::end() const
> {
> - return order_.end();
> + return config_.end();
> }
>
> /**
> @@ -128,9 +137,7 @@ bool CameraConfiguration::isValid() const
> if (isEmpty())
> return false;
>
> - for (auto const &it : config_) {
> - const StreamConfiguration &cfg = it.second;
> -
> + for (const StreamConfiguration &cfg : config_) {
> if (cfg.size.width == 0 || cfg.size.height == 0 ||
> cfg.pixelFormat == 0 || cfg.bufferCount == 0)
> return false;
> @@ -145,7 +152,7 @@ bool CameraConfiguration::isValid() const
> */
> bool CameraConfiguration::isEmpty() const
> {
> - return order_.empty();
> + return config_.empty();
> }
>
> /**
> @@ -154,75 +161,37 @@ bool CameraConfiguration::isEmpty() const
> */
> std::size_t CameraConfiguration::size() const
> {
> - return order_.size();
> -}
> -
> -/**
> - * \brief Access the first stream in the configuration
> - * \return The first stream in the configuration
> - */
> -Stream *CameraConfiguration::front()
> -{
> - return order_.front();
> -}
> -
> -/**
> - * \brief Access the first stream in the configuration
> - * \return The first const stream pointer in the configuration
> - */
> -const Stream *CameraConfiguration::front() const
> -{
> - return order_.front();
> -}
> -
> -/**
> - * \brief Retrieve a stream pointer from index
> - * \param[in] index Numerical index
> - *
> - * The \a index represents the zero based insertion order of stream and stream
> - * configuration into the camera configuration.
> - *
> - * \return The stream pointer at index, or a nullptr if the index is out of
> - * bounds
> - */
> -Stream *CameraConfiguration::operator[](unsigned int index) const
> -{
> - if (index >= order_.size())
> - return nullptr;
> -
> - return order_.at(index);
> + return config_.size();
> }
>
> /**
> * \brief Retrieve a reference to a stream configuration
> - * \param[in] stream Stream to retrieve configuration for
> + * \param[in] index Numerical index
> *
> - * If the camera configuration does not yet contain a configuration for
> - * the requested stream, create and return an empty stream configuration.
> + * 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 configuration for the stream
> + * \return The stream configuration
> */
> -StreamConfiguration &CameraConfiguration::operator[](Stream *stream)
> +StreamConfiguration &CameraConfiguration::operator[](unsigned int index)
> {
> - if (config_.find(stream) == config_.end())
> - order_.push_back(stream);
> -
> - return config_[stream];
> + return config_[index];
> }
>
> /**
> * \brief Retrieve a const reference to a stream configuration
> - * \param[in] stream Stream to retrieve configuration for
> + * \param[in] index Numerical index
> *
> - * No new stream configuration is created if called with \a stream that is not
> - * already part of the camera configuration, doing so is an invalid operation
> - * and results in undefined behaviour.
> + * 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 configuration for the stream
> + * \return The stream configuration
> */
> -const StreamConfiguration &CameraConfiguration::operator[](Stream *stream) const
> +const StreamConfiguration &CameraConfiguration::operator[](unsigned int index) const
> {
> - return config_.at(stream);
> + return config_[index];
> }
>
> /**
> @@ -561,13 +530,9 @@ Camera::generateConfiguration(const StreamRoles &roles)
> CameraConfiguration config = pipe_->generateConfiguration(this, roles);
>
> std::ostringstream msg("streams configuration:", std::ios_base::ate);
> - unsigned int index = 0;
>
> - for (Stream *stream : config) {
> - const StreamConfiguration &cfg = config[stream];
> - msg << " (" << index << ") " << cfg.toString();
> - index++;
> - }
> + for (unsigned int index = 0; index < config.size(); ++index)
> + msg << " (" << index << ") " << config[index].toString();
>
> LOG(Camera, Debug) << msg.str();
>
> @@ -593,12 +558,15 @@ Camera::generateConfiguration(const StreamRoles &roles)
> *
> * This function affects the state of the camera, see \ref camera_operation.
> *
> + * 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(const CameraConfiguration &config)
> +int Camera::configure(CameraConfiguration &config)
> {
> int ret;
>
> @@ -615,16 +583,11 @@ int Camera::configure(const CameraConfiguration &config)
> }
>
> std::ostringstream msg("configuring streams:", std::ios_base::ate);
> - unsigned int index = 0;
>
> - for (Stream *stream : config) {
> - if (streams_.find(stream) == streams_.end())
> - return -EINVAL;
> -
> - const StreamConfiguration &cfg = config[stream];
> - msg << std::dec << " (" << index << ") " << cfg.toString();
> -
> - index++;
> + for (unsigned int index = 0; index < config.size(); ++index) {
> + StreamConfiguration &cfg = config[index];
> + cfg.setStream(nullptr);
> + msg << " (" << index << ") " << cfg.toString();
> }
>
> LOG(Camera, Info) << msg.str();
> @@ -634,8 +597,11 @@ int Camera::configure(const CameraConfiguration &config)
> return ret;
>
> activeStreams_.clear();
> - for (Stream *stream : config) {
> - const StreamConfiguration &cfg = config[stream];
> + for (const StreamConfiguration &cfg : config) {
> + Stream *stream = cfg.stream();
> + if (!stream)
> + LOG(Camera, Fatal)
> + << "Pipeline handler failed to update stream configuration";
>
> stream->configuration_ = cfg;
> activeStreams_.insert(stream);
> diff --git a/src/libcamera/include/pipeline_handler.h b/src/libcamera/include/pipeline_handler.h
> index 3352cb0e5bc9..a025905ab68f 100644
> --- a/src/libcamera/include/pipeline_handler.h
> +++ b/src/libcamera/include/pipeline_handler.h
> @@ -62,7 +62,7 @@ public:
>
> virtual CameraConfiguration
> generateConfiguration(Camera *camera, const StreamRoles &roles) = 0;
> - virtual int configure(Camera *camera, const CameraConfiguration &config) = 0;
> + virtual int configure(Camera *camera, CameraConfiguration &config) = 0;
>
> virtual int allocateBuffers(Camera *camera,
> const std::set<Stream *> &streams) = 0;
> diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
> index d234a8ac5289..ed0ef69de1d1 100644
> --- a/src/libcamera/pipeline/ipu3/ipu3.cpp
> +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
> @@ -152,8 +152,7 @@ public:
>
> CameraConfiguration
> generateConfiguration(Camera *camera, const StreamRoles &roles) override;
> - int configure(Camera *camera,
> - const CameraConfiguration &config) override;
> + int configure(Camera *camera, CameraConfiguration &config) override;
>
> int allocateBuffers(Camera *camera,
> const std::set<Stream *> &streams) override;
> @@ -299,14 +298,13 @@ PipelineHandlerIPU3::generateConfiguration(Camera *camera,
> cfg.pixelFormat = V4L2_PIX_FMT_NV12;
> cfg.bufferCount = IPU3_BUFFER_COUNT;
>
> - config[stream] = cfg;
> + config.addConfiguration(cfg);
> }
>
> return config;
> }
>
> -int PipelineHandlerIPU3::configure(Camera *camera,
> - const CameraConfiguration &config)
> +int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration &config)
> {
> IPU3CameraData *data = cameraData(camera);
> IPU3Stream *outStream = &data->outStream_;
> @@ -318,9 +316,13 @@ int PipelineHandlerIPU3::configure(Camera *camera,
>
> outStream->active_ = false;
> vfStream->active_ = false;
> - for (Stream *s : config) {
> - IPU3Stream *stream = static_cast<IPU3Stream *>(s);
> - const StreamConfiguration &cfg = config[stream];
> + for (StreamConfiguration &cfg : config) {
> + /*
> + * Pick a stream for the configuration entry.
> + * \todo: This is a naive temporary implementation that will be
> + * reworked when implementing camera configuration validation.
> + */
> + IPU3Stream *stream = vfStream->active_ ? outStream : vfStream;
>
> /*
> * Verify that the requested size respects the IPU3 alignment
> @@ -355,6 +357,7 @@ int PipelineHandlerIPU3::configure(Camera *camera,
> sensorSize.height = cfg.size.height;
>
> stream->active_ = true;
> + cfg.setStream(stream);
> }
>
> /*
> @@ -379,10 +382,9 @@ int PipelineHandlerIPU3::configure(Camera *camera,
> return ret;
>
> /* Apply the format to the configured streams output devices. */
> - for (Stream *s : config) {
> - IPU3Stream *stream = static_cast<IPU3Stream *>(s);
> -
> - ret = imgu->configureOutput(stream->device_, config[stream]);
> + for (StreamConfiguration &cfg : config) {
> + IPU3Stream *stream = static_cast<IPU3Stream *>(cfg.stream());
> + ret = imgu->configureOutput(stream->device_, cfg);
> if (ret)
> return ret;
> }
> @@ -393,15 +395,13 @@ int PipelineHandlerIPU3::configure(Camera *camera,
> * be at least one active stream in the configuration request).
> */
> if (!outStream->active_) {
> - ret = imgu->configureOutput(outStream->device_,
> - config[vfStream]);
> + ret = imgu->configureOutput(outStream->device_, config[0]);
> if (ret)
> return ret;
> }
>
> if (!vfStream->active_) {
> - ret = imgu->configureOutput(vfStream->device_,
> - config[outStream]);
> + ret = imgu->configureOutput(vfStream->device_, config[0]);
> if (ret)
> return ret;
> }
> diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> index 05dd517846d6..6b35aa3fe7c3 100644
> --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> @@ -36,8 +36,7 @@ public:
>
> CameraConfiguration generateConfiguration(Camera *camera,
> const StreamRoles &roles) override;
> - int configure(Camera *camera,
> - const CameraConfiguration &config) override;
> + int configure(Camera *camera, CameraConfiguration &config) override;
>
> int allocateBuffers(Camera *camera,
> const std::set<Stream *> &streams) override;
> @@ -117,16 +116,15 @@ CameraConfiguration PipelineHandlerRkISP1::generateConfiguration(Camera *camera,
> cfg.size = data->sensor_->resolution();
> cfg.bufferCount = RKISP1_BUFFER_COUNT;
>
> - config[&data->stream_] = cfg;
> + config.addConfiguration(cfg);
>
> return config;
> }
>
> -int PipelineHandlerRkISP1::configure(Camera *camera,
> - const CameraConfiguration &config)
> +int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration &config)
> {
> RkISP1CameraData *data = cameraData(camera);
> - const StreamConfiguration &cfg = config[&data->stream_];
> + StreamConfiguration &cfg = config[0];
> CameraSensor *sensor = data->sensor_;
> int ret;
>
> @@ -220,6 +218,8 @@ int PipelineHandlerRkISP1::configure(Camera *camera,
> return -EINVAL;
> }
>
> + cfg.setStream(&data->stream_);
> +
> return 0;
> }
>
> diff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp
> index d2e1f7d4e5b2..5dcc868b2fc9 100644
> --- a/src/libcamera/pipeline/uvcvideo.cpp
> +++ b/src/libcamera/pipeline/uvcvideo.cpp
> @@ -27,8 +27,7 @@ public:
>
> CameraConfiguration
> generateConfiguration(Camera *camera, const StreamRoles &roles) override;
> - int configure(Camera *camera,
> - const CameraConfiguration &config) override;
> + int configure(Camera *camera, CameraConfiguration &config) override;
>
> int allocateBuffers(Camera *camera,
> const std::set<Stream *> &streams) override;
> @@ -78,38 +77,38 @@ CameraConfiguration
> PipelineHandlerUVC::generateConfiguration(Camera *camera,
> const StreamRoles &roles)
> {
> - UVCCameraData *data = cameraData(camera);
> CameraConfiguration config;
> - StreamConfiguration cfg{};
> + StreamConfiguration cfg;
>
> cfg.pixelFormat = V4L2_PIX_FMT_YUYV;
> cfg.size = { 640, 480 };
> cfg.bufferCount = 4;
>
> - config[&data->stream_] = cfg;
> + config.addConfiguration(cfg);
>
> return config;
> }
>
> -int PipelineHandlerUVC::configure(Camera *camera,
> - const CameraConfiguration &config)
> +int PipelineHandlerUVC::configure(Camera *camera, CameraConfiguration &config)
> {
> UVCCameraData *data = cameraData(camera);
> - const StreamConfiguration *cfg = &config[&data->stream_];
> + StreamConfiguration &cfg = config[0];
> int ret;
>
> V4L2DeviceFormat format = {};
> - format.fourcc = cfg->pixelFormat;
> - format.size = cfg->size;
> + format.fourcc = cfg.pixelFormat;
> + format.size = cfg.size;
>
> ret = data->video_->setFormat(&format);
> if (ret)
> return ret;
>
> - if (format.size != cfg->size ||
> - format.fourcc != cfg->pixelFormat)
> + if (format.size != cfg.size ||
> + format.fourcc != cfg.pixelFormat)
> return -EINVAL;
>
> + cfg.setStream(&data->stream_);
> +
> return 0;
> }
>
> diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp
> index 17e2491e5c27..af6b6f21e3c5 100644
> --- a/src/libcamera/pipeline/vimc.cpp
> +++ b/src/libcamera/pipeline/vimc.cpp
> @@ -27,8 +27,7 @@ public:
>
> CameraConfiguration
> generateConfiguration(Camera *camera, const StreamRoles &roles) override;
> - int configure(Camera *camera,
> - const CameraConfiguration &config) override;
> + int configure(Camera *camera, CameraConfiguration &config) override;
>
> int allocateBuffers(Camera *camera,
> const std::set<Stream *> &streams) override;
> @@ -78,38 +77,38 @@ CameraConfiguration
> PipelineHandlerVimc::generateConfiguration(Camera *camera,
> const StreamRoles &roles)
> {
> - VimcCameraData *data = cameraData(camera);
> CameraConfiguration config;
> - StreamConfiguration cfg{};
> + StreamConfiguration cfg;
>
> cfg.pixelFormat = V4L2_PIX_FMT_RGB24;
> cfg.size = { 640, 480 };
> cfg.bufferCount = 4;
>
> - config[&data->stream_] = cfg;
> + config.addConfiguration(cfg);
>
> return config;
> }
>
> -int PipelineHandlerVimc::configure(Camera *camera,
> - const CameraConfiguration &config)
> +int PipelineHandlerVimc::configure(Camera *camera, CameraConfiguration &config)
> {
> VimcCameraData *data = cameraData(camera);
> - const StreamConfiguration *cfg = &config[&data->stream_];
> + StreamConfiguration &cfg = config[0];
> int ret;
>
> V4L2DeviceFormat format = {};
> - format.fourcc = cfg->pixelFormat;
> - format.size = cfg->size;
> + format.fourcc = cfg.pixelFormat;
> + format.size = cfg.size;
>
> ret = data->video_->setFormat(&format);
> if (ret)
> return ret;
>
> - if (format.size != cfg->size ||
> - format.fourcc != cfg->pixelFormat)
> + if (format.size != cfg.size ||
> + format.fourcc != cfg.pixelFormat)
> return -EINVAL;
>
> + cfg.setStream(&data->stream_);
> +
> return 0;
> }
>
> diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
> index 81c11149c9fe..4185e3557dcb 100644
> --- a/src/libcamera/pipeline_handler.cpp
> +++ b/src/libcamera/pipeline_handler.cpp
> @@ -255,6 +255,10 @@ void PipelineHandler::unlock()
> * configuration of a subset of the streams can't be satisfied, the
> * whole configuration is considered invalid.
> *
> + * Once the configuration is validated and the camera configured, the pipeline
> + * handler shall associate a Stream instance to each StreamConfiguration entry
> + * in the CameraConfiguration with the StreamConfiguration::setStream() method.
> + *
> * \return 0 on success or a negative error code otherwise
> */
>
> diff --git a/src/libcamera/stream.cpp b/src/libcamera/stream.cpp
> index fe4c4ecf4150..0c59a31a3a05 100644
> --- a/src/libcamera/stream.cpp
> +++ b/src/libcamera/stream.cpp
> @@ -58,6 +58,28 @@ namespace libcamera {
> * \brief Requested number of buffers to allocate for the stream
> */
>
> +/**
> + * \fn StreamConfiguration::stream()
> + * \brief Retrieve the stream associated with the configuration
> + *
> + * When a camera is configured with Camera::configure() Stream instances are
> + * associated with each stream configuration entry. This method retrieves the
> + * associated Stream, which remains valid until the next call to
> + * Camera::configure() or Camera::release().
> + *
> + * \return The stream associated with the configuration
> + */
> +
> +/**
> + * \fn StreamConfiguration::setStream()
> + * \brief Associate a stream with a configuration
> + *
> + * This method is meant for the PipelineHandler::configure() method and shall
> + * not be called by applications.
> + *
> + * \param[in] stream The stream
> + */
> +
> /**
> * \brief Assemble and return a string describing the configuration
> *
> diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
> index a984aaca764f..06ae2985f80d 100644
> --- a/src/qcam/main_window.cpp
> +++ b/src/qcam/main_window.cpp
> @@ -98,14 +98,14 @@ int MainWindow::startCapture()
> int ret;
>
> config_ = camera_->generateConfiguration({ StreamRole::VideoRecording });
> - Stream *stream = config_.front();
> ret = camera_->configure(config_);
> if (ret < 0) {
> std::cout << "Failed to configure camera" << std::endl;
> return ret;
> }
>
> - const StreamConfiguration &cfg = config_[stream];
> + const StreamConfiguration &cfg = config_[0];
> + Stream *stream = cfg.stream();
> ret = viewfinder_->setFormat(cfg.pixelFormat, cfg.size.width,
> cfg.size.height);
> if (ret < 0) {
> diff --git a/test/camera/capture.cpp b/test/camera/capture.cpp
> index e7e6438203b9..bfd11eefedcf 100644
> --- a/test/camera/capture.cpp
> +++ b/test/camera/capture.cpp
> @@ -44,8 +44,7 @@ protected:
> {
> CameraConfiguration config =
> camera_->generateConfiguration({ StreamRole::VideoRecording });
> - Stream *stream = config.front();
> - StreamConfiguration *cfg = &config[stream];
> + StreamConfiguration *cfg = &config[0];
>
> if (!config.isValid()) {
> cout << "Failed to read default configuration" << endl;
> @@ -67,6 +66,7 @@ protected:
> return TestFail;
> }
>
> + Stream *stream = cfg->stream();
> BufferPool &pool = stream->bufferPool();
> std::vector<Request *> requests;
> for (Buffer &buffer : pool.buffers()) {
> diff --git a/test/camera/configuration_set.cpp b/test/camera/configuration_set.cpp
> index 76d8bc3e40a4..25b5db67103a 100644
> --- a/test/camera/configuration_set.cpp
> +++ b/test/camera/configuration_set.cpp
> @@ -20,7 +20,7 @@ protected:
> {
> CameraConfiguration config =
> camera_->generateConfiguration({ StreamRole::VideoRecording });
> - StreamConfiguration *cfg = &config[config.front()];
> + StreamConfiguration *cfg = &config[0];
>
> if (!config.isValid()) {
> cout << "Failed to read default configuration" << endl;
> --
> Regards,
>
> Laurent Pinchart
>
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel at lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
--
Regards,
Niklas Söderlund
More information about the libcamera-devel
mailing list