[libcamera-devel,1/1] android: [WIP] Map between camera configuration and requested configuration

Message ID 20200806061706.1025788-2-hiroh@chromium.org
State Superseded
Headers show
Series
  • Proposal of mapping between camera configurations and requested configurations
Related show

Commit Message

Hirokazu Honda Aug. 6, 2020, 6:17 a.m. UTC
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(-)

Patch

diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp
index b49d668..0f0a540 100644
--- a/src/android/camera_device.cpp
+++ b/src/android/camera_device.cpp
@@ -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;
+}
diff --git a/src/android/camera_device.h b/src/android/camera_device.h
index 00472c2..fdbc9f3 100644
--- a/src/android/camera_device.h
+++ b/src/android/camera_device.h
@@ -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_;