[libcamera-devel,RFC,6/6] android: camera_device: Support stream mapping
diff mbox series

Message ID 20210204100541.657503-7-hiroh@chromium.org
State New
Headers show
Series
  • Support stream mapping in Android HAL adaptation layer
Related show

Commit Message

Hirokazu Honda Feb. 4, 2021, 10:05 a.m. UTC
This add the support of stream mapping in Android HAL adaptation
layer. It helps to produce a stream that cannot be output by
a native camera directly.

Signed-off-by: Hirokazu Honda <hiroh@chromium.org>
---
 src/android/camera_device.cpp | 143 ++++++++++++++++++++++++++++++++++
 1 file changed, 143 insertions(+)

--
2.30.0.365.g02bc693789-goog

Patch
diff mbox series

diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp
index a1ef07b6..d45f83c1 100644
--- a/src/android/camera_device.cpp
+++ b/src/android/camera_device.cpp
@@ -316,6 +316,132 @@  void sortCamera3StreamConfigs(std::vector<Camera3StreamConfig> &unsortedConfigs,
 	unsortedConfigs = sortedConfigs;
 }

+bool canConvert(const StreamConfiguration &srcConfig,
+		const camera3_stream_t &dstStream,
+		CameraStream::Type &type,
+		PostProcessorType &postProcessorType)
+{
+	/* NV12 -> JPEG conversion. */
+	if (srcConfig.pixelFormat == formats::NV12 &&
+	    dstStream.format == HAL_PIXEL_FORMAT_BLOB &&
+	    dstStream.width == srcConfig.size.width &&
+	    dstStream.height == srcConfig.size.height) {
+		type = CameraStream::Type::Mapped;
+		postProcessorType = PostProcessorType::Jpeg;
+		return true;
+	}
+
+	/* NV12 -> NV12 */
+	if (srcConfig.pixelFormat == formats::NV12 &&
+	    (dstStream.format == HAL_PIXEL_FORMAT_YCbCr_420_888 ||
+	     dstStream.format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)) {
+		if (dstStream.width == srcConfig.size.width &&
+		    dstStream.height == srcConfig.size.height) {
+			/* Duplicated stream. No post processing is required. */
+			type = CameraStream::Type::Direct;
+			postProcessorType = PostProcessorType::None;
+			return true;
+		} else if(dstStream.width < srcConfig.size.width &&
+			  dstStream.height < srcConfig.size.height) {
+			/* Down scaling. */
+			type = CameraStream::Type::Mapped;
+			postProcessorType = PostProcessorType::Yuv;
+			return true;
+		}
+	}
+	return false;
+}
+
+bool mapConfig(
+	std::vector<Camera3StreamConfig> &streamConfigs,
+	const std::vector<std::pair<StreamConfiguration,
+				    CameraConfiguration::Status>> &tryConfigs)
+{
+	const StreamConfiguration kInvalidStreamConfiguration{};
+	assert(!kInvalidStreamConfiguration.pixelFormat.isValid());
+	std::vector<camera3_stream_t *> dstStreams;
+	for (size_t i = 0; i < tryConfigs.size(); i++) {
+		LOG(HAL, Debug) << "StreamConfiguration #" << i << ": "
+				<< tryConfigs[i].first.toString()
+				<< ", tryValidate() result ="
+				<< static_cast<int>(tryConfigs[i].second);
+		if (tryConfigs[i].second == CameraConfiguration::Valid)
+			continue;
+
+		for (auto &stream : streamConfigs[i].streams)
+			dstStreams.push_back(stream.stream);
+		streamConfigs[i].streams.clear();
+
+		if (tryConfigs[i].second == CameraConfiguration::Adjusted) {
+			streamConfigs[i].config =
+				std::move(tryConfigs[i].first);
+		} else {
+			/* Set invalid StreamConfiguration for a
+			 * CameraConfiguration::Invalid stream.
+			 */
+			streamConfigs[i].config = kInvalidStreamConfiguration;
+		}
+	}
+
+	/* Remove elements in streamConfigs whose stream is evaluated as
+	 * CameraConfiguration::Invalid.
+	 */
+	streamConfigs.erase(
+		std::remove_if(streamConfigs.begin(), streamConfigs.end(),
+			       [](const auto &cfg) {
+				       return !cfg.config.pixelFormat.isValid();
+			       }),
+		streamConfigs.end());
+
+	/* Find a new source StreamConfiguration from which |dstStream| can be
+	 * produced.
+	 */
+	for (auto *const dstStream : dstStreams) {
+		auto bestPostProcessorType = PostProcessorType::None;
+		auto bestType = CameraStream::Type::Mapped;
+		Camera3StreamConfig *bestConfig = nullptr;
+
+		for (auto &streamConfig : streamConfigs) {
+			auto type = CameraStream::Type::Mapped;
+			auto postProcessorType = PostProcessorType::None;
+
+			if (canConvert(streamConfig.config, *dstStream, type,
+				       postProcessorType) &&
+			    static_cast<uint8_t>(type) < static_cast<uint8_t>(bestType)) {
+				bestType = type;
+				bestPostProcessorType = postProcessorType;
+				bestConfig = &streamConfig;
+			}
+		}
+
+		if (!bestConfig) {
+			LOG(HAL, Error)
+				<< "No convertible native stream for the stream"
+				<< ", width: " << dstStream->width
+				<< ", height: " << dstStream->height
+				<< ", format: " << utils::hex(dstStream->format);
+			return false;
+		}
+
+		Camera3StreamConfig::Camera3Stream stream(
+			dstStream, bestType, bestPostProcessorType);
+		LOG(HAL, Error)
+			<< " Mapped to StreamConfiguration: "
+			<< bestConfig->config.toString()
+			<< " from " << stream.toString();
+		bestConfig->streams.push_back(std::move(stream));
+	}
+
+	/* Remove elements in streamConfigs whose streams will not be used.*/
+	streamConfigs.erase(
+		std::remove_if(streamConfigs.begin(), streamConfigs.end(),
+			       [](const auto &cfg) {
+				       return !cfg.config.pixelFormat.isValid();
+			       }),
+		streamConfigs.end());
+	return true;
+}
+
 } /* namespace */

 MappedCamera3Buffer::MappedCamera3Buffer(const buffer_handle_t camera3buffer,
@@ -1634,6 +1760,23 @@  int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)

 	sortCamera3StreamConfigs(streamConfigs, jpegStream);

+	std::vector<std::pair<StreamConfiguration, CameraConfiguration::Status>>
+		tryConfigs(streamConfigs.size());
+	for (size_t i = 0; i < streamConfigs.size(); ++i) {
+		LOG(HAL, Debug) << "Camera3StreamConfig #" << i << ": "
+				<< streamConfigs[i].toString();
+		tryConfigs[i].first = streamConfigs[i].config;
+		tryConfigs[i].second = CameraConfiguration::Valid;
+	}
+	if (!config_->tryValidate(tryConfigs)) {
+		LOG(HAL, Error) << "Camera configuration invalid";
+		return -EINVAL;
+	}
+	if (!mapConfig(streamConfigs, tryConfigs)) {
+		LOG(HAL, Error) << "Failed finding a stream mapping";
+		return -EINVAL;
+	}
+
 	std::vector<PostProcessorType> postProcessorTypes;
 	for (const auto &streamConfig : streamConfigs) {
 		config_->addConfiguration(streamConfig.config);