From patchwork Thu Jun 20 21:36:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joel Selvaraj X-Patchwork-Id: 20358 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 1D4F2BD87C for ; Thu, 20 Jun 2024 21:46:16 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id CF330654A8; Thu, 20 Jun 2024 23:46:13 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="BbE1t8Ex"; dkim-atps=neutral Received: from mail-oi1-x22f.google.com (mail-oi1-x22f.google.com [IPv6:2607:f8b0:4864:20::22f]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2231C6548A for ; Thu, 20 Jun 2024 23:36:22 +0200 (CEST) Received: by mail-oi1-x22f.google.com with SMTP id 5614622812f47-3d1b5f32065so62764b6e.2 for ; Thu, 20 Jun 2024 14:36:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718919380; x=1719524180; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Hx3Yckl4F+rvU8xgCBznDKT1c44AyOLR3Mo9QHxDLVI=; b=BbE1t8Exppgw30f4bMjqTxjsAdiPnjauaQ6H5OYcKo8SP5M0zbNjZ3viQ0U9Xb5fB7 DZnnyO98k/6GOvczagSnt/6QF6fJVYHnnP7pciXBU9poNHhLEqVxzCl3en7paBu34phR cGl5LmkPC8r50BTAYYwMpAJ/Xm/wG5lB+hSX0klagQWOuUTn8znEaHXtEdYTHZHxj3VR H2LKT5NejMQXeuqxXzH/Mn8jvs6OMr37SHwJAjwfu3MOs5Yxg9igvEzZhqkA4J4xwYub KL99Cpq+4F/0Oh4i/uLgcuIYzuy4QQviTAYtlvJKAwp2ggyGvY9VoQ9ERJUYYn1L//Zj BCLg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718919380; x=1719524180; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Hx3Yckl4F+rvU8xgCBznDKT1c44AyOLR3Mo9QHxDLVI=; b=Vw6WdwH/dfSTH2RMqmB5SlSvwatYPE5aTNQ3IIF1Xln02zjTUUfk4SlKQiddHfuWbb 89QasDGUF4mZiUqrd+gXydIc2lQ4F2PEpiugbA8RMNKyVJ48ny7no5qiR0slN3XoXrqF qysSRtg/2i+OMASVEmjh/bP1BhtgWE8yZrFPnsp8acGkxHckHMDnYilt5yNT21gAwZpA /paEXeq9hIxBqspmYNW/s7LKTjzeZ8c1iaObmVGOKuaoRZAR4IpKwWdq+ffDit05THAr rENPRHkF1JnqPgQAWX1VVqoVOMFRRn6kfNXkR2t+dSbPmJdhCHcy4m0j9NAPOj3hmgC5 dUuw== X-Gm-Message-State: AOJu0YyLW+tLfjn4aw3HPeG3kAhEkCjXCKvOy7h5zoYxtoyVmOyCBJL3 86an+vf9AN9kPXht7IV1iin8Bqc8vikiDHdiRuuEklcQz+zC/yAwg/Dxzjx4 X-Google-Smtp-Source: AGHT+IFtjWGzGXqSKa/kFK3hmpFX8lMcw0FkoclZr0NPpLnDoxeNUHkUFnfkocPQhhIWMqqoHUNtjg== X-Received: by 2002:a05:6830:3207:b0:6fa:106b:8d9b with SMTP id 46e09a7af769-7007079cdf6mr6998438a34.0.1718919380031; Thu, 20 Jun 2024 14:36:20 -0700 (PDT) Received: from localhost.localdomain ([67.6.32.220]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7009c65d116sm60530a34.57.2024.06.20.14.36.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 20 Jun 2024 14:36:19 -0700 (PDT) From: Joel Selvaraj To: libcamera-devel@lists.libcamera.org Cc: Joel Selvaraj Subject: [PATCH 1/2] qcam: rotate the viewfinder output as per camera properties Date: Thu, 20 Jun 2024 16:36:06 -0500 Message-ID: <20240620213607.32583-2-joelselvaraj.oss@gmail.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240620213607.32583-1-joelselvaraj.oss@gmail.com> References: <20240620213607.32583-1-joelselvaraj.oss@gmail.com> MIME-Version: 1.0 X-Mailman-Approved-At: Thu, 20 Jun 2024 23:46:10 +0200 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" Devicetrees may specify the rotation at which the camera is mounted in the hardware. If available, this gets populated in camera properties. Rotate the viewfinder output accordingly in qcam qt and opengl renderers. Signed-off-by: Joel Selvaraj --- include/libcamera/orientation.h | 2 ++ src/apps/qcam/main_window.cpp | 9 ++++++- src/apps/qcam/viewfinder.h | 4 ++- src/apps/qcam/viewfinder_gl.cpp | 46 ++++++++++++++++++++++++++++++--- src/apps/qcam/viewfinder_gl.h | 4 ++- src/apps/qcam/viewfinder_qt.cpp | 18 +++++++++++-- src/apps/qcam/viewfinder_qt.h | 5 +++- src/libcamera/orientation.cpp | 34 ++++++++++++++++++++++++ 8 files changed, 113 insertions(+), 9 deletions(-) diff --git a/include/libcamera/orientation.h b/include/libcamera/orientation.h index a3b40e63..e32f5eb8 100644 --- a/include/libcamera/orientation.h +++ b/include/libcamera/orientation.h @@ -25,6 +25,8 @@ enum class Orientation { Orientation orientationFromRotation(int angle, bool *success = nullptr); +int rotationFromOrientation(const Orientation &orientation, bool *success = nullptr); + std::ostream &operator<<(std::ostream &out, const Orientation &orientation); } /* namespace libcamera */ diff --git a/src/apps/qcam/main_window.cpp b/src/apps/qcam/main_window.cpp index d515beed..18c94cf3 100644 --- a/src/apps/qcam/main_window.cpp +++ b/src/apps/qcam/main_window.cpp @@ -363,6 +363,7 @@ void MainWindow::toggleCapture(bool start) int MainWindow::startCapture() { std::vector roles = StreamKeyValueParser::roles(options_[OptStream]); + Orientation orientation = Orientation::Rotate0; int ret; /* Verify roles are supported. */ @@ -392,6 +393,12 @@ int MainWindow::startCapture() return -EINVAL; } + /* Get orientation provided by camera kernel driver */ + const ControlList &properties = camera_->properties(); + const auto &rotation = properties.get(properties::Rotation); + if (rotation) + orientation = orientationFromRotation(*rotation); + StreamConfiguration &vfConfig = config_->at(0); /* Use a format supported by the viewfinder if available. */ @@ -444,7 +451,7 @@ int MainWindow::startCapture() ret = viewfinder_->setFormat(vfConfig.pixelFormat, QSize(vfConfig.size.width, vfConfig.size.height), vfConfig.colorSpace.value_or(ColorSpace::Sycc), - vfConfig.stride); + vfConfig.stride, orientation); if (ret < 0) { qInfo() << "Failed to set viewfinder format"; return ret; diff --git a/src/apps/qcam/viewfinder.h b/src/apps/qcam/viewfinder.h index 914f88ec..f17cc4a1 100644 --- a/src/apps/qcam/viewfinder.h +++ b/src/apps/qcam/viewfinder.h @@ -14,6 +14,7 @@ #include #include #include +#include class Image; @@ -26,7 +27,8 @@ public: virtual int setFormat(const libcamera::PixelFormat &format, const QSize &size, const libcamera::ColorSpace &colorSpace, - unsigned int stride) = 0; + unsigned int stride, + const libcamera::Orientation &orientation) = 0; virtual void render(libcamera::FrameBuffer *buffer, Image *image) = 0; virtual void stop() = 0; diff --git a/src/apps/qcam/viewfinder_gl.cpp b/src/apps/qcam/viewfinder_gl.cpp index 9d2a6960..c4b10e1e 100644 --- a/src/apps/qcam/viewfinder_gl.cpp +++ b/src/apps/qcam/viewfinder_gl.cpp @@ -77,7 +77,7 @@ const QList &ViewFinderGL::nativeFormats() const int ViewFinderGL::setFormat(const libcamera::PixelFormat &format, const QSize &size, const libcamera::ColorSpace &colorSpace, - unsigned int stride) + unsigned int stride, const libcamera::Orientation &orientation) { if (format != format_ || colorSpace != colorSpace_) { /* @@ -101,6 +101,7 @@ int ViewFinderGL::setFormat(const libcamera::PixelFormat &format, const QSize &s size_ = size; stride_ = stride; + orientation_ = orientation; updateGeometry(); return 0; @@ -511,7 +512,7 @@ void ViewFinderGL::initializeGL() glEnable(GL_TEXTURE_2D); glDisable(GL_DEPTH_TEST); - static const GLfloat coordinates[2][4][2]{ + GLfloat coordinates[2][4][2]{ { /* Vertex coordinates */ { -1.0f, -1.0f }, @@ -528,6 +529,41 @@ void ViewFinderGL::initializeGL() }, }; + switch (orientation_) { + case libcamera::Orientation::Rotate90: + coordinates[0][0][0] = -1.0f; + coordinates[0][0][1] = +1.0f; + coordinates[0][1][0] = +1.0f; + coordinates[0][1][1] = +1.0f; + coordinates[0][2][0] = +1.0f; + coordinates[0][2][1] = -1.0f; + coordinates[0][3][0] = -1.0f; + coordinates[0][3][1] = -1.0f; + break; + case libcamera::Orientation::Rotate180: + coordinates[0][0][0] = +1.0f; + coordinates[0][0][1] = +1.0f; + coordinates[0][1][0] = +1.0f; + coordinates[0][1][1] = -1.0f; + coordinates[0][2][0] = -1.0f; + coordinates[0][2][1] = -1.0f; + coordinates[0][3][0] = -1.0f; + coordinates[0][3][1] = +1.0f; + break; + case libcamera::Orientation::Rotate270: + coordinates[0][0][0] = +1.0f; + coordinates[0][0][1] = -1.0f; + coordinates[0][1][0] = -1.0f; + coordinates[0][1][1] = -1.0f; + coordinates[0][2][0] = -1.0f; + coordinates[0][2][1] = +1.0f; + coordinates[0][3][0] = +1.0f; + coordinates[0][3][1] = +1.0f; + break; + default: + break; + } + vertexBuffer_.create(); vertexBuffer_.bind(); vertexBuffer_.allocate(coordinates, sizeof(coordinates)); @@ -831,5 +867,9 @@ void ViewFinderGL::resizeGL(int w, int h) QSize ViewFinderGL::sizeHint() const { - return size_.isValid() ? size_ : QSize(640, 480); + if (orientation_ == libcamera::Orientation::Rotate90 || + orientation_ == libcamera::Orientation::Rotate270) + return size_.isValid() ? size_.transposed() : QSize(480, 640); + else + return size_.isValid() ? size_ : QSize(640, 480); } diff --git a/src/apps/qcam/viewfinder_gl.h b/src/apps/qcam/viewfinder_gl.h index 23744b41..1fc0f827 100644 --- a/src/apps/qcam/viewfinder_gl.h +++ b/src/apps/qcam/viewfinder_gl.h @@ -39,7 +39,8 @@ public: int setFormat(const libcamera::PixelFormat &format, const QSize &size, const libcamera::ColorSpace &colorSpace, - unsigned int stride) override; + unsigned int stride, + const libcamera::Orientation &orientation) override; void render(libcamera::FrameBuffer *buffer, Image *image) override; void stop() override; @@ -68,6 +69,7 @@ private: libcamera::FrameBuffer *buffer_; libcamera::PixelFormat format_; libcamera::ColorSpace colorSpace_; + libcamera::Orientation orientation_; QSize size_; unsigned int stride_; Image *image_; diff --git a/src/apps/qcam/viewfinder_qt.cpp b/src/apps/qcam/viewfinder_qt.cpp index 4821c27d..583a74f7 100644 --- a/src/apps/qcam/viewfinder_qt.cpp +++ b/src/apps/qcam/viewfinder_qt.cpp @@ -57,7 +57,7 @@ const QList &ViewFinderQt::nativeFormats() const int ViewFinderQt::setFormat(const libcamera::PixelFormat &format, const QSize &size, [[maybe_unused]] const libcamera::ColorSpace &colorSpace, - unsigned int stride) + unsigned int stride, const libcamera::Orientation &orientation) { image_ = QImage(); @@ -80,6 +80,15 @@ int ViewFinderQt::setFormat(const libcamera::PixelFormat &format, const QSize &s format_ = format; size_ = size; + orientation_ = orientation; + + bool success; + int angle = libcamera::rotationFromOrientation(orientation, &success); + if (!success) { + qWarning() << "Unsupported orientation"; + return -EINVAL; + } + transform_ = QTransform().rotate(angle); updateGeometry(); return 0; @@ -148,6 +157,7 @@ void ViewFinderQt::paintEvent(QPaintEvent *) /* If we have an image, draw it. */ if (!image_.isNull()) { + image_ = image_.transformed(transform_); painter.drawImage(rect(), image_, image_.rect()); return; } @@ -179,5 +189,9 @@ void ViewFinderQt::paintEvent(QPaintEvent *) QSize ViewFinderQt::sizeHint() const { - return size_.isValid() ? size_ : QSize(640, 480); + if (orientation_ == libcamera::Orientation::Rotate90 || + orientation_ == libcamera::Orientation::Rotate270) + return size_.isValid() ? size_.transposed() : QSize(480, 640); + else + return size_.isValid() ? size_ : QSize(640, 480); } diff --git a/src/apps/qcam/viewfinder_qt.h b/src/apps/qcam/viewfinder_qt.h index 4f4b9f11..309b39e5 100644 --- a/src/apps/qcam/viewfinder_qt.h +++ b/src/apps/qcam/viewfinder_qt.h @@ -33,7 +33,8 @@ public: int setFormat(const libcamera::PixelFormat &format, const QSize &size, const libcamera::ColorSpace &colorSpace, - unsigned int stride) override; + unsigned int stride, + const libcamera::Orientation &orientation) override; void render(libcamera::FrameBuffer *buffer, Image *image) override; void stop() override; @@ -51,6 +52,8 @@ private: libcamera::PixelFormat format_; QSize size_; + QTransform transform_; + libcamera::Orientation orientation_; /* Camera stopped icon */ QSize vfSize_; diff --git a/src/libcamera/orientation.cpp b/src/libcamera/orientation.cpp index 47fd6a32..7afb37a8 100644 --- a/src/libcamera/orientation.cpp +++ b/src/libcamera/orientation.cpp @@ -92,6 +92,40 @@ Orientation orientationFromRotation(int angle, bool *success) return Orientation::Rotate0; } +/** + * \brief Return the rotation angle for a given orientation + * \param[in] orientation The orientation to convert to a rotation angle + * \param[out] success Set to `true` if the given orientation is valid, + * otherwise `false` + * \return The rotation angle corresponding to the given orientation + * if \a success was set to `true`, otherwise 0. + */ +int rotationFromOrientation(const Orientation &orientation, bool *success) +{ + if (success != nullptr) + *success = true; + + switch (orientation) { + case Orientation::Rotate0: + case Orientation::Rotate0Mirror: + return 0; + case Orientation::Rotate90: + case Orientation::Rotate90Mirror: + return 90; + case Orientation::Rotate180: + case Orientation::Rotate180Mirror: + return 180; + case Orientation::Rotate270: + case Orientation::Rotate270Mirror: + return 270; + } + + if (success != nullptr) + *success = false; + + return 0; +} + /** * \brief Prints human-friendly names for Orientation items * \param[in] out The output stream From patchwork Thu Jun 20 21:36:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joel Selvaraj X-Patchwork-Id: 20359 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 7F2AFC3294 for ; Thu, 20 Jun 2024 21:46:17 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D2764654A9; Thu, 20 Jun 2024 23:46:14 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="drQbbvM2"; dkim-atps=neutral Received: from mail-ot1-x330.google.com (mail-ot1-x330.google.com [IPv6:2607:f8b0:4864:20::330]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E41B9654A3 for ; Thu, 20 Jun 2024 23:36:23 +0200 (CEST) Received: by mail-ot1-x330.google.com with SMTP id 46e09a7af769-7009a3976ebso14693a34.1 for ; Thu, 20 Jun 2024 14:36:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718919381; x=1719524181; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=wzHF0XV8hR+AE00WCp7mRWTjwhN1sMx3rrREb4N+3kk=; b=drQbbvM2/MxHZWsWLBMUYGzTbhd+HzkzWL0A5pqCAqU2Cy2T4KJUGRiDCrYzyPUQyd SpqReYoeBOQ9+63kXzO9oFDJ3pStozPxHanApS7O9GDBoPfCZxFxUgDdecVeg71I50JO 0sztUz9Zea/sWpiSG+Lr0lok1s+zbeYgN2oz295X4ljCo2If9v5VPcV3GLsKLaEKBPnB Nv76r0X/3n+iWUeZV/EfpG9WXG8Xh2FRzEblynpvMyyzyF8+IuENk4b2b1TVPNbewCpg eX8Eaiazd/mem21zIUtndAXZwJmen40nzIz3pstL+mlp2xLotULgAk+M+UKQWaqtJkZ1 uiNQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718919381; x=1719524181; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=wzHF0XV8hR+AE00WCp7mRWTjwhN1sMx3rrREb4N+3kk=; b=BwAMIPkWoOaU0KDngL2z2mcwvkOPA7lCmqRjx9mfODSiNk/ClZq705VHN4T0u50c+S Ilq8pRSN6DHSyz1+CsaEGqZA07AMnpEuQMeTFwKcxTnYiYjwOorYOh/OnTFvbDmCGYbO BtY++TU+vqypr8o23Cuc70FNrNLALv2fY5FROiddnx9QmgM2riZ5IIZB6ytN3NkloAbd kM4lv02+OIh4crjL5CX0gvEcCa9ur6GPx+2MB3mLrbivRyb0JW3yqIgqNL73BGShnIM6 3qD4FtOPPlW8fDINLSc1JLDBexf206gzk1Z4taXmEpgdiGL3x42UFSnB57jDgEMc/MNZ I8kw== X-Gm-Message-State: AOJu0YysDcSzpxOsIwG74qDu0q58i0dRPmi4Ho3l4pCK01rn9iDUggcC 40WgzRooTeeIdtSkkEowmFDIV2FRvm21R95N1aRH/V5s3JAoNLmXIGEdIv1c X-Google-Smtp-Source: AGHT+IEpBkP3gTS0/f4ukcwUpMq5NiCXQqYDriqxfLNfkO6A4NsrGabjRyQD8E2kDxMzDiBKOgxqYQ== X-Received: by 2002:a05:6830:350e:b0:6f9:624c:b58e with SMTP id 46e09a7af769-7007568d576mr7281759a34.2.1718919381531; Thu, 20 Jun 2024 14:36:21 -0700 (PDT) Received: from localhost.localdomain ([67.6.32.220]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7009c65d116sm60530a34.57.2024.06.20.14.36.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 20 Jun 2024 14:36:20 -0700 (PDT) From: Joel Selvaraj To: libcamera-devel@lists.libcamera.org Cc: Joel Selvaraj Subject: [PATCH 2/2] qcam: introduce a command line argument to rotate the viewfinder output Date: Thu, 20 Jun 2024 16:36:07 -0500 Message-ID: <20240620213607.32583-3-joelselvaraj.oss@gmail.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240620213607.32583-1-joelselvaraj.oss@gmail.com> References: <20240620213607.32583-1-joelselvaraj.oss@gmail.com> MIME-Version: 1.0 X-Mailman-Approved-At: Thu, 20 Jun 2024 23:46:10 +0200 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" Sometimes devicetrees may not specify the rotation or incorrectly specify it. Introduce a command line argument to quickly test different rotations. This also helps in easily identifying the rotation at which the camera is mounted if kernel developer doesn't already know it. Signed-off-by: Joel Selvaraj --- src/apps/qcam/main.cpp | 3 +++ src/apps/qcam/main_window.cpp | 19 +++++++++++++++++++ src/apps/qcam/main_window.h | 1 + 3 files changed, 23 insertions(+) diff --git a/src/apps/qcam/main.cpp b/src/apps/qcam/main.cpp index 9846fba5..9100c69d 100644 --- a/src/apps/qcam/main.cpp +++ b/src/apps/qcam/main.cpp @@ -37,6 +37,9 @@ OptionsParser::Options parseOptions(int argc, char *argv[]) ArgumentRequired, "camera"); parser.addOption(OptHelp, OptionNone, "Display this help message", "help"); + parser.addOption(OptOrientation, OptionString, + "Desired image orientation (rot0, rot90, rot180, rot270)", + "orientation", ArgumentRequired, "orientation"); parser.addOption(OptRenderer, OptionString, "Choose the renderer type {qt,gles} (default: qt)", "renderer", ArgumentRequired, "renderer"); diff --git a/src/apps/qcam/main_window.cpp b/src/apps/qcam/main_window.cpp index 18c94cf3..aa4a0fa0 100644 --- a/src/apps/qcam/main_window.cpp +++ b/src/apps/qcam/main_window.cpp @@ -399,6 +399,25 @@ int MainWindow::startCapture() if (rotation) orientation = orientationFromRotation(*rotation); + /* Override if user specifies orientation in command line argument */ + if (options_.isSet(OptOrientation)) { + std::string orientOpt = options_[OptOrientation].toString(); + static const std::map possible_orientations{ + { "rot0", Orientation::Rotate0 }, + { "rot90", Orientation::Rotate90 }, + { "rot180", Orientation::Rotate180 }, + { "rot270", Orientation::Rotate270 }, + }; + + auto requested_orientation = possible_orientations.find(orientOpt); + if (requested_orientation == possible_orientations.end()) { + std::cerr << "Unsupported orientation " << orientOpt << std::endl; + return -EINVAL; + } + + orientation = requested_orientation->second; + } + StreamConfiguration &vfConfig = config_->at(0); /* Use a format supported by the viewfinder if available. */ diff --git a/src/apps/qcam/main_window.h b/src/apps/qcam/main_window.h index 4cead734..6dbcd88d 100644 --- a/src/apps/qcam/main_window.h +++ b/src/apps/qcam/main_window.h @@ -40,6 +40,7 @@ class HotplugEvent; enum { OptCamera = 'c', OptHelp = 'h', + OptOrientation = 'o', OptRenderer = 'r', OptStream = 's', OptVerbose = 'v',