@@ -377,7 +377,7 @@ int ImgUDevice::init(MediaDevice *media, unsigned int index)
* \return An ImgUDevice::PipeConfig instance on success, an empty configuration
* otherwise
*/
-ImgUDevice::PipeConfig ImgUDevice::calculatePipeConfig(Pipe *pipe)
+ImgUDevice::PipeConfig ImgUDevice::calculatePipeConfig(Pipe *pipe) const
{
pipeConfigs.clear();
@@ -43,7 +43,7 @@ public:
int init(MediaDevice *media, unsigned int index);
- PipeConfig calculatePipeConfig(Pipe *pipe);
+ PipeConfig calculatePipeConfig(Pipe *pipe) const;
int configure(const PipeConfig &pipeConfig, V4L2DeviceFormat *inputFormat);
@@ -73,11 +73,15 @@ public:
IPU3CameraConfiguration(IPU3CameraData *data);
Status validate() override;
+ bool tryValidate(std::vector<std::pair<StreamConfiguration, Status>> &config) const override;
const StreamConfiguration &cio2Format() const { return cio2Configuration_; }
const ImgUDevice::PipeConfig imguConfig() const { return pipeConfig_; }
private:
+ bool tryValidateInternal(
+ std::vector<std::pair<StreamConfiguration, Status>> &configs,
+ ImgUDevice::PipeConfig &pipeConfig) const;
/*
* The IPU3CameraData instance is guaranteed to be valid as long as the
* corresponding Camera instance is valid. In order to borrow a
@@ -140,6 +144,162 @@ IPU3CameraConfiguration::IPU3CameraConfiguration(IPU3CameraData *data)
data_ = data;
}
+
+bool IPU3CameraConfiguration::tryValidateInternal(
+ std::vector<std::pair<StreamConfiguration, Status>> &configs,
+ ImgUDevice::PipeConfig &pipeConfig) const
+{
+ if (configs.empty() || configs.size() > IPU3_MAX_STREAMS)
+ return false;
+
+ unsigned int rawCount = 0;
+ unsigned int yuvCount = 0;
+ Size maxYuvSize;
+ for (size_t i = 0; i < configs.size(); ++i) {
+ const auto &cfg = configs[i].first;
+ const PixelFormatInfo &info = PixelFormatInfo::info(cfg.pixelFormat);
+ if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW) {
+ rawCount++;
+ } else {
+ yuvCount++;
+ maxYuvSize.expandTo(cfg.size);
+ }
+ }
+ LOG(IPU3, Debug) << rawCount << ", " << yuvCount;
+ if (rawCount > 1 || yuvCount > 2)
+ return false;
+
+ StreamConfiguration cio2Configuration =
+ data_->cio2_.generateConfiguration({});
+ if (!cio2Configuration.pixelFormat.isValid())
+ return false;
+ LOG(IPU3, Debug) << "CIO2 configuration: " << cio2Configuration.toString();
+
+ ImgUDevice::Pipe pipe{};
+ pipe.input = cio2Configuration.size;
+
+ bool mainOutputAvailable = true;
+ for (auto &[cfg, status] : configs) {
+ const PixelFormatInfo &info = PixelFormatInfo::info(cfg.pixelFormat);
+ const StreamConfiguration originalCfg = cfg;
+
+ LOG(IPU3, Debug) << "Validating " << cfg.toString()
+ << " to the raw stream";
+ if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW) {
+ cfg.size = cio2Configuration.size;
+ cfg.pixelFormat = cio2Configuration.pixelFormat;
+ cfg.bufferCount = cio2Configuration.bufferCount;
+ cfg.stride = info.stride(cfg.size.width, 0, 64);
+ cfg.frameSize = info.frameSize(cfg.size, 64);
+ cfg.setStream(const_cast<Stream *>(&data_->rawStream_));
+ LOG(IPU3, Debug) << "Assigned " << cfg.toString()
+ << " to the raw stream";
+ } else {
+ unsigned int limit;
+ limit = utils::alignDown(cio2Configuration.size.width - 1,
+ IMGU_OUTPUT_WIDTH_MARGIN);
+ cfg.size.width = std::clamp(cfg.size.width,
+ IMGU_OUTPUT_MIN_SIZE.width,
+ limit);
+
+ limit = utils::alignDown(cio2Configuration.size.height - 1,
+ IMGU_OUTPUT_HEIGHT_MARGIN);
+ cfg.size.height = std::clamp(cfg.size.height,
+ IMGU_OUTPUT_MIN_SIZE.height,
+ limit);
+
+ cfg.size.alignDownTo(IMGU_OUTPUT_WIDTH_ALIGN,
+ IMGU_OUTPUT_HEIGHT_ALIGN);
+
+ cfg.pixelFormat = formats::NV12;
+ cfg.bufferCount = IPU3_BUFFER_COUNT;
+ cfg.stride = info.stride(cfg.size.width, 0, 1);
+ cfg.frameSize = info.frameSize(cfg.size, 1);
+
+ if (mainOutputAvailable &&
+ (originalCfg.size == maxYuvSize || yuvCount == 1)) {
+ cfg.setStream(const_cast<Stream *>(&data_->outStream_));
+ mainOutputAvailable = false;
+
+ pipe.main = cfg.size;
+ if (yuvCount == 1)
+ pipe.viewfinder = pipe.main;
+
+ LOG(IPU3, Debug) << "Assigned " << cfg.toString()
+ << " to the main output";
+ } else {
+ cfg.setStream(const_cast<Stream *>(&data_->vfStream_));
+ pipe.viewfinder = cfg.size;
+
+ LOG(IPU3, Debug) << "Assigned " << cfg.toString()
+ << " to the viewfinder output";
+ }
+ }
+ if (cfg.pixelFormat != originalCfg.pixelFormat ||
+ cfg.size != originalCfg.size) {
+ LOG(IPU3, Debug)
+ << "Stream configuration adjusted to "
+ << cfg.toString();
+
+ status = Adjusted;
+ }
+ }
+
+ if (yuvCount) {
+ pipeConfig = data_->imgu_->calculatePipeConfig(&pipe);
+ if (pipeConfig.isNull())
+ return false;
+ }
+ return true;
+}
+
+bool IPU3CameraConfiguration::tryValidate(
+ std::vector<std::pair<StreamConfiguration, Status>> &configs) const
+{
+ if (configs.empty())
+ return Invalid;
+
+ struct AcceptedConfig {
+ StreamConfiguration config;
+ Status status;
+ unsigned int index;
+ };
+ std::vector<AcceptedConfig> acceptedConfigs;
+ for (unsigned int i = 0; i < configs.size(); ++i) {
+ LOG(IPU3, Debug) << "Trying config #" << i
+ << ": " << configs[i].first.toString();
+ std::vector<std::pair<StreamConfiguration, Status>>
+ tryConfigs(acceptedConfigs.size() + 1);
+ for (unsigned int j = 0; j < acceptedConfigs.size(); ++j) {
+ tryConfigs[j].first = acceptedConfigs[j].config;
+ tryConfigs[j].second = Valid;
+ }
+ tryConfigs.back().first = configs[i].first;
+ tryConfigs.back().second = Valid;
+ ImgUDevice::PipeConfig tryPipeConfig;
+ if (!tryValidateInternal(tryConfigs, tryPipeConfig))
+ continue;
+
+ for (unsigned int j = 0; j < acceptedConfigs.size(); ++j) {
+ acceptedConfigs[j].config = tryConfigs[j].first;
+ acceptedConfigs[j].status = tryConfigs[j].second;
+ }
+ acceptedConfigs.push_back(
+ { tryConfigs[i].first, tryConfigs[i].second, i });
+ }
+
+ for (unsigned int i = 0; i < configs.size(); ++i)
+ configs[i].second = Invalid;
+
+ for (auto &&ac : acceptedConfigs) {
+ unsigned int i = ac.index;
+ configs[i].first = std::move(ac.config);
+ configs[i].second = ac.status;
+ }
+
+ return !acceptedConfigs.empty();
+}
+
CameraConfiguration::Status IPU3CameraConfiguration::validate()
{
Status status = Valid;
IPU3CameraConfiguration::tryValidate() is implemented. It is mostly the same as the validate() implementation. Signed-off-by: Hirokazu Honda <hiroh@chromium.org> --- src/libcamera/pipeline/ipu3/imgu.cpp | 2 +- src/libcamera/pipeline/ipu3/imgu.h | 2 +- src/libcamera/pipeline/ipu3/ipu3.cpp | 160 +++++++++++++++++++++++++++ 3 files changed, 162 insertions(+), 2 deletions(-) -- 2.30.0.365.g02bc693789-goog