summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libcamera/pipeline/raspberrypi/raspberrypi.cpp31
-rw-r--r--src/libcamera/pipeline/raspberrypi/rpi_stream.cpp32
-rw-r--r--src/libcamera/pipeline/raspberrypi/rpi_stream.h54
3 files changed, 82 insertions, 35 deletions
diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
index 7d91188c..51544233 100644
--- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
+++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
@@ -890,7 +890,6 @@ int PipelineHandlerRPi::queueAllBuffers(Camera *camera)
int PipelineHandlerRPi::prepareBuffers(Camera *camera)
{
RPiCameraData *data = cameraData(camera);
- unsigned int index;
int ret;
/*
@@ -917,18 +916,14 @@ int PipelineHandlerRPi::prepareBuffers(Camera *camera)
* This will allow us to identify buffers passed between the pipeline
* handler and the IPA.
*/
- index = 0;
for (auto const &b : data->isp_[Isp::Stats].getBuffers()) {
- data->ipaBuffers_.push_back({ .id = RPiIpaMask::STATS | index,
- .planes = b->planes() });
- index++;
+ data->ipaBuffers_.push_back({ .id = RPiIpaMask::STATS | b.first,
+ .planes = b.second->planes() });
}
- index = 0;
for (auto const &b : data->unicam_[Unicam::Embedded].getBuffers()) {
- data->ipaBuffers_.push_back({ .id = RPiIpaMask::EMBEDDED_DATA | index,
- .planes = b->planes() });
- index++;
+ data->ipaBuffers_.push_back({ .id = RPiIpaMask::EMBEDDED_DATA | b.first,
+ .planes = b.second->planes() });
}
data->ipa_->mapBuffers(data->ipaBuffers_);
@@ -1127,7 +1122,7 @@ void RPiCameraData::unicamBufferDequeue(FrameBuffer *buffer)
return;
for (RPi::RPiStream &s : unicam_) {
- index = s.getBufferIndex(buffer);
+ index = s.getBufferId(buffer);
if (index != -1) {
stream = &s;
break;
@@ -1178,7 +1173,7 @@ void RPiCameraData::ispInputDequeue(FrameBuffer *buffer)
return;
LOG(RPI, Debug) << "Stream ISP Input buffer complete"
- << ", buffer id " << unicam_[Unicam::Image].getBufferIndex(buffer)
+ << ", buffer id " << unicam_[Unicam::Image].getBufferId(buffer)
<< ", timestamp: " << buffer->metadata().timestamp;
/* The ISP input buffer gets re-queued into Unicam. */
@@ -1195,7 +1190,7 @@ void RPiCameraData::ispOutputDequeue(FrameBuffer *buffer)
return;
for (RPi::RPiStream &s : isp_) {
- index = s.getBufferIndex(buffer);
+ index = s.getBufferId(buffer);
if (index != -1) {
stream = &s;
break;
@@ -1436,16 +1431,16 @@ void RPiCameraData::tryRunPipeline()
/* Set our state to say the pipeline is active. */
state_ = State::Busy;
- unsigned int bayerIndex = unicam_[Unicam::Image].getBufferIndex(bayerBuffer);
- unsigned int embeddedIndex = unicam_[Unicam::Embedded].getBufferIndex(embeddedBuffer);
+ unsigned int bayerId = unicam_[Unicam::Image].getBufferId(bayerBuffer);
+ unsigned int embeddedId = unicam_[Unicam::Embedded].getBufferId(embeddedBuffer);
LOG(RPI, Debug) << "Signalling RPI_IPA_EVENT_SIGNAL_ISP_PREPARE:"
- << " Bayer buffer id: " << bayerIndex
- << " Embedded buffer id: " << embeddedIndex;
+ << " Bayer buffer id: " << bayerId
+ << " Embedded buffer id: " << embeddedId;
op.operation = RPI_IPA_EVENT_SIGNAL_ISP_PREPARE;
- op.data = { RPiIpaMask::EMBEDDED_DATA | embeddedIndex,
- RPiIpaMask::BAYER_DATA | bayerIndex };
+ op.data = { RPiIpaMask::EMBEDDED_DATA | embeddedId,
+ RPiIpaMask::BAYER_DATA | bayerId };
ipa_->processEvent(op);
}
diff --git a/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp b/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp
index 80170d64..aee0aa2d 100644
--- a/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp
+++ b/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp
@@ -44,26 +44,28 @@ bool RPiStream::isExternal() const
void RPiStream::setExportedBuffers(std::vector<std::unique_ptr<FrameBuffer>> *buffers)
{
- std::transform(buffers->begin(), buffers->end(), std::back_inserter(bufferList_),
- [](std::unique_ptr<FrameBuffer> &b) { return b.get(); });
+ for (auto const &buffer : *buffers)
+ bufferMap_.emplace(id_.get(), buffer.get());
}
-const std::vector<FrameBuffer *> &RPiStream::getBuffers() const
+const BufferMap &RPiStream::getBuffers() const
{
- return bufferList_;
+ return bufferMap_;
}
-int RPiStream::getBufferIndex(FrameBuffer *buffer) const
+int RPiStream::getBufferId(FrameBuffer *buffer) const
{
if (importOnly_)
return -1;
- /* Find the buffer in the list, and return the index position. */
- auto it = std::find(bufferList_.begin(), bufferList_.end(), buffer);
- if (it != bufferList_.end())
- return std::distance(bufferList_.begin(), it);
+ /* Find the buffer in the map, and return the buffer id. */
+ auto it = std::find_if(bufferMap_.begin(), bufferMap_.end(),
+ [&buffer](auto const &p) { return p.second == buffer; });
- return -1;
+ if (it == bufferMap_.end())
+ return -1;
+
+ return it->first;
}
int RPiStream::prepareBuffers(unsigned int count)
@@ -86,7 +88,7 @@ int RPiStream::prepareBuffers(unsigned int count)
}
/* We must import all internal/external exported buffers. */
- count = bufferList_.size();
+ count = bufferMap_.size();
}
return dev_->importBuffers(count);
@@ -139,6 +141,9 @@ void RPiStream::returnBuffer(FrameBuffer *buffer)
/* Push this buffer back into the queue to be used again. */
availableBuffers_.push(buffer);
+ /* Allow the buffer id to be reused. */
+ id_.release(getBufferId(buffer));
+
/*
* Do we have any Request buffers that are waiting to be queued?
* If so, do it now as availableBuffers_ will not be empty.
@@ -196,12 +201,13 @@ void RPiStream::clearBuffers()
availableBuffers_ = std::queue<FrameBuffer *>{};
requestBuffers_ = std::queue<FrameBuffer *>{};
internalBuffers_.clear();
- bufferList_.clear();
+ bufferMap_.clear();
+ id_.reset();
}
int RPiStream::queueToDevice(FrameBuffer *buffer)
{
- LOG(RPISTREAM, Debug) << "Queuing buffer " << getBufferIndex(buffer)
+ LOG(RPISTREAM, Debug) << "Queuing buffer " << getBufferId(buffer)
<< " for " << name_;
int ret = dev_->queueBuffer(buffer);
diff --git a/src/libcamera/pipeline/raspberrypi/rpi_stream.h b/src/libcamera/pipeline/raspberrypi/rpi_stream.h
index 959e9147..df986367 100644
--- a/src/libcamera/pipeline/raspberrypi/rpi_stream.h
+++ b/src/libcamera/pipeline/raspberrypi/rpi_stream.h
@@ -9,8 +9,10 @@
#include <queue>
#include <string>
+#include <unordered_map>
#include <vector>
+#include <libcamera/ipa/raspberrypi.h>
#include <libcamera/stream.h>
#include "libcamera/internal/v4l2_videodevice.h"
@@ -19,6 +21,8 @@ namespace libcamera {
namespace RPi {
+using BufferMap = std::unordered_map<unsigned int, FrameBuffer *>;
+
/*
* Device stream abstraction for either an internal or external stream.
* Used for both Unicam and the ISP.
@@ -27,12 +31,13 @@ class RPiStream : public Stream
{
public:
RPiStream()
+ : id_(RPiIpaMask::ID)
{
}
RPiStream(const char *name, MediaEntity *dev, bool importOnly = false)
: external_(false), importOnly_(importOnly), name_(name),
- dev_(std::make_unique<V4L2VideoDevice>(dev))
+ dev_(std::make_unique<V4L2VideoDevice>(dev)), id_(RPiIpaMask::ID)
{
}
@@ -45,8 +50,8 @@ public:
bool isExternal() const;
void setExportedBuffers(std::vector<std::unique_ptr<FrameBuffer>> *buffers);
- const std::vector<FrameBuffer *> &getBuffers() const;
- int getBufferIndex(FrameBuffer *buffer) const;
+ const BufferMap &getBuffers() const;
+ int getBufferId(FrameBuffer *buffer) const;
int prepareBuffers(unsigned int count);
int queueBuffer(FrameBuffer *buffer);
@@ -56,6 +61,44 @@ public:
void releaseBuffers();
private:
+ class IdGenerator
+ {
+ public:
+ IdGenerator(int max)
+ : max_(max), id_(0)
+ {
+ }
+
+ int get()
+ {
+ int id;
+ if (!recycle_.empty()) {
+ id = recycle_.front();
+ recycle_.pop();
+ } else {
+ id = id_++;
+ ASSERT(id_ <= max_);
+ }
+ return id;
+ }
+
+ void release(int id)
+ {
+ recycle_.push(id);
+ }
+
+ void reset()
+ {
+ id_ = 0;
+ recycle_ = {};
+ }
+
+ private:
+ int max_;
+ int id_;
+ std::queue<int> recycle_;
+ };
+
void clearBuffers();
int queueToDevice(FrameBuffer *buffer);
@@ -74,8 +117,11 @@ private:
/* The actual device stream. */
std::unique_ptr<V4L2VideoDevice> dev_;
+ /* Tracks a unique id key for the bufferMap_ */
+ IdGenerator id_;
+
/* All frame buffers associated with this device stream. */
- std::vector<FrameBuffer *> bufferList_;
+ BufferMap bufferMap_;
/*
* List of frame buffers that we can use if none have been provided by
ref='#n554'>554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
 * Copyright (C) 2018, Google Inc.
 *
 * pipeline_handler.cpp - Pipeline handler infrastructure
 */

#include "libcamera/internal/pipeline_handler.h"

#include <sys/sysmacros.h>

#include <libcamera/base/log.h>
#include <libcamera/base/utils.h>

#include <libcamera/camera.h>
#include <libcamera/camera_manager.h>
#include <libcamera/framebuffer.h>

#include "libcamera/internal/camera.h"
#include "libcamera/internal/device_enumerator.h"
#include "libcamera/internal/media_device.h"
#include "libcamera/internal/tracepoints.h"

/**
 * \file pipeline_handler.h
 * \brief Create pipelines and cameras from a set of media devices
 *
 * Each pipeline supported by libcamera needs to be backed by a pipeline
 * handler implementation that operate on a set of media devices. The pipeline
 * handler is responsible for matching the media devices it requires with the
 * devices present in the system, and once all those devices can be acquired,
 * create corresponding Camera instances.
 *
 * Every subclass of PipelineHandler shall be registered with libcamera using
 * the REGISTER_PIPELINE_HANDLER() macro.
 */

namespace libcamera {

LOG_DEFINE_CATEGORY(Pipeline)

/**
 * \class PipelineHandler
 * \brief Create and manage cameras based on a set of media devices
 *
 * The PipelineHandler matches the media devices provided by a DeviceEnumerator
 * with the pipelines it supports and creates corresponding Camera devices.
 *
 * Pipeline handler instances are reference-counted through std::shared_ptr<>.
 * They implement std::enable_shared_from_this<> in order to create new
 * std::shared_ptr<> in code paths originating from member functions of the
 * PipelineHandler class where only the 'this' pointer is available.
 */

/**
 * \brief Construct a PipelineHandler instance
 * \param[in] manager The camera manager
 *
 * In order to honour the std::enable_shared_from_this<> contract,
 * PipelineHandler instances shall never be constructed manually, but always
 * through the PipelineHandlerFactory::create() function implemented by the
 * respective factories.
 */
PipelineHandler::PipelineHandler(CameraManager *manager)
	: manager_(manager)
{
}

PipelineHandler::~PipelineHandler()
{
	for (std::shared_ptr<MediaDevice> media : mediaDevices_)
		media->release();
}

/**
 * \fn PipelineHandler::match(DeviceEnumerator *enumerator)
 * \brief Match media devices and create camera instances
 * \param[in] enumerator The enumerator providing all media devices found in the
 * system
 *
 * This function is the main entry point of the pipeline handler. It is called
 * by the camera manager with the \a enumerator passed as an argument. It shall
 * acquire from the \a enumerator all the media devices it needs for a single
 * pipeline, create one or multiple Camera instances and register them with the
 * camera manager.
 *
 * If all media devices needed by the pipeline handler are found, they must all
 * be acquired by a call to MediaDevice::acquire(). This function shall then
 * create the corresponding Camera instances, store them internally, and return
 * true. Otherwise it shall not acquire any media device (or shall release all
 * the media devices is has acquired by calling MediaDevice::release()) and
 * return false.
 *
 * If multiple instances of a pipeline are available in the system, the
 * PipelineHandler class will be instantiated once per instance, and its match()
 * function called for every instance. Each call shall acquire media devices for
 * one pipeline instance, until all compatible media devices are exhausted.
 *
 * If this function returns true, a new instance of the pipeline handler will
 * be created and its match() function called.
 *
 * \context This function is called from the CameraManager thread.
 *
 * \return true if media devices have been acquired and camera instances
 * created, or false otherwise
 */

/**
 * \brief Search and acquire a MediaDevice matching a device pattern
 * \param[in] enumerator Enumerator containing all media devices in the system
 * \param[in] dm Device match pattern
 *
 * Search the device \a enumerator for an available media device matching the
 * device match pattern \a dm. Matching media device that have previously been
 * acquired by MediaDevice::acquire() are not considered. If a match is found,