summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2020-12-29 03:52:24 +0200
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2021-03-03 00:59:27 +0200
commit4382d80036409f903bec4b2fa82209ab65012579 (patch)
tree09ca2fecbad9bd69d22c7b15289a30993fe05b97
parent37b3064bedbc4e5754f1690cefee5b150457261c (diff)
libcamera: pipeline: simple: Support configuration of multiple streams
Extend the SimpleCameraConfiguration to support multiple streams, using the multi-stream capability of the SimpleConverter class. Wiring up multi-stream support in the other pipeline handler operations will come in further commits. To keep the code simple, require all streams to use the converter if any stream needs it. It would be possible to generate one stream without conversion (provided the format and size match what the capture device can generate), and this is left as a future optimization. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Tested-by: Phi-Bang Nguyen <pnguyen@baylibre.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
-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,