From patchwork Tue Aug 9 20:50:40 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Utkarsh Tiwari X-Patchwork-Id: 17058 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 81292BE173 for ; Tue, 9 Aug 2022 20:53:20 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 2D33463330; Tue, 9 Aug 2022 22:53:20 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1660078400; bh=yGiyvD6CNzKoNXt3g9zqrzvMZXD/w3VQgQy4aizvZzM=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=gTwQe/XHYnID/ZV7fT7Nef4XdeTnVomAgWRBcnC+X9Bs3eaAXC9+BXAgRNMdEyXc3 KOX/vLB6ZQiBht7cRccVaFFpGzxZKEQMIFHbFp67QcL+qhnYixdY2crMruSSro4sAR 61TkWp7tsSbgCWNTONHMcxi4L5DDsekHUfocEIqtywDsyTMFjVOdStjC7uxhFMcA4w fksy7fi4DSf2a9ESTxYHyrEOaN/pC+iupA5tC2PDQzJSKvXCCE6CWK+gdg8NNERhPv Odj8RlfSg4Jhifq1wmFAfhk0SYM58yV54a54lcw2oPkUeIYkB67Xtgt27EFE6qvj8i TLeUXK8BliNpg== Received: from mail-pg1-x536.google.com (mail-pg1-x536.google.com [IPv6:2607:f8b0:4864:20::536]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8FF2263326 for ; Tue, 9 Aug 2022 22:53:18 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="IU+10EBm"; dkim-atps=neutral Received: by mail-pg1-x536.google.com with SMTP id r22so10050094pgm.5 for ; Tue, 09 Aug 2022 13:53:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc; bh=Mcr64yjVCfEAXiluxTvpzmJGc/Y98mtU/N/B27cP2jA=; b=IU+10EBmKTgtfPDDrs1ecW+INRHl2FQo/JncMdpxpdMsybAIIn2GvrnsH+QM45CaJw 8C34zAnl7GOcYFhrNsb1a7izIOYA4SThF6xMVjkJy60t0kgmIgZwYzUPa4CGdKCBJ0sA WsZRnz5+4Za493e4TMbW87Y7FWhk8R+2R8qpgX1cOj+UHe42nHrolVCubrbt3JpccT6z b/S7pcaob23oXNPaB+Nw8gle3FsyKF66fumRr0cPgj4GxKcJ1x2s/Y7WmkqUIcRYfROL hogSbAUJSR8pX+Nquub0ij/PEi1dYWdeo+O6kHqB+OsSysoST4W3IGOD4pZktF8QL/pX cwSg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc; bh=Mcr64yjVCfEAXiluxTvpzmJGc/Y98mtU/N/B27cP2jA=; b=AYPqx1QCNk9famHxlCgw7ORXkcbF1BEiPy1/ludvhW3cGnZyRgN9o08InDSjL4vYvH ac1n6zL4dqMaTbWv1IQ/C9nrESh+75Th58kgA956v5vDrEmrk74Rhi5L25oQc41aWSym S0SF25RV92w+hb6754Bq7C2LpnHQ6JZqugAr/Cl382RflucFBUwjXQ5VRY4eLSQOSON8 7rdrp1mFnVy9LU5imomi6rnk0R52PvbbdLdLURDICAAw6pgu82tvo7s5ibw52DYR38Zh FJ2CZBmHCdCETuNKYooMJ20ZVAClIDjx4rfh6GKntOg3f30JqAuEC6EVrriVtJHskL8k hq2w== X-Gm-Message-State: ACgBeo3ZX3A3nYtGn7cHO60tWCTAaRfAF7s5gTT1nsc30fFVRPSLY9sR nN4RDToc1S/EXtUHfxQJ20gyaampfI0= X-Google-Smtp-Source: AA6agR41oW00X1WTf9EjnSirkTrq5QzprDsLoyRYioVEjt5P1WQ8jQ/XVaVRM0CsKi4hIxb58v7GFg== X-Received: by 2002:a63:1021:0:b0:41c:89f8:f4f4 with SMTP id f33-20020a631021000000b0041c89f8f4f4mr21058880pgl.416.1660078396830; Tue, 09 Aug 2022 13:53:16 -0700 (PDT) Received: from localhost.localdomain ([2404:bd00:3:d2bc:2358:3bcd:fb4f:cbb7]) by smtp.gmail.com with ESMTPSA id d3-20020a623603000000b0052d981e7842sm301936pfa.208.2022.08.09.13.53.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 09 Aug 2022 13:53:16 -0700 (PDT) To: libcamera-devel@lists.libcamera.org Date: Wed, 10 Aug 2022 02:20:40 +0530 Message-Id: <20220809205042.344923-7-utkarsh02t@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220809205042.344923-1-utkarsh02t@gmail.com> References: <20220809205042.344923-1-utkarsh02t@gmail.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v7 6/8] qcam: CamSelectDialog: Add capture script button 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: , X-Patchwork-Original-From: Utkarsh Tiwari via libcamera-devel From: Utkarsh Tiwari Reply-To: Utkarsh Tiwari Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Implement an Capture Script in CamSelectDialog button which would allow the user to open a Capture Script (*.yaml). This button has three states : - Open Capture Script - Loaded - Stop the execution of current capture script When being clicked in open state, present them with a QFileDialog to allow user to select a single file. When the script is loaded the button displays "Loaded", the script has not been verified yet. Verifying the script and executing it happens after user presses Ok. Introduce a queueCount_ to keep track of the requests queued. When stopping the execution of the capture script the queueCount_ is not reseted and the capture is continues as it is (i.e it is not stopped or restarted). Requests are queued with any controls the script matching the current queueCount_. Signed-off-by: Utkarsh Tiwari --- Difference: 1. override accept and reject to handle capture script paths. src/qcam/cam_select_dialog.cpp | 68 ++++++++++++++++++++++++++++++++-- src/qcam/cam_select_dialog.h | 21 ++++++++++- src/qcam/main_window.cpp | 59 ++++++++++++++++++++++++++++- src/qcam/main_window.h | 7 ++++ src/qcam/meson.build | 2 + 5 files changed, 152 insertions(+), 5 deletions(-) diff --git a/src/qcam/cam_select_dialog.cpp b/src/qcam/cam_select_dialog.cpp index f97ad6eb..f3df9970 100644 --- a/src/qcam/cam_select_dialog.cpp +++ b/src/qcam/cam_select_dialog.cpp @@ -20,8 +20,8 @@ #include CameraSelectorDialog::CameraSelectorDialog(libcamera::CameraManager *cameraManager, - QWidget *parent) - : QDialog(parent), cm_(cameraManager) + bool isScriptRunning, QWidget *parent) + : QDialog(parent), cm_(cameraManager), isScriptRunning_(isScriptRunning) { /* Use a QFormLayout for the dialog. */ QFormLayout *layout = new QFormLayout(this); @@ -39,6 +39,16 @@ CameraSelectorDialog::CameraSelectorDialog(libcamera::CameraManager *cameraManag connect(cameraIdComboBox_, &QComboBox::currentTextChanged, this, &CameraSelectorDialog::handleCameraChange); + captureScriptButton_ = new QPushButton; + connect(captureScriptButton_, &QPushButton::clicked, + this, &CameraSelectorDialog::handleCaptureScriptButton); + + /* Display the action that would be performed when button is clicked. */ + if (isScriptRunning_) + captureScriptButton_->setText("Stop"); + else + captureScriptButton_->setText("Open"); + /* Setup the QDialogButton Box */ QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | @@ -50,10 +60,10 @@ CameraSelectorDialog::CameraSelectorDialog(libcamera::CameraManager *cameraManag this, &QDialog::reject); /* Set the layout. */ - layout->addRow("Camera:", cameraIdComboBox_); layout->addRow("Location:", cameraLocation_); layout->addRow("Model:", cameraModel_); + layout->addRow("Capture Script:", captureScriptButton_); layout->addWidget(buttonBox); } @@ -62,6 +72,11 @@ std::string CameraSelectorDialog::getCameraId() return cameraIdComboBox_->currentText().toStdString(); } +std::string CameraSelectorDialog::getCaptureScript() +{ + return scriptPath_; +} + /* Hotplug / Unplug Support. */ void CameraSelectorDialog::cameraAdded(libcamera::Camera *camera) { @@ -115,3 +130,50 @@ void CameraSelectorDialog::updateCamInfo(const std::shared_ptrsetText(QString::fromStdString(model)); } + +/* Capture script support. */ +void CameraSelectorDialog::handleCaptureScriptButton() +{ + if (isScriptRunning_) { + Q_EMIT stopCaptureScript(); + isScriptRunning_ = false; + captureScriptButton_->setText("Open"); + } else { + selectedScriptPath_ = QFileDialog::getOpenFileName(this, + "Run Capture Script", QDir::currentPath(), + "Capture Script (*.yaml)") + .toStdString(); + + if (!selectedScriptPath_.empty()) + captureScriptButton_->setText("Loaded"); + else + captureScriptButton_->setText("Open"); + } +} + +void CameraSelectorDialog::accept() +{ + scriptPath_ = selectedScriptPath_; + QDialog::accept(); +} + +void CameraSelectorDialog::reject() +{ + if (isScriptRunning_) + selectedScriptPath_ = scriptPath_; + QDialog::reject(); +} + +void CameraSelectorDialog::informScriptReset() +{ + isScriptRunning_ = false; + scriptPath_.clear(); + captureScriptButton_->setText("Open"); +} + +void CameraSelectorDialog::informScriptRunning(std::string scriptPath) +{ + isScriptRunning_ = true; + scriptPath_ = scriptPath; + captureScriptButton_->setText("Stop"); +} diff --git a/src/qcam/cam_select_dialog.h b/src/qcam/cam_select_dialog.h index 359df811..56d90596 100644 --- a/src/qcam/cam_select_dialog.h +++ b/src/qcam/cam_select_dialog.h @@ -17,8 +17,10 @@ #include #include #include +#include #include #include +#include #include class CameraSelectorDialog : public QDialog @@ -26,12 +28,14 @@ class CameraSelectorDialog : public QDialog Q_OBJECT public: CameraSelectorDialog(libcamera::CameraManager *cameraManager, - QWidget *parent); + bool isScriptRunning, QWidget *parent); ~CameraSelectorDialog() = default; std::string getCameraId(); + std::string getCaptureScript(); + /* Hotplug / Unplug Support. */ void cameraAdded(libcamera::Camera *camera); @@ -41,11 +45,26 @@ public: void updateCamInfo(const std::shared_ptr &camera); void handleCameraChange(); + /* Capture script support. */ + void handleCaptureScriptButton(); + void informScriptReset(); + void informScriptRunning(std::string scriptPath); + void accept() override; + void reject() override; + +Q_SIGNALS: + void stopCaptureScript(); + private: libcamera::CameraManager *cm_; + bool isScriptRunning_; + std::string scriptPath_; + std::string selectedScriptPath_; + /* UI elements. */ QComboBox *cameraIdComboBox_; QLabel *cameraLocation_; QLabel *cameraModel_; + QPushButton *captureScriptButton_; }; diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index 3feabcff..d73fb42a 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -19,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -151,6 +153,9 @@ MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options) return; } + /* Start capture script. */ + loadCaptureScript(); + startStopAction_->setChecked(true); } @@ -289,10 +294,53 @@ void MainWindow::switchCamera() startStopAction_->setChecked(true); } +void MainWindow::stopCaptureScript() +{ + if (script_) { + script_.reset(); + cameraSelectorDialog_->informScriptReset(); + } +} + +void MainWindow::loadCaptureScript() +{ + if (scriptPath_.empty() || camera_ == nullptr) + return; + + script_ = std::make_unique(camera_, scriptPath_); + + /* + * If we are already capturing, stop so we don't have stuck image + * in viewfinder. + */ + bool wasCapturing = isCapturing_; + if (isCapturing_) + toggleCapture(false); + + if (!script_->valid()) { + script_.reset(); + cameraSelectorDialog_->informScriptReset(); + + QMessageBox::critical(this, "Invalid Script", + "Couldn't load the capture script"); + + } else + cameraSelectorDialog_->informScriptRunning(scriptPath_); + + /* Start capture again if we were capturing before. */ + if (wasCapturing) + toggleCapture(true); +} + std::string MainWindow::chooseCamera() { + bool scriptRunning = script_ != nullptr; + /* Construct the selection dialog, unconditionally. */ - cameraSelectorDialog_ = new CameraSelectorDialog(cm_, this); + cameraSelectorDialog_ = new CameraSelectorDialog(cm_, scriptRunning, this); + + connect(cameraSelectorDialog_, &CameraSelectorDialog::stopCaptureScript, + this, &MainWindow::stopCaptureScript); /* * Use the camera specified on the command line, if any, or display the @@ -305,6 +353,9 @@ std::string MainWindow::chooseCamera() std::string cameraId = cameraSelectorDialog_->getCameraId(); cameraSelectButton_->setText(QString::fromStdString(cameraId)); + scriptPath_ = cameraSelectorDialog_->getCaptureScript(); + loadCaptureScript(); + return cameraId; } else return std::string(); @@ -502,6 +553,7 @@ int MainWindow::startCapture() previousFrames_ = 0; framesCaptured_ = 0; lastBufferTime_ = 0; + queueCount_ = 0; ret = camera_->start(); if (ret) { @@ -779,5 +831,10 @@ void MainWindow::renderComplete(FrameBuffer *buffer) int MainWindow::queueRequest(Request *request) { + if (script_) + request->controls() = script_->frameControls(queueCount_); + + queueCount_++; + return camera_->queueRequest(request); } diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h index bd6f0172..887f1db1 100644 --- a/src/qcam/main_window.h +++ b/src/qcam/main_window.h @@ -28,6 +28,7 @@ #include #include +#include "../cam/capture_script.h" #include "../cam/stream_options.h" #include "cam_select_dialog.h" @@ -90,6 +91,9 @@ private: void processHotplug(HotplugEvent *e); void processViewfinder(libcamera::FrameBuffer *buffer); + void loadCaptureScript(); + void stopCaptureScript(); + /* UI elements */ QToolBar *toolbar_; QAction *startStopAction_; @@ -130,6 +134,9 @@ private: QElapsedTimer frameRateInterval_; uint32_t previousFrames_; uint32_t framesCaptured_; + uint32_t queueCount_; std::vector> requests_; + std::unique_ptr script_; + std::string scriptPath_; }; diff --git a/src/qcam/meson.build b/src/qcam/meson.build index 61861ea6..70a18d7e 100644 --- a/src/qcam/meson.build +++ b/src/qcam/meson.build @@ -15,6 +15,7 @@ endif qcam_enabled = true qcam_sources = files([ + '../cam/capture_script.cpp', '../cam/image.cpp', '../cam/options.cpp', '../cam/stream_options.cpp', @@ -39,6 +40,7 @@ qcam_resources = files([ qcam_deps = [ libatomic, libcamera_public, + libyaml, qt5_dep, ]