From patchwork Wed Aug 10 15:03:47 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Utkarsh Tiwari X-Patchwork-Id: 17072 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 D10EFC3272 for ; Wed, 10 Aug 2022 15:04:12 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9B25963339; Wed, 10 Aug 2022 17:04:12 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1660143852; bh=upCoIlKlT5qp5pF9zmX7F8MyEgG7EXGLGtXNIVPP4js=; 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=qxqbbJHQgZhZzOsZ5Ve3dfXJKCPcXNVYKY0zFz5WH5/1IKAINAAIgz5nG6O2Ks+fw NFBCbJDwDRrnnIiq9wmAyVz4zwQiv55IVbxWKCMsvYNY6B9A2Zr4sFrwVtxEttU0nA KCvlrNMXRK40TWL8LD/xHhgn4PScx9UpPshm7KESlR8VvMP4MtVePnTFk4WZuAMo9J VgJU8iH3Q4MTBxR0ooF6y261ftCWBklSK+Z8tDAAhjo5nw2n/hpP6iKLL/4FJEar/W uPZlmc8pEXHw2k6IJ+QdkcmchxlMnBrrKdJUYNjKQpP5D/KZuox5nqT0CvoHaUdaML RIHViC8qdi5kg== 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 A14BF6333A for ; Wed, 10 Aug 2022 17:04:10 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="Xcczk3j8"; dkim-atps=neutral Received: by mail-pg1-x536.google.com with SMTP id f65so14568088pgc.12 for ; Wed, 10 Aug 2022 08:04:10 -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=19kf8evk0yJiVwc4l+BQ3glXTE//vBYqtlQDA6iT9iQ=; b=Xcczk3j8do8Ouv1FnHaxf3LsrW8Jcy7R3ZfupUUWjA9yYUVPqbPd3c5EtPv/LSw8R6 tp+sGuNu+/fjLUAfK8yNerXAAsWtqBByvN2BQ363g65PQ1R3R9g3FmLVeS5QNkKvOPm/ hl192LWtkNwp5UWsfD0Z2x1fL8DRNs0wut6453N9QL3C7cdwM/n8S2YZvRI58xmNOgxw r4ly9rKj3BfBYc11D+0XQ0MmA75QOHSFYGlKIk6t84fkWtzNgcl6W6ub/5tdp24ihz61 8X4FpxoIsTNRTrdwO5hJ+mP8Enopz4r5ZdrqmJqokg8DGmyOl4FA25ZYcq8GvfNId+WA Xxrg== 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=19kf8evk0yJiVwc4l+BQ3glXTE//vBYqtlQDA6iT9iQ=; b=dRgfqys8GerFXjPXEEyj3pumrlyU1hmfjnttIG29K75AOy3Z+wU5ISpLiA+vIknBR4 vAXr2FYM4l71sPTJZLExcK02t//6jJG9mtVOGeYbSgg2Y1lkvh57xsyiO4lPI+q+4bBg XmVDNPxm1nSm5SN+Drns8R3ZiROMmN8cIqIZuPAcInQK0HO32qkmUbAfyAZ1cgyYfsL3 ptJzy+p7xvo9Jf3aL/EoGufFUklWFvFJX02CJwqXtPraL5xNA0miJ+bqC4YWjzWqabcQ uSeF/TkDXVTegNpbgHf6L6kHoSqkJFJLirlDLzAV69T2cEndf+kOP1oLgNYvzOZNtmDf o8RQ== X-Gm-Message-State: ACgBeo0QAKxPsN8EKnQqLT8GA2f80QE6teBWsgJjyfgWbKjgH06S2/mY qdcfJFjrS9w08NUGkFrYKBsdCD9Yo4U= X-Google-Smtp-Source: AA6agR52dU11VAbKLtRtPpGW2DBb9AXIDCzFxOBrvShFsw5FhiMA87Z0bpS8SSzIFkRu01H8xnPPIg== X-Received: by 2002:a62:1c04:0:b0:52e:d2b4:c029 with SMTP id c4-20020a621c04000000b0052ed2b4c029mr22847371pfc.60.1660143848887; Wed, 10 Aug 2022 08:04:08 -0700 (PDT) Received: from localhost.localdomain ([2404:bd00:3:d2bc:2a55:4cae:bf8f:f4ed]) by smtp.gmail.com with ESMTPSA id b3-20020a1709027e0300b0016f1319d2a7sm12882624plm.297.2022.08.10.08.04.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Aug 2022 08:04:08 -0700 (PDT) To: libcamera-devel@lists.libcamera.org Date: Wed, 10 Aug 2022 20:33:47 +0530 Message-Id: <20220810150349.414043-7-utkarsh02t@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220810150349.414043-1-utkarsh02t@gmail.com> References: <20220810150349.414043-1-utkarsh02t@gmail.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v8 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 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 | 69 ++++++++++++++++++++++++++++++++-- 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, 152 insertions(+), 5 deletions(-) diff --git a/src/qcam/cam_select_dialog.cpp b/src/qcam/cam_select_dialog.cpp index f97ad6eb..0db0a5bd 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,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 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, ]