From patchwork Mon Sep 7 16:44:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 9512 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 01E98BDB1C for ; Mon, 7 Sep 2020 16:44:59 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id CEE8362BF9; Mon, 7 Sep 2020 18:44:57 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="Nv6Y8ohS"; dkim-atps=neutral Received: from mail-wr1-x435.google.com (mail-wr1-x435.google.com [IPv6:2a00:1450:4864:20::435]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id AF2AA60599 for ; Mon, 7 Sep 2020 18:44:56 +0200 (CEST) Received: by mail-wr1-x435.google.com with SMTP id e16so16443997wrm.2 for ; Mon, 07 Sep 2020 09:44:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=t8Hq0wZqqzzJWcIK/J0NH0XRrmlQ5FJTq1ubok6iBi8=; b=Nv6Y8ohS0Otx6TI72kJpd0T6IQu/un9V+i6OagPL6xTYsU84VZucDvmHNt7QFej9Gt TXT5XDt70V4Zy32B2ZYZqJoLmHcwOAx5Qt6WP56RPaD6g/GGC/nKUqieTITC1q5zHZvB IfHT6mvU1LbirwcxHQZjYXi9719cRHWg0IqgCxZbBikcplOZ6C9fUNqVlZAjwyI88eH5 7IsDKhpDTHvlQoSN7mRNvk/rXFffAvZE6sEqbE9yNXCcdxK5t9Cx2gxqZxhRZzlWwKcJ KQHqc7ri26N7ENWGHP/LE3Z9mLme+mTOLy3k7m3R5dvs2T3FICceUmu9eNx4ig3keDZn WLOQ== 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=t8Hq0wZqqzzJWcIK/J0NH0XRrmlQ5FJTq1ubok6iBi8=; b=Lz1IngCW25pB+Y4yqMX+ii61Zkasa2YuYaHSrtRhpKPYZJ/K6mxOd/P53RR6g7c0QE myAXhW5UiK54Jmodd2tNJIocYDYogv6KJ0ktEh+0uxvAnoDyvndYfB8lxURl9hYL18uO svhJT6EceSVoNX6omOTQX51ppZwD5u8os45N0+M2lqfi3/X8UvfvjFNkAc7Wm7MuXIq5 kJgRkMUpyRuUd/+luNoaYWOelWUXLqp7buiLemj5WFUDZKPlMukVkMNvfMHFtfBcFawD PbArFc9zmKYEnfwjP+gE009r0Lspw5hIVMKtj371/hzsR2QAJZt04qZ01Odr9sebGLAX z1ng== X-Gm-Message-State: AOAM5338tOyA0twgFHPlPbkan2luD2epxivdFQOtc+oZTpS0StiIr4qo 5ZPp3xQRZa8nYO9PbhgV03hM5ZDopsMN5g== X-Google-Smtp-Source: ABdhPJwl3dl10UYpf0EdZkCeawPpoohd6ozh5b4rm75vh+zjfZ4NtcNBLbWswRQI/GyH8t/uDrzq4Q== X-Received: by 2002:adf:f106:: with SMTP id r6mr22783471wro.106.1599497096183; Mon, 07 Sep 2020 09:44:56 -0700 (PDT) Received: from pi4-davidp.lan (plowpeople3.plus.com. [80.229.223.72]) by smtp.gmail.com with ESMTPSA id v3sm27707033wmh.6.2020.09.07.09.44.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Sep 2020 09:44:55 -0700 (PDT) From: David Plowman To: libcamera-devel@lists.libcamera.org Date: Mon, 7 Sep 2020 17:44:47 +0100 Message-Id: <20200907164450.13082-2-david.plowman@raspberrypi.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200907164450.13082-1-david.plowman@raspberrypi.com> References: <20200907164450.13082-1-david.plowman@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [RFC PATCH 1/4] libcamera: Add SensorOutputSize property 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The SensorOutputSize camera property changes with the selected camera mode, so it must be updated when a new mode is chosen. --- src/libcamera/camera_sensor.cpp | 3 +++ src/libcamera/pipeline/raspberrypi/raspberrypi.cpp | 2 ++ src/libcamera/property_ids.yaml | 6 ++++++ 3 files changed, 11 insertions(+) diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp index d2679a4..b1c218e 100644 --- a/src/libcamera/camera_sensor.cpp +++ b/src/libcamera/camera_sensor.cpp @@ -249,6 +249,9 @@ int CameraSensor::init() propertyValue = 0; properties_.set(properties::Rotation, propertyValue); + /* The SensorOutputSize is known once the camera mode is chosen. */ + properties_.set(properties::SensorOutputSize, Size(0, 0)); + /* Enumerate, sort and cache media bus codes and sizes. */ formats_ = subdev_->formats(pad_); if (formats_.empty()) { diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp index ce43af3..7f151cb 100644 --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp @@ -646,6 +646,8 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config) LOG(RPI, Info) << "Sensor: " << camera->id() << " - Selected mode: " << sensorFormat.toString(); + data->properties_.set(properties::SensorOutputSize, sensorFormat.size); + /* * This format may be reset on start() if the bayer order has changed * because of flips in the sensor. diff --git a/src/libcamera/property_ids.yaml b/src/libcamera/property_ids.yaml index 74ad019..ed1df19 100644 --- a/src/libcamera/property_ids.yaml +++ b/src/libcamera/property_ids.yaml @@ -640,4 +640,10 @@ controls: \todo Rename this property to ActiveAreas once we will have property categories (i.e. Properties::PixelArray::ActiveAreas) + - SensorOutputSize: + type: Size + description: | + The size, in pixels, of the image being output by the sensor in this + camera mode. + ... From patchwork Mon Sep 7 16:44:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 9513 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 65100BDB1C for ; Mon, 7 Sep 2020 16:45:00 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 2F1E762B90; Mon, 7 Sep 2020 18:45:00 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="SdNYWQw/"; dkim-atps=neutral Received: from mail-wr1-x441.google.com (mail-wr1-x441.google.com [IPv6:2a00:1450:4864:20::441]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6607A60372 for ; Mon, 7 Sep 2020 18:44:57 +0200 (CEST) Received: by mail-wr1-x441.google.com with SMTP id z1so16479083wrt.3 for ; Mon, 07 Sep 2020 09:44:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=cS3PuvAp3Llsuq3WC0FESFzYKEwZc+lcHlaZ68hADTM=; b=SdNYWQw/n80vbBEPOqU/tT6CVH21UZqRmWGJd4Nxddar2NLYEnboa9itKQ597+S5pT 6KPcPjmfh9oKJYfD6oFlgs9ZcqcU+5dzwY8cZHIllt5qocs8EIbsFC5wg/KpA3B4aL2Y Nv5q72IQ/iyakjexhf1foHWSuVyCbO3qOW9alI+Z1RcN0qeXXsZNnmLsTH1UnYvkszAV ji1UVNbC+mCoZZodkk1IXP3ImBBJK/1QL2Fabgsqo6FC3Js13GBFewN+YLXLn2QQkMkd nTpx1+mDdDnrNLoOjXu3OikwJOPjz/EX0eABA/TxotgyrITlQgmLUsAj7GxxP+Ozd1aN hV4Q== 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=cS3PuvAp3Llsuq3WC0FESFzYKEwZc+lcHlaZ68hADTM=; b=jwzbGcEB6KWt/5whcpniHkSgVR4GAjNPlQ/kXAJCD2D0+OwPG38xxiYRRUpsOvnPFe mKaQAC3uEn7kq9Kz9wVIqeA7LAbffDRhSOrCRJXnObd4AP61VgTdXRj4ATbymZ3IrraP QbjIEaY/T09/bS8l5Qoy4L0m5VUuQ+VlihxPi8gdVumEfwXOry25K3gNhbGPWGGpGAP2 xuVrHHT2pilpObdQpHVr25pffInnx/CD0DX0liBi7RFkeuNgp0tjOISQ+6wlrNpTd+GD NuXVywR6RogFXbASX2d3YnseL1ceLLDNp1c+0B8FDOk6LLV517+DxH1qHk89p/W5IwGJ gQbw== X-Gm-Message-State: AOAM533cv5S8w58ynLtjagXR1NeEOOt1FhzqhNko4FeKDtZe3gcbdDbs D6y/SVedzX1bOSzA7lnovySwWiOy/I1yRw== X-Google-Smtp-Source: ABdhPJyOcbZr11BFyk3rQPmcmWE1C4AnEOPL1dgZc8CuIvXmhml1YVry5YNhmFUJZ4gTq6QhbLtkoQ== X-Received: by 2002:adf:e7ce:: with SMTP id e14mr21718783wrn.43.1599497096942; Mon, 07 Sep 2020 09:44:56 -0700 (PDT) Received: from pi4-davidp.lan (plowpeople3.plus.com. [80.229.223.72]) by smtp.gmail.com with ESMTPSA id v3sm27707033wmh.6.2020.09.07.09.44.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Sep 2020 09:44:56 -0700 (PDT) From: David Plowman To: libcamera-devel@lists.libcamera.org Date: Mon, 7 Sep 2020 17:44:48 +0100 Message-Id: <20200907164450.13082-3-david.plowman@raspberrypi.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200907164450.13082-1-david.plowman@raspberrypi.com> References: <20200907164450.13082-1-david.plowman@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [RFC PATCH 2/4] libcamera: Add SensorCrop control 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The SensorCrop control selects how much of the sensor's output image will be scaled to form the output image. It can be used to implement digital zoom. --- src/libcamera/control_ids.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libcamera/control_ids.yaml b/src/libcamera/control_ids.yaml index 3560d4a..cebaa25 100644 --- a/src/libcamera/control_ids.yaml +++ b/src/libcamera/control_ids.yaml @@ -273,4 +273,13 @@ controls: order in an array of 9 floating point values. size: [3x3] + + - SensorCrop: + type: Rectangle + description: | + Sets the portion of the full sensor image, in pixels, that will be + scaled up to form the whole of the final output image. This control + can be used to implement digital zoom. The size of the full sensor + image within which an application can crop is available from the + SensorOutputSize property. ... From patchwork Mon Sep 7 16:44:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 9514 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 C9606BDB1C for ; Mon, 7 Sep 2020 16:45:00 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 932B462BBA; Mon, 7 Sep 2020 18:45:00 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="K6SyI6rP"; dkim-atps=neutral Received: from mail-wr1-x42f.google.com (mail-wr1-x42f.google.com [IPv6:2a00:1450:4864:20::42f]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4ACE062BBA for ; Mon, 7 Sep 2020 18:44:58 +0200 (CEST) Received: by mail-wr1-x42f.google.com with SMTP id z4so16450223wrr.4 for ; Mon, 07 Sep 2020 09:44:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=O61rTSPSnTdYCOC7EfprGKw/KQFBenZCvM1enIUSkgs=; b=K6SyI6rPmy3qLPoD3QNZxE0lz4hZ9G+2KZEVYueSLA6p/j/C/a0HV7F2xnFNJyskMw SCNj+fEzbXW5vuMqEJE5Z96eSaK+uJ1aCsnaNGSB19oMCes3SxVixdOULgKUrhzjSwv2 1PVMsMFSNnBbSjZX0tBYzMbzRJgqaW/xCpKGynX+SKBjDwwouwixT6muxe5XXRJmsy25 bQBcqme9i6myDjSG8Uc5aByEAblYn/VMtvLCMRx9pRCPtMcrdproKrBmhou9X2XEAYzV j+yiqp1cBxjITqj8vXVaJESAf32ZM652ZSqqiO3HjZG9CqaAHBfXpU/DAs0/ZFPgy/wt AWiA== 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=O61rTSPSnTdYCOC7EfprGKw/KQFBenZCvM1enIUSkgs=; b=hVzskMEbDSwR8it006ZQesOxnrZ41pnSBAXghaM6JiWHWZpNfxB56Bgz4H5Pcf3Vbq Ht+KOKIl5NInlDZ4H2uq4tlpGOna5VQFwd+G+2hOsO75FTt5nAY2Q6Z13otq/T70V34h 1lsMI9ENJ22aIGus+kKjVXWVcAteYL4jrw7C/tlopZcNvOryo4O1gkuasZXgWzdFrU6D 7G77fqx6n0+svXhO3Sp6Oyr69fCilIZAclzG07Cy4rwEp4//BhzBGiEILSAm0CaYYMUO B0WrAfieqoQJ1YTR5XOqythcdXaFwsMY+iMuS44VNysIzqHDSXLY9UeIFjQO4m2uU4rL lgWg== X-Gm-Message-State: AOAM532lxz/7Oc8QGARLsRWpmRqmK5Yl4fwci3a4WvTuP9MlM0p7rXbR +moI1aDJaj3VIk1hWUfUO5o7q1KP0mWOwg== X-Google-Smtp-Source: ABdhPJwlMXoZSrwC01EFwkbxTQB2snDH41eXBppWiulz3jpr8cqLB/1ag3cPIopn9JfHKAWSK5beYQ== X-Received: by 2002:adf:ec90:: with SMTP id z16mr21613682wrn.145.1599497097680; Mon, 07 Sep 2020 09:44:57 -0700 (PDT) Received: from pi4-davidp.lan (plowpeople3.plus.com. [80.229.223.72]) by smtp.gmail.com with ESMTPSA id v3sm27707033wmh.6.2020.09.07.09.44.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Sep 2020 09:44:57 -0700 (PDT) From: David Plowman To: libcamera-devel@lists.libcamera.org Date: Mon, 7 Sep 2020 17:44:49 +0100 Message-Id: <20200907164450.13082-4-david.plowman@raspberrypi.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200907164450.13082-1-david.plowman@raspberrypi.com> References: <20200907164450.13082-1-david.plowman@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [RFC PATCH 3/4] libcamera: Add geometry helper functions 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" These functions are aimed at making it easier to calculate cropping rectangles, particularly in order to implement digital zoom. --- include/libcamera/geometry.h | 18 +++++ src/libcamera/geometry.cpp | 129 +++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) diff --git a/include/libcamera/geometry.h b/include/libcamera/geometry.h index 02fb63c..8f6a9a0 100644 --- a/include/libcamera/geometry.h +++ b/include/libcamera/geometry.h @@ -13,6 +13,8 @@ namespace libcamera { +class Rectangle; + class Size { public: @@ -93,8 +95,16 @@ public: std::max(height, expand.height) }; } + + Size aspectRatioDown(const Size &ar) const; + Size aspectRatioUp(const Size &ar) const; + Rectangle centre(const Rectangle ®ion, + int offsetX = 0, int offsetY = 0) const; }; +Size operator*(const Size &size, float f); +Size operator/(const Size &size, float f); + bool operator==(const Size &lhs, const Size &rhs); bool operator<(const Size &lhs, const Size &rhs); @@ -176,6 +186,11 @@ public: { } + constexpr explicit Rectangle(const Size &size) + : x(0), y(0), width(size.width), height(size.height) + { + } + int x; int y; unsigned int width; @@ -183,6 +198,9 @@ public: bool isNull() const { return !width && !height; } const std::string toString() const; + + Size size() const; + Rectangle clamp(const Rectangle &boundary) const; }; bool operator==(const Rectangle &lhs, const Rectangle &rhs); diff --git a/src/libcamera/geometry.cpp b/src/libcamera/geometry.cpp index b12e1a6..3e26167 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -143,6 +143,89 @@ const std::string Size::toString() const * height of this size and the \a expand size */ +/** + * \brief Clip the given size to have a given aspect ratio + * \param[in] ar The aspect ratio the result is to have + */ +Size Size::aspectRatioDown(const Size &ar) const +{ + Size result; + + uint64_t ratio1 = static_cast(width) * + static_cast(ar.height); + uint64_t ratio2 = static_cast(ar.width) * + static_cast(height); + + if (ratio1 > ratio2) + result = Size(ratio2 / ar.height, height); + else + result = Size(width, ratio1 / ar.width); + + return result; +} + +/** + * \brief Expand the given size to have a given aspect ratio + * \param[in] ar The aspect ratio the result is to have + */ +Size Size::aspectRatioUp(const Size &ar) const +{ + Size result; + + uint64_t ratio1 = static_cast(width) * + static_cast(ar.height); + uint64_t ratio2 = static_cast(ar.width) * + static_cast(height); + + if (ratio1 < ratio2) + result = Size(ratio2 / ar.height, height); + else + result = Size(width, ratio1 / ar.width); + + return result; +} + +/** + * \brief centre a rectangle of this size within another rectangular region, + * with optional offsets + * \param[in] region The rectangular region relative to which the returned + * rectangle can be position + * \param[in] offsetX the X offset of the mid-point of the returned rectangle + * relative to the mid-point of the region + * \param[in] offsetY the Y offset of the mid-point of the returned rectangle + * relative to the mid-point of the region + * + * A rectangle of this object's size is positioned within the rectangle + * given by \a region. It is positioned so that its mid-point coincides + * with the mid-point of \a region, and is then further offset by the + * values \a offsetX and \a offsetY. + * + * \return A Rectangle offset within a region + */ +Rectangle Size::centre(const Rectangle ®ion, int offsetX, int offsetY) const +{ + int x = (region.width - width) / 2 + region.x + offsetX; + int y = (region.height - height) / 2 + region.y + offsetY; + + return Rectangle(x, y, width, height); +} + +/** + * \brief Scale size up by the given factor + */ +Size operator*(const Size &size, float f) +{ + return Size(size.width * f, size.height * f); +} + +/** + * \brief Scale size down by the given factor + */ +Size operator/(const Size &size, float f) +{ + return Size(size.width / f, size.height / f); +} + /** * \brief Compare sizes for equality * \return True if the two sizes are equal, false otherwise @@ -365,6 +448,12 @@ bool operator==(const SizeRange &lhs, const SizeRange &rhs) * \param[in] height The height */ +/** + * \fn Rectangle::Rectangle(const Size &size) + * \brief Construct a Rectangle with the zero offsets and size + * \param[in] size The size + */ + /** * \var Rectangle::x * \brief The horizontal coordinate of the rectangle's top-left corner @@ -404,6 +493,46 @@ const std::string Rectangle::toString() const return ss.str(); } +/** + * \brief Return the size of this rectangle + */ +Size Rectangle::size() const +{ + return Size(width, height); +} + +/** + * \brief Clamp a rectangle so as not to exceeed another rectangle + * \param[in] boundary the limit that the returned rectangle will not exceed + * + * The rectangle is clamped so that it does not exceeed the given \a boundary. + * This process involves translating the rectangle if any of its edges + * lie beyond \a boundary, so that those edges then lie along the boundary + * instead. + * + * If either width or height are larger than \a bounary, then the returned + * rectangle is clipped to be no larger. But other than this, the + * rectangle is not clipped or reduced in size, merely translated. + * + * We note that this is not a conventional rectangle intersection function. + * + * \return A rectangle that does not extend beyond a boundary rectangle + */ +Rectangle Rectangle::clamp(const Rectangle &boundary) const +{ + Rectangle result(*this); + + result.width = std::min(result.width, boundary.width); + result.x = std::clamp(result.x, boundary.x, + boundary.x + boundary.width - result.width); + + result.height = std::min(result.height, boundary.height); + result.y = std::clamp(result.y, boundary.y, + boundary.y + boundary.height - result.height); + + return result; +} + /** * \brief Compare rectangles for equality * \return True if the two rectangles are equal, false otherwise From patchwork Mon Sep 7 16:44:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 9515 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 425DEBDB1E for ; Mon, 7 Sep 2020 16:45:01 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 026BE62C15; Mon, 7 Sep 2020 18:45:01 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="mkTU+JS4"; dkim-atps=neutral Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2D43960372 for ; Mon, 7 Sep 2020 18:44:59 +0200 (CEST) Received: by mail-wr1-x42b.google.com with SMTP id m6so16472951wrn.0 for ; Mon, 07 Sep 2020 09:44:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=cLq8fMZ6wax4QpFQ10/ZmQl82O46CeZqaT5ztQBHqlQ=; b=mkTU+JS4xNFJTI838MsBxzKXWdCYGOuAxz9oidmS03AyoIkScaUejjivABci/8AdgC DfDfw0WZexTOAF0ENYghjyA+bdpwSN6ucJxa7R/M1F5dmKufIdzLXzkzvL40s1+fT789 SjHYkHhHRr2kvpc1dHEn1spmY/NpwcRNmFUY40DwZVBmE3uI1L6COCizjBZqrADtSs9b vV2cPomwz6l08mBZ+OXRmJEvhcjOt0RnOFu8BHdpMgnY+1obihvKU0iFzg9yELJeyRxX ccB5/sIOnQlMoTHWPiNsV21A2Jf1ZOeVyQlvILeaWDn7uVnr5B+DDTHAH4QSpkE/nV7Z yRKA== 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=cLq8fMZ6wax4QpFQ10/ZmQl82O46CeZqaT5ztQBHqlQ=; b=G2xsR1wYWP0P6XtqB6HxSwWbEo58EcOim5IleXucu8nRZBeDEWVAtN5wA8OBYanF8l j9G/YE1E05tmIp+Lell1AcEOdH7SVJHCQWhLZaLERlXFo/r81ZJcB4fIZTxc1ibTpSOH 5A4oR5yvNemCIeklOoRVdIjCIJG9ctJ5U8VSaHQ1GEjquo6AqI6/iIRvuKPEzkfjmrLO vLDGo31mIbnpsNNb4VZl5zV2URH1brFjN+MA/oRQMIlDmqIytRVGuJh74Fdq9o62V4Zc +FqD5CcTWTyV+j+QTdzLJ09aW7fqMxZnn8mbHTls81MM1nScemjeLtfeez2ZTirseA+p 3Kcg== X-Gm-Message-State: AOAM532VFJzUUeHS47RsJly1NCf2IchoQukuX6LFW+mMz6eMk+f8kzdL HR9GdCH93aZmSnP7Qs3wmpuoWLWQYxRtyQ== X-Google-Smtp-Source: ABdhPJyj8EjZOEn3VqX4p1Ac7S/iEVtp+Uy2bBwKP+mb+iNWYP4OkiS+ibxmRNFaE7xyajp0IuVPKw== X-Received: by 2002:a5d:6806:: with SMTP id w6mr22489405wru.395.1599497098538; Mon, 07 Sep 2020 09:44:58 -0700 (PDT) Received: from pi4-davidp.lan (plowpeople3.plus.com. [80.229.223.72]) by smtp.gmail.com with ESMTPSA id v3sm27707033wmh.6.2020.09.07.09.44.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Sep 2020 09:44:57 -0700 (PDT) From: David Plowman To: libcamera-devel@lists.libcamera.org Date: Mon, 7 Sep 2020 17:44:50 +0100 Message-Id: <20200907164450.13082-5-david.plowman@raspberrypi.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200907164450.13082-1-david.plowman@raspberrypi.com> References: <20200907164450.13082-1-david.plowman@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [RFC PATCH 4/4] libcamera: pipeline: raspberrypi: Implementation of digital zoom 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" During configure() we make a note of the minimum crop size allowed by the ISP, and the image output size of the chosen sensor mode. Whenever a new SensorCrop request is received we check it's valid and apply it to the ISP V4L2 device. We also forward it to the IPA so that the IPA can return the values used in the image metadata. --- include/libcamera/ipa/raspberrypi.h | 1 + src/ipa/raspberrypi/raspberrypi.cpp | 7 ++++ .../pipeline/raspberrypi/raspberrypi.cpp | 39 +++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/include/libcamera/ipa/raspberrypi.h b/include/libcamera/ipa/raspberrypi.h index ca62990..361b47d 100644 --- a/include/libcamera/ipa/raspberrypi.h +++ b/include/libcamera/ipa/raspberrypi.h @@ -57,6 +57,7 @@ static const ControlInfoMap RPiControls = { { &controls::Saturation, ControlInfo(0.0f, 32.0f) }, { &controls::Sharpness, ControlInfo(0.0f, 16.0f, 1.0f) }, { &controls::ColourCorrectionMatrix, ControlInfo(-16.0f, 16.0f) }, + { &controls::SensorCrop, ControlInfo(Rectangle(0, 0, 0, 0), Rectangle(65535, 65535, 65535, 65535), Rectangle(0, 0, 0, 0)) }, }; } /* namespace libcamera */ diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp index 4557016..4a364b7 100644 --- a/src/ipa/raspberrypi/raspberrypi.cpp +++ b/src/ipa/raspberrypi/raspberrypi.cpp @@ -687,6 +687,13 @@ void IPARPi::queueRequest(const ControlList &controls) break; } + case controls::SENSOR_CROP: { + /* Just copy the information back. */ + Rectangle crop = ctrl.second.get(); + libcameraMetadata_.set(controls::SensorCrop, crop); + break; + } + default: LOG(IPARPI, Warning) << "Ctrl " << controls::controls.at(ctrl.first)->name() diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp index 7f151cb..3196a61 100644 --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp @@ -335,6 +335,11 @@ public: std::queue embeddedQueue_; std::deque requestQueue_; + /* For handling digital zoom. */ + Size ispMinSize_; + Size sensorOutputSize_; + Rectangle lastSensorCrop_; + private: void checkRequestCompleted(); void tryRunPipeline(); @@ -737,6 +742,16 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config) return ret; } + /* + * Figure out the smallest selection the ISP will allow. We also store + * the output image size, in pixels, from the sensor. These will be + * used for digital zoom. + */ + Rectangle testCrop(0, 0, 1, 1); + data->isp_[Isp::Input].dev()->setSelection(V4L2_SEL_TGT_CROP, &testCrop); + data->ispMinSize_ = testCrop.size(); + data->sensorOutputSize_ = sensorFormat.size; + /* Adjust aspect ratio by providing crops on the input image. */ Rectangle crop{ 0, 0, sensorFormat.size }; @@ -753,6 +768,8 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config) crop.y = (sensorFormat.size.height - crop.height) >> 1; data->isp_[Isp::Input].dev()->setSelection(V4L2_SEL_TGT_CROP, &crop); + data->lastSensorCrop_ = crop; + ret = data->configureIPA(); if (ret) LOG(RPI, Error) << "Failed to configure the IPA: " << ret; @@ -1545,6 +1562,28 @@ void RPiCameraData::tryRunPipeline() */ Request *request = requestQueue_.front(); + if (request->controls().contains(controls::SensorCrop)) { + Rectangle crop = request->controls().get(controls::SensorCrop); + if (crop.width && crop.height) { + /* + * The crop that we set must be: + * 1. At least as big as ispMinSize_, once that's been + * enlarged to the same aspect ratio. + * 2. With the same mid-point, if possible. + * 3. But it can't go outside the sensor area. + */ + Size minSize = ispMinSize_.aspectRatioUp(crop.size()); + Size size = crop.size().expandedTo(minSize); + crop = size.centre(crop).clamp(Rectangle(sensorOutputSize_)); + + if (crop != lastSensorCrop_) + isp_[Isp::Input].dev()->setSelection(V4L2_SEL_TGT_CROP, &crop); + lastSensorCrop_ = crop; + } + + request->controls().set(controls::SensorCrop, lastSensorCrop_); + } + /* * Process all the user controls by the IPA. Once this is complete, we * queue the ISP output buffer listed in the request to start the HW