From patchwork Sun Aug 7 20:32:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Utkarsh Tiwari X-Patchwork-Id: 17020 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 8F029BE173 for ; Sun, 7 Aug 2022 20:32:25 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4D57763331; Sun, 7 Aug 2022 22:32:25 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1659904345; bh=ZKxp1KsJ4mvRmllU7wUk04TZnWO1Vjh4fMSlg/VQkw0=; 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=AhrUfwKldXWKqzsyg7YqszkMcAiQy5O+/L8Yt3OtIl96+/YoeIkUhzm7MlSPIY0Sn sJzQJDfjF+ho6ycmMNCaUmfc9Gn290GeFQOURqeH8tdfXoOA1QviJfi69h75yx8tql nBn84MsrI1xNRc0YXU0utuNdEXzjmkjx0csplY/3UtdKbvqFpX8YXVyDIMJyYdJO4j rKUlKILooCwPk1oRxq7bQxV7Vv+ZhPU2uN6AisAUIiJGDD5cLFJ/dIV4+/xyn/ILWe 71/xiPhhyK0AuLzOG0up7lB0CBb+M9l0/u2gWP3raKJtD2qImYjGAekUttKXlkOub2 q0FHMK08F15xQ== Received: from mail-pf1-x42b.google.com (mail-pf1-x42b.google.com [IPv6:2607:f8b0:4864:20::42b]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8142E63327 for ; Sun, 7 Aug 2022 22:32:24 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="ZIjgJjPm"; dkim-atps=neutral Received: by mail-pf1-x42b.google.com with SMTP id z187so6495598pfb.12 for ; Sun, 07 Aug 2022 13:32:24 -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=qavyrCFTP++VA/WS4m58ciqEI9ghwGad3JE3DUvPKRk=; b=ZIjgJjPmRVpz78lKANhJu9O9VZf/0K8TBWx+SQUVnstNrLo2vOn6lKnki5+ZkebhLO UbwLF8M9cHBwsYUGmfnXhOsgrJ2auxqsjhQ2z/gqb5EkcUEVFIW5sJTMAmRYVOHrr4hi /dH8hkZsng63nZ0UdzE3ET63UQDhHNHx0BN4WUzMryrwUCVc7npSByAFpQFVstIEpIBJ 2ajOZ6gJDjGDkRvRGCTJjhLK+frm5R9YhKVZnkQQBLyALG7XncddJHk+CFNT31EkzSFg SR5Brw565s39iUbjmdEbgj3JI4XVYH6zevs3BDPAnXqVI3G1otHQcDB8MIp294B5tIL2 MtlA== 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=qavyrCFTP++VA/WS4m58ciqEI9ghwGad3JE3DUvPKRk=; b=HsP2sl/Crfp6sSpk5MgCfKx0b/Plutv0hpEJigdwCpisS6oO7vT6H/SSOmLppVD60G pLHPYBBDc9Ypev/rPSjBaVfzF9bh/6U8GKKBLd8q67+Eycd1y8ij4CwGE5OuaXMrj95P g0CIphwD6FIkP84PKXLw7pGDvMvYxz6c+9sy+Tx/nMYl603js+eRPKwaXAf8TO0TT/YF YSgyL2foJ2acDgLcNWsrArX7JdB5oxiP4cLGYVc3qBFv8ENzXTTewogwGt6Hjv9I0Tq3 2K9XI8sy49YA/YbumSj3twa0t1Dlz6Kse/n0968MDrPbwhmT4xZNav/RSPnQ+55KxImP 97Jw== X-Gm-Message-State: ACgBeo2CIBf3DOCntFiP6SjYh0VQ/7VK1v1tDk0+Aa12BPxELrwvuO88 d4wzwdFt4FAGxviPdtybulP6PICK8GM= X-Google-Smtp-Source: AA6agR7wP3liw94tKGm/JtfTr4zmW9+9Gj15nyUQiLlylKHFt+4/U54Ak3aJJM+fqQL7/GuGn8LCZQ== X-Received: by 2002:a63:bd49:0:b0:41b:8a07:a6ed with SMTP id d9-20020a63bd49000000b0041b8a07a6edmr12826181pgp.124.1659904342804; Sun, 07 Aug 2022 13:32:22 -0700 (PDT) Received: from localhost.localdomain ([2404:bd00:3:d2bc:8eec:115d:8ea8:b700]) by smtp.gmail.com with ESMTPSA id x29-20020aa7941d000000b0052d194a6602sm7006334pfo.102.2022.08.07.13.32.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 07 Aug 2022 13:32:22 -0700 (PDT) To: libcamera-devel@lists.libcamera.org Date: Mon, 8 Aug 2022 02:02:02 +0530 Message-Id: <20220807203204.152358-3-utkarsh02t@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220807203204.152358-1-utkarsh02t@gmail.com> References: <20220807203204.152358-1-utkarsh02t@gmail.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v6 2/4] 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 from V1: No button on toolbar now it resides in CamSelectDialog src/qcam/cam_select_dialog.h | 47 +++++++++++++++++++++++++++++-- src/qcam/main_window.cpp | 54 +++++++++++++++++++++++++++++++++++- src/qcam/main_window.h | 7 +++++ src/qcam/meson.build | 2 ++ 4 files changed, 107 insertions(+), 3 deletions(-) diff --git a/src/qcam/cam_select_dialog.h b/src/qcam/cam_select_dialog.h index 6ba61cff..fc29b46a 100644 --- a/src/qcam/cam_select_dialog.h +++ b/src/qcam/cam_select_dialog.h @@ -18,16 +18,19 @@ #include #include #include +#include #include #include +#include #include class CamSelectDialog : public QDialog { Q_OBJECT public: - CamSelectDialog(libcamera::CameraManager *cameraManager, QWidget *parent) - : QDialog(parent), cm_(cameraManager) + CamSelectDialog(libcamera::CameraManager *cameraManager, + bool isScriptRunning, QWidget *parent) + : QDialog(parent), cm_(cameraManager), isScriptRunning_(isScriptRunning) { /* Use a QFormLayout for the dialog. */ QFormLayout *camSelectDialogLayout = new QFormLayout(this); @@ -48,6 +51,16 @@ public: cameraIdComboBox_->currentText().toStdString())); }); + captureScriptButton_ = new QPushButton; + connect(captureScriptButton_, &QPushButton::clicked, + this, &CamSelectDialog::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 *dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok | @@ -62,6 +75,7 @@ public: camSelectDialogLayout->addRow("Camera: ", cameraIdComboBox_); camSelectDialogLayout->addRow("Location: ", cameraLocation_); camSelectDialogLayout->addRow("Model: ", cameraModel_); + camSelectDialogLayout->addRow("Capture Script: ", captureScriptButton_); camSelectDialogLayout->addWidget(dialogButtonBox); } @@ -72,6 +86,11 @@ public: return cameraIdComboBox_->currentText().toStdString(); } + std::string getCaptureScript() + { + return scriptPath_; + } + /* Hotplug / Unplug Support. */ void cameraAdded(libcamera::Camera *camera) { @@ -122,11 +141,35 @@ public: cameraModel_->setText(QString()); } + /* Capture script support. */ + void handleCaptureScriptButton() + { + if (isScriptRunning_) { + Q_EMIT stopCaptureScript(); + isScriptRunning_ = false; + captureScriptButton_->setText("Open"); + } else { + scriptPath_ = QFileDialog::getOpenFileName(this, "Run Capture Script", + QDir::currentPath(), "Capture Script (*.yaml)") + .toStdString(); + + if (!scriptPath_.empty()) + captureScriptButton_->setText("Loaded"); + } + } + +Q_SIGNALS: + void stopCaptureScript(); + private: libcamera::CameraManager *cm_; + bool isScriptRunning_; + std::string scriptPath_; + /* 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 549af024..e0219e5e 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); } @@ -290,14 +295,55 @@ void MainWindow::switchCamera() startStopAction_->setChecked(true); } +void MainWindow::stopCaptureScript() +{ + if (script_) { + script_.reset(); + } +} + +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(); + + QMessageBox::critical(this, "Invalid Script", + "Couldn't load the capture script"); + } + + /* Start capture again if we were capturing before. */ + if (wasCapturing) + toggleCapture(true); +} + std::string MainWindow::chooseCamera() { - camSelectDialog_ = new CamSelectDialog(cm_, this); + bool scriptRunning = script_ != nullptr; + camSelectDialog_ = new CamSelectDialog(cm_, scriptRunning, this); + + connect(camSelectDialog_, &CamSelectDialog::stopCaptureScript, + this, &MainWindow::stopCaptureScript); if (camSelectDialog_->exec() == QDialog::Accepted) { std::string cameraId = camSelectDialog_->getCameraId(); cameraSwitchButton_->setText(QString::fromStdString(cameraId)); + scriptPath_ = camSelectDialog_->getCaptureScript(); + loadCaptureScript(); + return cameraId; } else return std::string(); @@ -504,6 +550,7 @@ int MainWindow::startCapture() previousFrames_ = 0; framesCaptured_ = 0; lastBufferTime_ = 0; + queueCount_ = 0; ret = camera_->start(); if (ret) { @@ -783,5 +830,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 7982939e..01466e28 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 70615e92..80c97cc5 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', @@ -38,6 +39,7 @@ qcam_resources = files([ qcam_deps = [ libatomic, libcamera_public, + libyaml, qt5_dep, ]