summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libcamera/pipeline/simple/simple.cpp166
1 files changed, 100 insertions, 66 deletions
diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
index 9f822397..ce4e42c3 100644
--- a/src/libcamera/pipeline/simple/simple.cpp
+++ b/src/libcamera/pipeline/simple/simple.cpp
@@ -538,64 +538,96 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate()
}
/* Cap the number of entries to the available streams. */
- if (config_.size() > 1) {
- config_.resize(1);
+ if (config_.size() > data_->streams_.size()) {
+ config_.resize(data_->streams_.size());
status = Adjusted;
}
- StreamConfiguration &cfg = config_[0];
-
- /* Adjust the pixel format. */
- auto it = data_->formats_.find(cfg.pixelFormat);
- if (it == data_->formats_.end())
- it = data_->formats_.begin();
+ /*
+ * Pick a configuration for the pipeline based on the pixel format for
+ * the streams (ordered from highest to lowest priority). Default to
+ * the first pipeline configuration if no streams requests a supported
+ * pixel format.
+ */
+ pipeConfig_ = data_->formats_.begin()->second;
- PixelFormat pixelFormat = it->first;
- if (cfg.pixelFormat != pixelFormat) {
- LOG(SimplePipeline, Debug) << "Adjusting pixel format";
- cfg.pixelFormat = pixelFormat;
- status = Adjusted;
+ for (const StreamConfiguration &cfg : config_) {
+ auto it = data_->formats_.find(cfg.pixelFormat);
+ if (it != data_->formats_.end()) {
+ pipeConfig_ = it->second;
+ break;
+ }
}
- pipeConfig_ = it->second;
- if (!pipeConfig_->outputSizes.contains(cfg.size)) {
- LOG(SimplePipeline, Debug)
- << "Adjusting size from " << cfg.size.toString()
- << " to " << pipeConfig_->captureSize.toString();
- cfg.size = pipeConfig_->captureSize;
- status = Adjusted;
- }
+ /* Adjust the requested streams. */
+ SimplePipelineHandler *pipe = static_cast<SimplePipelineHandler *>(data_->pipe_);
+ SimpleConverter *converter = pipe->converter();
- /* \todo Create a libcamera core class to group format and size */
- needConversion_ = cfg.pixelFormat != pipeConfig_->captureFormat
- || cfg.size != pipeConfig_->captureSize;
+ /*
+ * Enable usage of the converter when producing multiple streams, as
+ * the video capture device can't capture to multiple buffers.
+ *
+ * It is possible to produce up to one stream without conversion
+ * (provided the format and size match), at the expense of more complex
+ * buffer handling (including allocation of internal buffers to be used
+ * when a request doesn't contain a buffer for the stream that doesn't
+ * require any conversion, similar to raw capture use cases). This is
+ * left as a future improvement.
+ */
+ needConversion_ = config_.size() > 1;
+
+ for (unsigned int i = 0; i < config_.size(); ++i) {
+ StreamConfiguration &cfg = config_[i];
+
+ /* Adjust the pixel format and size. */
+ auto it = std::find(pipeConfig_->outputFormats.begin(),
+ pipeConfig_->outputFormats.end(),
+ cfg.pixelFormat);
+ if (it == pipeConfig_->outputFormats.end())
+ it = pipeConfig_->outputFormats.begin();
+
+ PixelFormat pixelFormat = *it;
+ if (cfg.pixelFormat != pixelFormat) {
+ LOG(SimplePipeline, Debug) << "Adjusting pixel format";
+ cfg.pixelFormat = pixelFormat;
+ status = Adjusted;
+ }
- cfg.bufferCount = 3;
+ if (!pipeConfig_->outputSizes.contains(cfg.size)) {
+ LOG(SimplePipeline, Debug)
+ << "Adjusting size from " << cfg.size.toString()
+ << " to " << pipeConfig_->captureSize.toString();
+ cfg.size = pipeConfig_->captureSize;
+ status = Adjusted;
+ }
- /* Set the stride and frameSize. */
- if (!needConversion_) {
- V4L2DeviceFormat format;
- format.fourcc = data_->video_->toV4L2PixelFormat(cfg.pixelFormat);
- format.size = cfg.size;
+ /* \todo Create a libcamera core class to group format and size */
+ if (cfg.pixelFormat != pipeConfig_->captureFormat ||
+ cfg.size != pipeConfig_->captureSize)
+ needConversion_ = true;
+
+ /* Set the stride, frameSize and bufferCount. */
+ if (needConversion_) {
+ std::tie(cfg.stride, cfg.frameSize) =
+ converter->strideAndFrameSize(cfg.pixelFormat, cfg.size);
+ if (cfg.stride == 0)
+ return Invalid;
+ } else {
+ V4L2DeviceFormat format;
+ format.fourcc = data_->video_->toV4L2PixelFormat(cfg.pixelFormat);
+ format.size = cfg.size;
- int ret = data_->video_->tryFormat(&format);
- if (ret < 0)
- return Invalid;
+ int ret = data_->video_->tryFormat(&format);
+ if (ret < 0)
+ return Invalid;
- cfg.stride = format.planes[0].bpl;
- cfg.frameSize = format.planes[0].size;
+ cfg.stride = format.planes[0].bpl;
+ cfg.frameSize = format.planes[0].size;
+ }
- return status;
+ cfg.bufferCount = 3;
}
- SimplePipelineHandler *pipe = static_cast<SimplePipelineHandler *>(data_->pipe_);
- SimpleConverter *converter = pipe->converter();
-
- std::tie(cfg.stride, cfg.frameSize) =
- converter->strideAndFrameSize(cfg.pixelFormat, cfg.size);
- if (cfg.stride == 0)
- return Invalid;
-
return status;
}
@@ -629,16 +661,18 @@ CameraConfiguration *SimplePipelineHandler::generateConfiguration(Camera *camera
});
/*
- * Create the stream configuration. Take the first entry in the formats
+ * Create the stream configurations. Take the first entry in the formats
* map as the default, for lack of a better option.
*
* \todo Implement a better way to pick the default format
*/
- StreamConfiguration cfg{ StreamFormats{ formats } };
- cfg.pixelFormat = formats.begin()->first;
- cfg.size = formats.begin()->second[0].max;
+ for ([[maybe_unused]] StreamRole role : roles) {
+ StreamConfiguration cfg{ StreamFormats{ formats } };
+ cfg.pixelFormat = formats.begin()->first;
+ cfg.size = formats.begin()->second[0].max;
- config->addConfiguration(cfg);
+ config->addConfiguration(cfg);
+ }
config->validate();
@@ -651,7 +685,6 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c)
static_cast<SimpleCameraConfiguration *>(c);
SimpleCameraData *data = cameraData(camera);
V4L2VideoDevice *video = data->video_;
- StreamConfiguration &cfg = config->at(0);
int ret;
/*
@@ -695,28 +728,29 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c)
return -EINVAL;
}
- /* Configure the converter if required. */
+ /* Configure the converter if needed. */
+ std::vector<std::reference_wrapper<StreamConfiguration>> outputCfgs;
data->useConverter_ = config->needConversion();
- if (data->useConverter_) {
- StreamConfiguration inputCfg;
- inputCfg.pixelFormat = pipeConfig->captureFormat;
- inputCfg.size = pipeConfig->captureSize;
- inputCfg.stride = captureFormat.planes[0].bpl;
- inputCfg.bufferCount = kNumInternalBuffers;
- ret = converter_->configure(inputCfg, { cfg });
- if (ret < 0) {
- LOG(SimplePipeline, Error)
- << "Unable to configure converter";
- return ret;
- }
+ for (unsigned int i = 0; i < config->size(); ++i) {
+ StreamConfiguration &cfg = config->at(i);
- LOG(SimplePipeline, Debug) << "Using format converter";
+ cfg.setStream(&data->streams_[i]);
+
+ if (data->useConverter_)
+ outputCfgs.push_back(cfg);
}
- cfg.setStream(&data->streams_[0]);
+ if (outputCfgs.empty())
+ return 0;
+
+ StreamConfiguration inputCfg;
+ inputCfg.pixelFormat = pipeConfig->captureFormat;
+ inputCfg.size = pipeConfig->captureSize;
+ inputCfg.stride = captureFormat.planes[0].bpl;
+ inputCfg.bufferCount = kNumInternalBuffers;
- return 0;
+ return converter_->configure(inputCfg, outputCfgs);
}
int SimplePipelineHandler::exportFrameBuffers(Camera *camera, Stream *stream,