@@ -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);
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