@@ -913,7 +913,7 @@ const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type)
return requestTemplate->get();
}
-PixelFormat CameraDevice::toPixelFormat(int format)
+PixelFormat CameraDevice::toPixelFormat(int format) const
{
/* Translate Android format code to libcamera pixel format. */
auto it = formatsMap_.find(format);
@@ -985,26 +985,18 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)
switch (config_->validate()) {
case CameraConfiguration::Valid:
- break;
case CameraConfiguration::Adjusted:
- LOG(HAL, Info) << "Camera configuration adjusted";
- config_.reset();
- return -EINVAL;
+ break;
case CameraConfiguration::Invalid:
LOG(HAL, Info) << "Camera configuration invalid";
config_.reset();
return -EINVAL;
}
- for (unsigned int i = 0; i < stream_list->num_streams; ++i) {
- camera3_stream_t *stream = stream_list->streams[i];
- CameraStream *cameraStream = &streams_[i];
- StreamConfiguration &cfg = config_->at(cameraStream->index);
-
- /* Use the bufferCount confirmed by the validation process. */
- stream->max_buffers = cfg.bufferCount;
+ if (!mapStreams(stream_list, *config_)) {
+ LOG(HAL, Info) << "Unsupported configurations";
+ return -EINVAL;
}
-
/*
* Once the CameraConfiguration has been adjusted/validated
* it can be applied to the camera.
@@ -1277,3 +1269,121 @@ std::unique_ptr<CameraMetadata> CameraDevice::getResultMetadata(int frame_number
return resultMetadata;
}
+
+bool CameraDevice::convertible(const Size& srcSize, const PixelFormat& srcFormat,
+ const Size& dstSize, const PixelFormat& dstFormat) const
+{
+ // TODO: Implement this.
+ return true;
+}
+
+bool CameraDevice::getBestCameraStream(
+ const std::vector<libcamera::CameraConfiguration::const_iterator>& sameRatios,
+ const std::vector<libcamera::CameraConfiguration::const_iterator>& sameFormats,
+ const Size& requestedSize,
+ const PixelFormat& requestedFormat,
+ libcamera::CameraConfiguration::const_iterator* bestCameraStream) const
+{
+ // 3. Find the stream whose ratio and format are same as requested ones.
+ for (const auto& it : sameRatios) {
+ if (std::find(sameFormats.begin(), sameFormats.end(), it) != sameFormats.end() &&
+ convertible(requestedSize, requestedFormat, it->size, it->pixelFormat)) {
+ // SameRatio and sameFormat.
+ // Scale-only. (or no-op if the resolution is the same as the requested one.
+ *bestCameraStream = it;
+ return true;
+ }
+ }
+
+ // 4. Find the smallest resolution stream among ones whose ratios are the same as requested one.
+ for (const auto& it : sameRatios) {
+ if (convertible(requestedSize, requestedFormat, it->size, it->pixelFormat)) {
+ // Scale & Pixel format conversion.
+ *bestCameraStream = it;
+ return true;
+ }
+ }
+
+ // 5. Find the smallest resolution stream among ones whose formats are the same as requested one.
+ for (const auto& it : sameFormats) {
+ if (convertible(requestedSize, requestedFormat, it->size, it->pixelFormat)) {
+ // Scale & Crop.
+ *bestCameraStream = it;
+ return true;
+ }
+ }
+ return false;
+}
+
+/*
+ * Finds best matching between requested configurations and configurations adjusted by CameraConfiguration class.
+ * Returns false if no convertible camera configuration is found for a requested configuration.
+ */
+bool CameraDevice::mapStreams(camera3_stream_configuration_t* requestedStreams,
+ const libcamera::CameraConfiguration& config) const {
+ std::vector<libcamera::CameraConfiguration::const_iterator> candidates;
+ for (auto it = config.begin(); it != config.end(); ++it) {
+ candidates.push_back(it);
+ }
+
+ for (size_t i = 0; i < requestedStreams->num_streams; ++i) {
+ const camera3_stream_t& requestedStream = *requestedStreams->streams[i];
+ const Size requestedSize(requestedStream.width, requestedStream.height);
+ decltype(candidates) currentCandidates;
+ // 1. Filters out smaller resolution's streams than requestedSize.
+ std::copy_if(candidates.begin(), candidates.end(),
+ std::back_inserter(currentCandidates),
+ [requestedSize](const auto& it) {
+ const StreamConfiguration& cfg = *it;
+ return requestedSize.width <= cfg.size.width &&
+ requestedSize.height <= cfg.size.height;
+ });
+ // 2. Prioritizes smaller resolutions.
+ std::sort(currentCandidates.begin(), currentCandidates.end(),
+ [](const auto& itA, const auto& itB) {
+ return itA->size < itB->size;
+ });
+
+ auto getRatio = [](const Size& size) {
+ int d = std::__gcd(size.width, size.height);
+ return Size(size.width / d, size.height / d);
+ };
+ decltype(candidates) sameRatios; // = list of ones whose ratios are as requested one.
+ std::copy_if(currentCandidates.begin(), currentCandidates.end(),
+ std::back_inserter(sameRatios),
+ [&getRatio, requestedRatio=getRatio(requestedSize)](const auto& it) {
+ return requestedRatio == getRatio(it->size);
+ });
+ decltype(candidates) sameFormats; // = list of ones whose formats are as requested one.
+ const PixelFormat requestedFormat = toPixelFormat(requestedStream.format);
+ if (requestedFormat.isValid()) {
+ std::copy_if(currentCandidates.begin(), currentCandidates.end(),
+ std::back_inserter(sameFormats),
+ [requestedFormat](const auto& it) {
+ return requestedFormat == it->pixelFormat;
+ });
+ }
+
+ auto bestCameraStream = config.end();
+ if (!getBestCameraStream(sameRatios, sameFormats, requestedSize, requestedFormat, &bestCameraStream)) {
+ // 6. Find one whose resolution is the smallest among convertible ones.
+ auto convertibleConfig =
+ std::find_if(currentCandidates.begin(), currentCandidates.end(),
+ [requestedSize, requestedFormat,this](const auto& it) {
+ return convertible(requestedSize, requestedFormat, it->size, it->pixelFormat);
+ });
+ if (convertibleConfig != currentCandidates.end()) {
+ // No map is available.
+ LOG(HAL, Info) << "No convertible configuration, i=" << i;
+ return false;
+ }
+ bestCameraStream = *convertibleConfig;
+ }
+ assert(bestCameraStream != config.end());
+
+ CameraStream* cameraStream = reinterpret_cast<CameraStream*>(requestedStreams->streams[i]->priv);
+ cameraStream->index = (unsigned int) (bestCameraStream - config.begin());
+ }
+
+ return true;
+}
@@ -83,10 +83,18 @@ private:
libcamera::FrameBuffer *createFrameBuffer(const buffer_handle_t camera3buffer);
void notifyShutter(uint32_t frameNumber, uint64_t timestamp);
void notifyError(uint32_t frameNumber, camera3_stream_t *stream);
- libcamera::PixelFormat toPixelFormat(int format);
+ libcamera::PixelFormat toPixelFormat(int format) const;
std::unique_ptr<CameraMetadata> getResultMetadata(int frame_number,
int64_t timestamp);
-
+ bool convertible(const libcamera::Size& srcSize, const libcamera::PixelFormat& srcFormat,
+ const libcamera::Size& dstSize, const libcamera::PixelFormat& dstFormat) const;
+ bool getBestCameraStream(const std::vector<libcamera::CameraConfiguration::const_iterator>& sameRatios,
+ const std::vector<libcamera::CameraConfiguration::const_iterator>& sameFormats,
+ const libcamera::Size& requestedSize,
+ const libcamera::PixelFormat& requestedFormat,
+ libcamera::CameraConfiguration::const_iterator* bestCameraStream) const;
+ bool mapStreams(camera3_stream_configuration_t* requestedStreams,
+ const libcamera::CameraConfiguration& config) const;
unsigned int id_;
camera3_device_t camera3Device_;
Signed-off-by: Hirokazu Honda <hiroh@chromium.org> --- src/android/camera_device.cpp | 136 ++++++++++++++++++++++++++++++---- src/android/camera_device.h | 12 ++- 2 files changed, 133 insertions(+), 15 deletions(-)