From patchwork Thu Aug 6 06:17:06 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hirokazu Honda X-Patchwork-Id: 9245 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 58F0ABD86F for ; Thu, 6 Aug 2020 06:17:19 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 2413860740; Thu, 6 Aug 2020 08:17:19 +0200 (CEST) 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="YtXY/oDU"; dkim-atps=neutral Received: from mail-pj1-x1034.google.com (mail-pj1-x1034.google.com [IPv6:2607:f8b0:4864:20::1034]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 281446038D for ; Thu, 6 Aug 2020 08:17:18 +0200 (CEST) Received: by mail-pj1-x1034.google.com with SMTP id c6so6113895pje.1 for ; Wed, 05 Aug 2020 23:17:18 -0700 (PDT) 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=PNsObdRFmanHdtmQQrGXJSwOWh+FdhVCiYIUAYe5rRs=; b=YtXY/oDUReNqZ6CSaiT8NX3UBG4pqE27+Gkpyd0TivXC/iJ8QZMuXjVDJLyawT+44A 9fFBl3YI2Nj41jbUl1N0Qh1PH0UneuLWTB3R/Vvg1KfroDarb5RV2yxy1n1JVMQ30LvN Egs8SX2jN+2x1wYo8i+F0DW1qDrkK5y5wMCeE= 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=PNsObdRFmanHdtmQQrGXJSwOWh+FdhVCiYIUAYe5rRs=; b=kfMbxN2E5StxG/hixbacqaeUt/nxrigAPEGoL5l5inj+nNwItqHG4otgXenJ0HLP32 /cIZ295eYQnMnivut00tWv2NOGhk2sIvN17FP47m12VQl+HPgLsJhRzDxswosdEznhrc d8gJMj/jcoQ+Uw2FQI3s0BYWq6w+gIJpuoZajSyLSgYvSzjtmcMhPWxknTPh40gLZhMw yR/m9/JC238ljfwAxdVTI43cHktp7EmvDQehiZgPVpkXIQEkBSo3av5sx+9U20XTeOmO XZDABv/13fnZLMKFrIkTygea6SxJeruQCETY0iHdivUM+qKwhGq1SenbY5mnA6icMw+i ZQ7g== X-Gm-Message-State: AOAM532PY55rdM+zPa/vjhK/Ed6UZJroHU5+atFYryg4zOg/mRpyDKnv tfmnWmrG0GQZtUJF7CJVfe/Ic+YLt2A= X-Google-Smtp-Source: ABdhPJyYzQnWvY4gyXcSpsBBfKfKQ6AppiuGyMeAcJOqBxhO7s+5Z6pVzejRFyowRXvP52AXkU7ZcA== X-Received: by 2002:a17:902:ee82:: with SMTP id a2mr6206943pld.204.1596694636040; Wed, 05 Aug 2020 23:17:16 -0700 (PDT) Received: from hiroh.tok.corp.google.com ([2401:fa00:8f:2:de4a:3eff:fe7d:f78f]) by smtp.gmail.com with ESMTPSA id 21sm6388267pfa.4.2020.08.05.23.17.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 05 Aug 2020 23:17:15 -0700 (PDT) From: Hirokazu Honda To: libcamera-devel@lists.libcamera.org Date: Thu, 6 Aug 2020 15:17:06 +0900 Message-Id: <20200806061706.1025788-2-hiroh@chromium.org> X-Mailer: git-send-email 2.28.0.236.gb10cc79966-goog In-Reply-To: <20200806061706.1025788-1-hiroh@chromium.org> References: <20200806061706.1025788-1-hiroh@chromium.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 1/1] android: [WIP] Map between camera configuration and requested configuration 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" Signed-off-by: Hirokazu Honda --- src/android/camera_device.cpp | 136 ++++++++++++++++++++++++++++++---- src/android/camera_device.h | 12 ++- 2 files changed, 133 insertions(+), 15 deletions(-) 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 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& sameRatios, + const std::vector& 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 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(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 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& sameRatios, + const std::vector& 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_;