From patchwork Fri Aug 12 12:15:39 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Utkarsh Tiwari X-Patchwork-Id: 17094 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 97D3EC3272 for ; Fri, 12 Aug 2022 12:15:50 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1BE7661FAB; Fri, 12 Aug 2022 14:15:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1660306550; bh=wXin4dfZWdlxruIwocqPnvDD6DwTixXnq1/SlB4SKJU=; 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=WOoGlrxE9+RlqNP77raLifbsPuvsrE8oq/vU47NEuT7Fy0k7TAGSj1Zf0f8Nuu9rl AsFLIB+xPXfz88Ue1k5JupHf94z68NwER5opcEJ7KVIjgbgB9AGQ2cP0XXwCC8EZH+ 1fnsYF+DFc3C7NeJXPuLLARFadsZFeJtxs3w/a/yLLN72r+jlQf2nj3h9XUO+F0GCa FvnbVMlltYHebkinD5mLNM7Cwz4bezCeEB/9GaB/BWyn43HixxVaZd7hHEsB+f0Q6J U0Y8eapzUc4jcBAON4X3guvNa/BLgWXM2nBYtufLbWdTKlSQXbZSNK6cFzLhbnu6MA U776+QxX28Tiw== Received: from mail-pf1-x42c.google.com (mail-pf1-x42c.google.com [IPv6:2607:f8b0:4864:20::42c]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id F1118603EA for ; Fri, 12 Aug 2022 14:15:48 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="VxZo8eTm"; dkim-atps=neutral Received: by mail-pf1-x42c.google.com with SMTP id q19so794107pfg.8 for ; Fri, 12 Aug 2022 05:15:48 -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=MOvtulXyMj//il5ULsG9BMva1Q2taIraU0/CKP0RhfY=; b=VxZo8eTm6YJ34cpW+0DnmUEv5ePAWrrZXvfwz6FwVE7FJrPCAOKvaWcWWWLdK5vROn W6K333koAa+o3Kho2mG3NPyNgFkupRHzfjBjyconE9htXPYtczy5TpGVYmJWaBbGqWQC eFIEwy+BAxrgDvEffeoIihRH7xToz8MZg35t44XdgHFBG5seFnn2V30hFoxhxO03ZJl+ 5pCwme+Y4xD3XnyjflDp07U5uBJEsNthl2t341T8e6KuuBvdtw1u6Obl5Lyj7KDACsbC NwDSZCNOCPBIH+rh72bSzZ9a7pBRBCjyPJ7tFRdUtrRTDjrcPulgtRZXol1iw1E8M7h+ pOyQ== 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=MOvtulXyMj//il5ULsG9BMva1Q2taIraU0/CKP0RhfY=; b=CR8SvJmpfzWamIH3kZ8ZkJWW4L9cvjnNZeh7cPX5/rm/YVo3tMLkQOS44Kb20uzQrE Zr/yRcOejh5DgwVadWJdHxi5RkWa5CCipvdnslqbibA8NjtT3g8bAfrBNJS5uFo02zw7 K3y3kGzxw6zhRGS/SSHQEzbBDs9Sy3O994nEnXDHj5LZRdJ/BLUJSqisNuinWcMk9vec /gci7EX/zMAgTtXpC7xXapiOg8U9gT8qT4MsCu9xJY162I5a+24DZixmQ8Mr5T7JkWJM hpoLjFDsgbvZAjRK0s3CMhYdMBgJ+HYjyr1dEL5kvgL/xZq7SWBqJZ3LFJUCou5AaUOn vGJA== X-Gm-Message-State: ACgBeo1TiretGA/JstV0/Szau0RP2R1zuXC8BgjR4OKWcbbOj94j6tvZ KD6q2/yrfyPc9hwpIYssjKtnL287N5M= X-Google-Smtp-Source: AA6agR4dAvuX/TjkH8razk90tShWD+MXpO/uDTbLCTH/kP5TOHtZzleqF05tVpMRagpfvZ2i9t0Wqw== X-Received: by 2002:a63:1726:0:b0:41d:b30:46d4 with SMTP id x38-20020a631726000000b0041d0b3046d4mr2878327pgl.27.1660306546943; Fri, 12 Aug 2022 05:15:46 -0700 (PDT) Received: from localhost.localdomain ([2404:bd00:3:dc0d:d8e:96a2:2dbe:5a83]) by smtp.gmail.com with ESMTPSA id ik4-20020a170902ab0400b0016c0eb202a5sm1548918plb.225.2022.08.12.05.15.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Aug 2022 05:15:46 -0700 (PDT) To: libcamera-devel@lists.libcamera.org Date: Fri, 12 Aug 2022 17:45:39 +0530 Message-Id: <20220812121539.21441-1-utkarsh02t@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220810150349.414043-7-utkarsh02t@gmail.com> References: <20220810150349.414043-7-utkarsh02t@gmail.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v8.1 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 clicked in an open state, present the user with a QFileDialog to allow selecting 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 reset and the capture 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 from v8: 1. selectedScriptPath_ is now cleared when informScriptReset() is invoked. Difference from v7: 1. Fix grammetical errors in the commit message 2. Intialize the cameraSelectorDialog_ to nullptr in Construct so we construct the CameraSelectorDialog just once src/qcam/cam_select_dialog.cpp | 70 ++++++++++++++++++++++++++++++++-- src/qcam/cam_select_dialog.h | 20 +++++++++- src/qcam/main_window.cpp | 59 +++++++++++++++++++++++++++- src/qcam/main_window.h | 7 ++++ src/qcam/meson.build | 2 + 5 files changed, 153 insertions(+), 5 deletions(-) diff --git a/src/qcam/cam_select_dialog.cpp b/src/qcam/cam_select_dialog.cpp index f97ad6eb..58cbfc28 100644 --- a/src/qcam/cam_select_dialog.cpp +++ b/src/qcam/cam_select_dialog.cpp @@ -16,12 +16,13 @@ #include #include #include +#include #include #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 +40,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 +61,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 +73,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 +131,51 @@ 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(); + selectedScriptPath_.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 16475af6..bbdf897e 100644 --- a/src/qcam/cam_select_dialog.h +++ b/src/qcam/cam_select_dialog.h @@ -17,18 +17,21 @@ #include #include #include +#include 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); @@ -38,11 +41,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 bf40572a..3c7c3173 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 @@ -152,6 +154,9 @@ MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options) return; } + /* Start capture script. */ + loadCaptureScript(); + startStopAction_->setChecked(true); } @@ -290,11 +295,54 @@ 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, only the first time. */ if (!cameraSelectorDialog_) - 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 @@ -309,6 +357,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(); @@ -506,6 +557,7 @@ int MainWindow::startCapture() previousFrames_ = 0; framesCaptured_ = 0; lastBufferTime_ = 0; + queueCount_ = 0; ret = camera_->start(); if (ret) { @@ -783,5 +835,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 d161365a..10994b67 100644 --- a/src/qcam/main_window.h +++ b/src/qcam/main_window.h @@ -27,6 +27,7 @@ #include #include +#include "../cam/capture_script.h" #include "../cam/stream_options.h" #include "cam_select_dialog.h" @@ -89,6 +90,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, ]