From patchwork Thu Feb 4 10:05:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hirokazu Honda X-Patchwork-Id: 11144 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 5B8F1BD162 for ; Thu, 4 Feb 2021 10:06:04 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 2B11861435; Thu, 4 Feb 2021 11:06:04 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="HhMs6b7F"; dkim-atps=neutral Received: from mail-pj1-x1031.google.com (mail-pj1-x1031.google.com [IPv6:2607:f8b0:4864:20::1031]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 549DD61402 for ; Thu, 4 Feb 2021 11:06:02 +0100 (CET) Received: by mail-pj1-x1031.google.com with SMTP id q72so1419428pjq.2 for ; Thu, 04 Feb 2021 02:06:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=4piughn7EJr6AAA84UOv5h4/uYmAf0s9228/+iPEiJg=; b=HhMs6b7FtEro1fVhmic20BtTV+zER88RXUl0EDj7sjtAQ3IMR8qKcIIvjaWPsM+iX/ 3/DQ9thzd1iOn33T7WR52JKAqgW6/soj87kuAN4y85BTarpMZUDPnmNYf117+32PYQ26 Da6FSfPXtMNzvOY79WnlYtwqi4ysninyjD6bc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=4piughn7EJr6AAA84UOv5h4/uYmAf0s9228/+iPEiJg=; b=XpWCamwuFVn4UmjQVTEO5GJ7tBL7fucOJjo3AXC+ppR9EFbVJZLLOThur9wujpLp5T 5lsfmQt4k4SbJajGeLht+EUae1xrb8o3/BvBj0NJKJMQCk7+i72YLbOzYBjkvf7hcchS 6oKZ4Q/KD3khIYxS/5176naRBfuq5CP/T/heX2tXN11vWaP5y16t8nVgA5eeQfmhFgXa 6NTQCYPSYCMNww4FbOTZ6/+pYkg78NZNVzYyUUN4l4h7Wdwiy2sBVsgtKhc905Db18nG bPDWEiBMMSrtcfnCQpY7itS7J7/5DKu6790yrO2hC11ZCH+zaevOa5mKFTlXz0hqObAW UgZA== X-Gm-Message-State: AOAM5329Nrf7EIQOajP1T5DdcM7MnJyJbRi/iSWuk9WYhm5ATCbLpN4o a96rb0+EZRmy0L7wakWSn3JtRfZlY3D3fauy X-Google-Smtp-Source: ABdhPJyD4GEcoRG1ddnRGo7ErQKScmOxv9J5+THseF6PKm3Y0cfaPcPexudId9X+Udf1vBN26DtZeg== X-Received: by 2002:a17:902:6b43:b029:df:fb48:aece with SMTP id g3-20020a1709026b43b02900dffb48aecemr7483343plt.59.1612433160729; Thu, 04 Feb 2021 02:06:00 -0800 (PST) Received: from hiroh.c.googlers.com.com (128.141.236.35.bc.googleusercontent.com. [35.236.141.128]) by smtp.gmail.com with ESMTPSA id j9sm5808418pgb.47.2021.02.04.02.05.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Feb 2021 02:05:59 -0800 (PST) From: Hirokazu Honda To: libcamera-devel@lists.libcamera.org Date: Thu, 4 Feb 2021 10:05:41 +0000 Message-Id: <20210204100541.657503-7-hiroh@chromium.org> X-Mailer: git-send-email 2.30.0.365.g02bc693789-goog In-Reply-To: <20210204100541.657503-1-hiroh@chromium.org> References: <20210204100541.657503-1-hiroh@chromium.org> MIME-Version: 1.0 Subject: [libcamera-devel] [RFC PATCH 6/6] android: camera_device: Support stream mapping X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: hanlinchen@chromium.org Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" 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 --- src/android/camera_device.cpp | 143 ++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) -- 2.30.0.365.g02bc693789-goog 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 &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 &streamConfigs, + const std::vector> &tryConfigs) +{ + const StreamConfiguration kInvalidStreamConfiguration{}; + assert(!kInvalidStreamConfiguration.pixelFormat.isValid()); + std::vector dstStreams; + for (size_t i = 0; i < tryConfigs.size(); i++) { + LOG(HAL, Debug) << "StreamConfiguration #" << i << ": " + << tryConfigs[i].first.toString() + << ", tryValidate() result =" + << static_cast(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(type) < static_cast(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> + 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 postProcessorTypes; for (const auto &streamConfig : streamConfigs) { config_->addConfiguration(streamConfig.config);