diff options
Diffstat (limited to 'tests/manual/wasm')
-rw-r--r-- | tests/manual/wasm/CMakeLists.txt | 6 | ||||
-rw-r--r-- | tests/manual/wasm/camera/CMakeLists.txt | 42 | ||||
-rw-r--r-- | tests/manual/wasm/camera/camera-test.pro | 69 | ||||
-rw-r--r-- | tests/manual/wasm/camera/main.cpp | 17 | ||||
-rw-r--r-- | tests/manual/wasm/camera/mainwindow.cpp | 261 | ||||
-rw-r--r-- | tests/manual/wasm/camera/mainwindow.h | 53 | ||||
-rw-r--r-- | tests/manual/wasm/camera/mainwindow.ui | 107 |
7 files changed, 555 insertions, 0 deletions
diff --git a/tests/manual/wasm/CMakeLists.txt b/tests/manual/wasm/CMakeLists.txt new file mode 100644 index 000000000..1d3c623c4 --- /dev/null +++ b/tests/manual/wasm/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(QT_FEATURE_widgets) + add_subdirectory(camera) +endif() diff --git a/tests/manual/wasm/camera/CMakeLists.txt b/tests/manual/wasm/camera/CMakeLists.txt new file mode 100644 index 000000000..f63c60bbf --- /dev/null +++ b/tests/manual/wasm/camera/CMakeLists.txt @@ -0,0 +1,42 @@ +# Generated from camera-test.pro. + +cmake_minimum_required(VERSION 3.16) +project(camera-test VERSION 1.0 LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() +set(CMAKE_BUILD_TYPE Release) +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}") + +find_package(QT NAMES Qt5 Qt6 REQUIRED COMPONENTS Core) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Gui Multimedia MultimediaWidgets) +find_package(Qt${QT_VERSION_MAJOR} OPTIONAL_COMPONENTS Widgets) + +qt_add_executable(camera-test WIN32 MACOSX_BUNDLE + main.cpp + mainwindow.cpp mainwindow.h mainwindow.ui +) +target_link_libraries(camera-test PUBLIC + Qt::Core + Qt::Gui + Qt::Multimedia + Qt::MultimediaWidgets + Qt::CorePrivate + Qt::Widgets +) + +set(CMAKE_BUILD_TYPE Debug) +# uncomment to enable asyncify +# target_link_options(wasm-camera PUBLIC -sASYNCIFY -Os) + +install(TARGETS camera-test + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/tests/manual/wasm/camera/camera-test.pro b/tests/manual/wasm/camera/camera-test.pro new file mode 100644 index 000000000..f13ba3596 --- /dev/null +++ b/tests/manual/wasm/camera/camera-test.pro @@ -0,0 +1,69 @@ +QT += core gui multimedia multimediawidgets + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++17 debug + +# uncomment this to use asyncify +#wasm: QMAKE_LFLAGS += -s ASYNCIFY -Os + +# You can make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + mainwindow.cpp + +HEADERS += \ + mainwindow.h + +FORMS += \ + mainwindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +macos { + PRODUCT_NAME = $$TARGET + macx-xcode: PRODUCT_NAME = $${LITERAL_DOLLAR}{PRODUCT_NAME} + INFOPLIST = \ + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" \ + "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">" \ + "<plist version=\"1.0\">" \ + "<dict>" \ + " <key>CFBundleIconFile</key>" \ + " <string></string>" \ + " <key>CFBundlePackageType</key>" \ + " <string>APPL</string>" \ + " <key>CFBundleGetInfoString</key>" \ + " <string>Created by Qt/QMake</string>" \ + " <key>CFBundleSignature</key>" \ + " <string>????</string>" \ + " <key>CFBundleExecutable</key>" \ + " <string>$$TARGET</string>" \ + " <key>CFBundleIdentifier</key>" \ + " <string>com.digia.$${LITERAL_DOLLAR}{PRODUCT_NAME:rfc1034identifier}</string>" \ + " <key>CFBundleDisplayName</key>" \ + " <string>$$PRODUCT_NAME</string>" \ + " <key>CFBundleName</key>" \ + " <string>$$PRODUCT_NAME</string>" \ + " <key>CFBundleShortVersionString</key>" \ + " <string>1.0</string>" \ + " <key>CFBundleVersion</key>" \ + " <string>1.0</string>" \ + " <key>NSPrincipalClass</key>" \ + " <string>NSApplication</string>" \ + " <key>NSCameraUsageDescription</key>" \ + " <string>Qt Multimedia Example</string>" \ + " <key>NSMicrophoneUsageDescription</key>" \ + " <string>Qt Multimedia Example</string>" \ + " <key>NOTE</key>" \ + " <string>This file was generated by Qt/QMake.</string>" \ + "</dict>" \ + "</plist>" + write_file($$OUT_PWD/Info.plist, INFOPLIST)|error() + QMAKE_INFO_PLIST = $$OUT_PWD/Info.plist +} diff --git a/tests/manual/wasm/camera/main.cpp b/tests/manual/wasm/camera/main.cpp new file mode 100644 index 000000000..8370ffb87 --- /dev/null +++ b/tests/manual/wasm/camera/main.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "mainwindow.h" + +#include <QApplication> +#include <QLoggingCategory> + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + QLoggingCategory::setFilterRules("*.debug=false\n" + "qt.multimedia.wasm.*=true"); + MainWindow w; + w.show(); + return a.exec(); +} diff --git a/tests/manual/wasm/camera/mainwindow.cpp b/tests/manual/wasm/camera/mainwindow.cpp new file mode 100644 index 000000000..78c6a7584 --- /dev/null +++ b/tests/manual/wasm/camera/mainwindow.cpp @@ -0,0 +1,261 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "mainwindow.h" +#include "ui_mainwindow.h" + +#include <QAudioInput> +#include <QCamera> +#include <QCameraDevice> +#include <QGraphicsScene> +#include <QGraphicsVideoItem> +#include <QImageCapture> +#include <QMediaCaptureSession> +#include <QMediaDevices> +#include <QMediaFormat> +#include <QApplication> +#include <QTimer> +#include <QVideoWidget> +#include <QLabel> +#include <QFileDialog> +#include <QScreen> +#include <QMediaPlayer> + +#if QT_CONFIG(permissions) + #include <QPermission> +#endif + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent), + ui(new Ui::MainWindow), + m_recorder(nullptr) +{ + ui->setupUi(this); + init(); +} + +MainWindow::~MainWindow() +{ + if (m_recorder) + delete m_recorder; + delete ui; +} + +void MainWindow::init() +{ +#if QT_CONFIG(permissions) + // camera + QCameraPermission cameraPermission; + switch (qApp->checkPermission(cameraPermission)) { + case Qt::PermissionStatus::Undetermined: + qApp->requestPermission(cameraPermission, this, &MainWindow::init); + return; + case Qt::PermissionStatus::Denied: + qWarning("Camera permission is not granted!"); + return; + case Qt::PermissionStatus::Granted: + break; + } + // microphone + QMicrophonePermission microphonePermission; + switch (qApp->checkPermission(microphonePermission)) { + case Qt::PermissionStatus::Undetermined: + qApp->requestPermission(microphonePermission, this, &MainWindow::init); + return; + case Qt::PermissionStatus::Denied: + qWarning("Microphone permission is not granted!"); + return; + case Qt::PermissionStatus::Granted: + break; + } +#endif + m_captureSession = new QMediaCaptureSession(this); + + m_mediaDevices = new QMediaDevices(this); + // wait until devices list is ready + connect(m_mediaDevices, &QMediaDevices::videoInputsChanged, + [this]() { doCamera(); }); +} + +void MainWindow::doCamera() +{ + m_audioInput.reset(new QAudioInput); + m_captureSession->setAudioInput(m_audioInput.get()); + const QList<QCameraDevice> cameras = QMediaDevices::videoInputs(); + + ui->camerasComboBox->clear(); + ui->camerasComboBox->setPlaceholderText("select camera"); + + for (const QCameraDevice &cameraDevice : cameras) { + if (ui->camerasComboBox->findText(cameraDevice.description()) == -1) + ui->camerasComboBox->addItem(cameraDevice.description(), cameraDevice.id()); + } + + if (cameras.count() == 0) { + qWarning() << "No camera found"; + } else { + + QGraphicsVideoItem *videoItem = new QGraphicsVideoItem(); + QGraphicsScene *scene = new QGraphicsScene(this); + m_captureSession->setVideoOutput(videoItem); // sets videoSink + + ui->graphicsView->setScene(scene); + ui->graphicsView->scene()->addItem(videoItem); + ui->graphicsView->show(); + } +} + +void MainWindow::on_startButton_clicked() +{ + m_camera.data()->start(); +} + +void MainWindow::on_stopButton_clicked() +{ + m_camera.data()->stop(); +} + +void MainWindow::on_captureButton_clicked() +{ + connect(m_camera.data(), &QCamera::errorOccurred, + [](QCamera::Error error, const QString &errorString) { + qWarning() << "Error occurred" << error << errorString; + }); + + QImageCapture *m_imageCapture = new QImageCapture(this); + connect(m_imageCapture, &QImageCapture::readyForCaptureChanged, [] (bool ready) { + + qWarning() << "MainWindow::readyForCaptureChanged" << ready; + }); + + connect(m_imageCapture, + &QImageCapture::imageCaptured, + [] (int id, const QImage &preview) { + qWarning() << "MainWindow::imageCaptured" << id << preview; + + }); + + connect(m_imageCapture, &QImageCapture::imageSaved, + [this] (int id, const QString &fileName) { + Q_UNUSED(id) + QFileInfo fi(fileName); + if (!fi.exists()) { + qWarning() << fileName << "Does not exist"; + } else { + QDialog *dlg = new QDialog(this); + dlg->setWindowTitle(fi.fileName()); + QHBoxLayout *l = new QHBoxLayout(dlg); + QLabel *label = new QLabel(this); + l->addWidget(label); + label->setPixmap(QPixmap(fileName)); + dlg->show(); + } + + }); + connect(m_imageCapture, + &QImageCapture::errorOccurred, [] + (int id, QImageCapture::Error error, const QString &errorString) { + qWarning() << "MainWindow::errorOccurred" << id << error << errorString; + }); + + m_captureSession->setImageCapture(m_imageCapture); + + // take photo + if (m_imageCapture->isReadyForCapture()) + m_imageCapture->captureToFile(QStringLiteral("/home/web_user/image.png")); +} + +void MainWindow::on_openButton_clicked() +{ + // open + QFileDialog *dialog = new QFileDialog(this); + dialog->setNameFilter(tr("All Files (*.*)")); + connect(dialog, &QFileDialog::fileSelected, + [this](const QString &file) { + qWarning() << "open this file" << file; + showFile(file); + }); + + dialog->show(); +} + +void MainWindow::on_camerasComboBox_textActivated(const QString &arg1) +{ + const QList<QCameraDevice> cameras = QMediaDevices::videoInputs(); + for (const QCameraDevice &cameraDevice :cameras) { + if (arg1 == cameraDevice.description()) { + m_camera.reset(new QCamera(cameraDevice)); + connect(m_captureSession, &QMediaCaptureSession::cameraChanged, + [this]() { + enableButtons(true); + }); + m_captureSession->setCamera(m_camera.data()); + break; + } + } +} + +void MainWindow::on_recordButton_clicked() +{ + if (!isRecording) { + if (m_recorder) + delete m_recorder; + m_recorder = new QMediaRecorder(); + connect(m_recorder, &QMediaRecorder::durationChanged, + [](qint64 duration) { + qWarning() << "MainWindow::durationChanged" + << duration; + }); + m_captureSession->setRecorder(m_recorder); + + m_recorder->setQuality(QMediaRecorder::HighQuality); + m_recorder->setOutputLocation(QUrl::fromLocalFile("test.mp4")); + m_recorder->record(); + isRecording = true; + ui->recordButton->setText(QStringLiteral("Stop")); + } else { + m_recorder->stop(); + isRecording = false; + m_recorder->deleteLater(); + ui->recordButton->setText(QStringLiteral("Record")); + } +} + +void MainWindow::enableButtons(bool ok) +{ + ui->captureButton->setEnabled(ok); + ui->startButton->setEnabled(ok); + ui->stopButton->setEnabled(ok); + ui->openButton->setEnabled(ok); + ui->recordButton->setEnabled(ok); +} + +void MainWindow::showFile(const QString &fileName) +{ + + const QSize screenGeometry = screen()->availableSize(); + QFileInfo fi(fileName); + QDialog *dlg = new QDialog(this); + dlg->setWindowTitle(fi.fileName()); + QHBoxLayout *layout = new QHBoxLayout(dlg); + QMediaPlayer *player = new QMediaPlayer(dlg); + connect(player, &QMediaPlayer::errorOccurred, [=] (QMediaPlayer::Error error, const QString &errorString) { + qWarning() << "MediaPlayer erro!:" << error << errorString; + }); + + QGraphicsVideoItem *m_videoItem = new QGraphicsVideoItem(); + QSizeF dialogSize(screenGeometry.width() / 2, screenGeometry.height() / 2); + m_videoItem->setSize(dialogSize); + player->setVideoOutput(m_videoItem); + dlg->setGeometry(20, 20, dialogSize.width() + 40, dialogSize.height() + 40); + + QGraphicsScene *scene = new QGraphicsScene(dlg); + QGraphicsView *graphicsView = new QGraphicsView(scene); + scene->addItem(m_videoItem); + layout->addWidget(graphicsView); + + player->setSource(QUrl(fileName)); + + dlg->show(); + player->play(); +} diff --git a/tests/manual/wasm/camera/mainwindow.h b/tests/manual/wasm/camera/mainwindow.h new file mode 100644 index 000000000..854c00935 --- /dev/null +++ b/tests/manual/wasm/camera/mainwindow.h @@ -0,0 +1,53 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <QMainWindow> +#include <QImageCapture> +#include <QMediaCaptureSession> +#include <QGraphicsVideoItem> +#include <QCamera> +#include <QMediaDevices> +#include <QMediaRecorder> + +QT_BEGIN_NAMESPACE +namespace Ui { class MainWindow; } + +class QMediaCaptureSession; +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + + void init(); + +private slots: + void doCamera(); + void on_startButton_clicked(); + void on_stopButton_clicked(); + void on_captureButton_clicked(); + void on_openButton_clicked(); + void on_recordButton_clicked(); + void on_camerasComboBox_textActivated(const QString &arg1); + +private: + Ui::MainWindow *ui; + + void enableButtons(bool ok); + void showFile(const QString &filename); + + QScopedPointer<QCamera> m_camera; + QMediaCaptureSession *m_captureSession; + QScopedPointer<QAudioInput> m_audioInput; + QMediaDevices *m_mediaDevices; + QMediaRecorder *m_recorder; + bool isRecording = false; +}; + +QT_END_NAMESPACE +#endif // MAINWINDOW_H diff --git a/tests/manual/wasm/camera/mainwindow.ui b/tests/manual/wasm/camera/mainwindow.ui new file mode 100644 index 000000000..b5de38348 --- /dev/null +++ b/tests/manual/wasm/camera/mainwindow.ui @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>800</width> + <height>600</height> + </rect> + </property> + <property name="windowTitle"> + <string>MainWindow</string> + </property> + <widget class="QWidget" name="centralwidget"> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QComboBox" name="camerasComboBox"> + <property name="currentIndex"> + <number>-1</number> + </property> + <item> + <property name="text"> + <string/> + </property> + </item> + </widget> + </item> + <item row="1" column="0"> + <widget class="QGraphicsView" name="graphicsView"/> + </item> + <item row="2" column="0"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QPushButton" name="startButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>start camera</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="stopButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>stop camera</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="3" column="0"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QPushButton" name="captureButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>capture photo</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="recordButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>record</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="openButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>open</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menubar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>800</width> + <height>24</height> + </rect> + </property> + </widget> + <widget class="QStatusBar" name="statusbar"/> + </widget> + <resources/> + <connections/> +</ui> |