diff options
Diffstat (limited to 'examples/multimedia')
23 files changed, 1469 insertions, 114 deletions
diff --git a/examples/multimedia/audiooutput/audiooutput.py b/examples/multimedia/audiooutput/audiooutput.py index e0634e751..06d52f68a 100644 --- a/examples/multimedia/audiooutput/audiooutput.py +++ b/examples/multimedia/audiooutput/audiooutput.py @@ -40,24 +40,23 @@ class Generator(QIODevice): sample_size = fmt.bytesPerSample() * 8 if sample_size == 8: if fmt.sampleFormat() == QAudioFormat.UInt8: - scaler = lambda x: ((1.0 + x) / 2 * 255) + scaler = lambda x: ((1.0 + x) / 2 * 255) # noqa: E731 pack_format = 'B' elif fmt.sampleFormat() == QAudioFormat.Int16: - scaler = lambda x: x * 127 + scaler = lambda x: x * 127 # noqa: E731 pack_format = 'b' elif sample_size == 16: little_endian = QSysInfo.ByteOrder == QSysInfo.LittleEndian if fmt.sampleFormat() == QAudioFormat.UInt8: - scaler = lambda x: (1.0 + x) / 2 * 65535 + scaler = lambda x: (1.0 + x) / 2 * 65535 # noqa: E731 pack_format = '<H' if little_endian else '>H' elif fmt.sampleFormat() == QAudioFormat.Int16: - scaler = lambda x: x * 32767 + scaler = lambda x: x * 32767 # noqa: E731 pack_format = '<h' if little_endian else '>h' - assert(pack_format != '') + assert pack_format != '' channel_bytes = fmt.bytesPerSample() - sample_bytes = fmt.channelCount() * channel_bytes length = (fmt.sampleRate() * fmt.channelCount() * channel_bytes) * durationUs // 100000 @@ -133,16 +132,14 @@ class AudioTest(QMainWindow): layout.addWidget(self.m_modeButton) - self.m_suspendResumeButton = QPushButton( - clicked=self.toggle_suspend_resume) + self.m_suspendResumeButton = QPushButton(clicked=self.toggle_suspend_resume) self.m_suspendResumeButton.setText(self.SUSPEND_LABEL) layout.addWidget(self.m_suspendResumeButton) volume_box = QHBoxLayout() volume_label = QLabel("Volume:") - self.m_volumeSlider = QSlider(Qt.Horizontal, minimum=0, maximum=100, - singleStep=10) + self.m_volumeSlider = QSlider(Qt.Horizontal, minimum=0, maximum=100, singleStep=10) self.m_volumeSlider.valueChanged.connect(self.volume_changed) volume_box.addWidget(volume_label) @@ -167,8 +164,8 @@ class AudioTest(QMainWindow): qWarning("Default format not supported - trying to use nearest") self.m_format = info.nearestFormat(self.m_format) - self.m_generator = Generator(self.m_format, - self.DURATION_SECONDS * 1000000, self.TONE_SAMPLE_RATE_HZ, self) + self.m_generator = Generator(self.m_format, self.DURATION_SECONDS * 1000000, + self.TONE_SAMPLE_RATE_HZ, self) self.create_audio_output() @@ -180,11 +177,18 @@ class AudioTest(QMainWindow): self.m_audioSink.start(self.m_generator) self.m_volumeSlider.setValue(self.m_audioSink.volume() * 100) - @Slot(int) - def device_changed(self, index): + def closeEvent(self, e): + self.stop() + e.accept() + + def stop(self): self.m_pullTimer.stop() self.m_generator.stop() self.m_audioSink.stop() + + @Slot(int) + def device_changed(self, index): + self.stop() self.m_device = self.m_deviceBox.itemData(index) self.create_audio_output() diff --git a/examples/multimedia/audiooutput/doc/audiooutput.rst b/examples/multimedia/audiooutput/doc/audiooutput.rst index bbd71c5d8..fac7e33e1 100644 --- a/examples/multimedia/audiooutput/doc/audiooutput.rst +++ b/examples/multimedia/audiooutput/doc/audiooutput.rst @@ -1,6 +1,8 @@ Audio Output Example ==================== +.. tags:: Android + Audio Output demonstrates the basic use cases of QAudioOutput. This example provides a tone generator to supply continuous audio playback. The diff --git a/examples/multimedia/audiosource/audiosource.py b/examples/multimedia/audiosource/audiosource.py index 5b476af9b..a78beb584 100644 --- a/examples/multimedia/audiosource/audiosource.py +++ b/examples/multimedia/audiosource/audiosource.py @@ -12,27 +12,21 @@ Note: This Python example is not fully complete as compared to its C++ counterpa Only the push mode works at the moment. For the pull mode to work, the class QIODevice have python bindings that needs to be fixed. """ +import os import sys from typing import Optional import PySide6 -from PySide6.QtCore import QByteArray, QMargins, Qt, Slot +from PySide6.QtCore import QByteArray, QMargins, Qt, Slot, qWarning from PySide6.QtGui import QPainter, QPalette -from PySide6.QtMultimedia import ( - QAudio, - QAudioDevice, - QAudioFormat, - QAudioSource, - QMediaDevices, -) -from PySide6.QtWidgets import ( - QApplication, - QComboBox, - QPushButton, - QSlider, - QVBoxLayout, - QWidget, -) +from PySide6.QtMultimedia import QAudio, QAudioDevice, QAudioFormat, QAudioSource, QMediaDevices +from PySide6.QtWidgets import (QApplication, QComboBox, QPushButton, QSlider, QVBoxLayout, + QWidget, QLabel) + +is_android = os.environ.get('ANDROID_ARGUMENT') + +if is_android or sys.platform == "darwin": + from PySide6.QtCore import QMicrophonePermission class AudioInfo: @@ -95,6 +89,28 @@ class InputTest(QWidget): super().__init__() self.m_devices = QMediaDevices(self) self.m_pullMode = False + self.initialize() + + @Slot() + def initialize(self): + if is_android or sys.platform == "darwin": + is_nuitka = "__compiled__" in globals() + if not is_nuitka and sys.platform == "darwin": + print("This example does not work on macOS when Python is run in interpreted mode." + "For this example to work on macOS, package the example using pyside6-deploy" + "For more information, read `Notes for Developer` in the documentation") + sys.exit(0) + permission = QMicrophonePermission() + permission_status = qApp.checkPermission(permission) # noqa: F821 + if permission_status == Qt.PermissionStatus.Undetermined: + qApp.requestPermission(permission, self, self.initialize) # noqa: F821 + return + if permission_status == Qt.PermissionStatus.Denied: + qWarning("Microphone permission is not granted!") + self.initializeErrorWindow() + return + elif permission_status == Qt.PermissionStatus.Granted: + print("[AudioSource] Microphone permission granted") self.initialize_window() self.initialize_audio(QMediaDevices.defaultAudioInput()) @@ -132,6 +148,13 @@ class InputTest(QWidget): self.m_suspend_resume_button.clicked.connect(self.toggle_suspend) self.layout.addWidget(self.m_suspend_resume_button) + def initializeErrorWindow(self): + self.layout = QVBoxLayout(self) + error_label = QLabel(self.tr("Microphone permission is not granted!")) + error_label.setWordWrap(True) + error_label.setAlignment(Qt.AlignCenter) + self.layout.addWidget(error_label) + def initialize_audio(self, device_info: QAudioDevice): format = QAudioFormat() format.setSampleRate(8000) diff --git a/examples/multimedia/audiosource/doc/audiosource.rst b/examples/multimedia/audiosource/doc/audiosource.rst index b1dcd61a8..3a247c503 100644 --- a/examples/multimedia/audiosource/doc/audiosource.rst +++ b/examples/multimedia/audiosource/doc/audiosource.rst @@ -1,6 +1,8 @@ Audio Source Example ==================== +.. tags:: Android + A Python application that demonstrates the analogous example in C++ `Audio Source Example <https://doc-snapshots.qt.io/qt6-dev/qtmultimedia-multimedia-audiosource-example.html>`_ diff --git a/examples/multimedia/camera/camera.py b/examples/multimedia/camera/camera.py index 95d33243e..fa379c807 100644 --- a/examples/multimedia/camera/camera.py +++ b/examples/multimedia/camera/camera.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause import os +import sys from pathlib import Path from PySide6.QtMultimedia import (QAudioInput, QCamera, QCameraDevice, @@ -10,12 +11,19 @@ from PySide6.QtMultimedia import (QAudioInput, QCamera, QCameraDevice, QMediaRecorder) from PySide6.QtWidgets import QDialog, QMainWindow, QMessageBox from PySide6.QtGui import QAction, QActionGroup, QIcon, QImage, QPixmap -from PySide6.QtCore import QDateTime, QDir, QTimer, Qt, Slot +from PySide6.QtCore import QDateTime, QDir, QTimer, Qt, Slot, qWarning -from ui_camera import Ui_Camera from metadatadialog import MetaDataDialog from imagesettings import ImageSettings -from videosettings import VideoSettings +from videosettings import VideoSettings, is_android + +if is_android or sys.platform == "darwin": + from PySide6.QtCore import QMicrophonePermission, QCameraPermission + +if is_android: + from ui_camera_mobile import Ui_Camera +else: + from ui_camera import Ui_Camera class Camera(QMainWindow): @@ -23,13 +31,10 @@ class Camera(QMainWindow): super().__init__() self._video_devices_group = None - self.m_devices = QMediaDevices() self.m_imageCapture = None self.m_captureSession = QMediaCaptureSession() self.m_camera = None - self.m_audioInput = QAudioInput() - self.m_captureSession.setAudioInput(self.m_audioInput) self.m_mediaRecorder = None self.m_isCapturingImage = False @@ -42,7 +47,8 @@ class Camera(QMainWindow): self._ui.setupUi(self) image = Path(__file__).parent / "shutter.svg" self._ui.takeImageButton.setIcon(QIcon(os.fspath(image))) - self._ui.actionAbout_Qt.triggered.connect(qApp.aboutQt) + if not is_android: + self._ui.actionAbout_Qt.triggered.connect(qApp.aboutQt) # noqa: F821 # disable all buttons by default self.updateCameraActive(False) @@ -53,6 +59,47 @@ class Camera(QMainWindow): self._ui.metaDataButton.setEnabled(False) # try to actually initialize camera & mic + self.initialize() + + @Slot() + def initialize(self): + if is_android or sys.platform == "darwin": + is_nuitka = "__compiled__" in globals() + if not is_nuitka and sys.platform == "darwin": + print("This example does not work on macOS when Python is run in interpreted mode." + "For this example to work on macOS, package the example using pyside6-deploy" + "For more information, read `Notes for Developer` in the documentation") + sys.exit(0) + + # camera + cam_permission = QCameraPermission() + cam_permission_status = qApp.checkPermission(cam_permission) # noqa: F821 + if cam_permission_status == Qt.PermissionStatus.Undetermined: + qApp.requestPermission(cam_permission, self, self.initialize) # noqa: F821 + return + if cam_permission_status == Qt.PermissionStatus.Denied: + qWarning("Camera permission is not granted!") + return + elif cam_permission_status == Qt.PermissionStatus.Granted: + print("[AudioSource] Camera permission granted") + + # microphone + microphone_permission = QMicrophonePermission() + microphone_permission_status = qApp.checkPermission(microphone_permission) # noqa: F821 + if microphone_permission_status == Qt.PermissionStatus.Undetermined: + qApp.requestPermission(microphone_permission, self, self.initialize) # noqa: F821 + return + if microphone_permission_status == Qt.PermissionStatus.Denied: + qWarning("Microphone permission is not granted!") + self.initializeErrorWindow() + return + elif microphone_permission_status == Qt.PermissionStatus.Granted: + print("[AudioSource] Microphone permission granted") + + self.m_audioInput = QAudioInput() + self.m_captureSession.setAudioInput(self.m_audioInput) + + # Camera devices self._video_devices_group = QActionGroup(self) self._video_devices_group.setExclusive(True) diff --git a/examples/multimedia/camera/camera.pyproject b/examples/multimedia/camera/camera.pyproject index 9b4171d9a..9067b1dfa 100644 --- a/examples/multimedia/camera/camera.pyproject +++ b/examples/multimedia/camera/camera.pyproject @@ -2,9 +2,11 @@ "files": ["main.py", "camera.py", "camera.ui", + "camera_mobile.ui", "imagesettings.py", "imagesettings.ui", "metadatadialog.py", "videosettings.py", - "videosettings.ui"] + "videosettings.ui", + "videosettings_mobile.ui"] } diff --git a/examples/multimedia/camera/camera_mobile.ui b/examples/multimedia/camera/camera_mobile.ui new file mode 100644 index 000000000..7f269b17b --- /dev/null +++ b/examples/multimedia/camera/camera_mobile.ui @@ -0,0 +1,504 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Camera</class> + <widget class="QMainWindow" name="Camera"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>668</width> + <height>429</height> + </rect> + </property> + <property name="windowTitle"> + <string>Camera</string> + </property> + <widget class="QWidget" name="centralwidget"> + <layout class="QGridLayout" name="gridLayout_3"> + <item row="1" column="1" colspan="2"> + <widget class="QTabWidget" name="captureWidget"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="tab_2"> + <attribute name="title"> + <string>Image</string> + </attribute> + <layout class="QGridLayout" name="gridLayout"> + <item row="4" column="0"> + <widget class="QSlider" name="exposureCompensation"> + <property name="minimum"> + <number>-4</number> + </property> + <property name="maximum"> + <number>4</number> + </property> + <property name="pageStep"> + <number>2</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksAbove</enum> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Exposure Compensation:</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QPushButton" name="takeImageButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Capture Photo</string> + </property> + <property name="icon"> + <iconset> + <normaloff>:/images/shutter.svg</normaloff>:/images/shutter.svg</iconset> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab"> + <attribute name="title"> + <string>Video</string> + </attribute> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QPushButton" name="recordButton"> + <property name="text"> + <string>Record</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pauseButton"> + <property name="text"> + <string>Pause</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="stopButton"> + <property name="text"> + <string>Stop</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>10</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="muteButton"> + <property name="text"> + <string>Mute</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="metaDataButton"> + <property name="text"> + <string>Set metadata</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + </item> + <item row="0" column="2"> + <widget class="QStackedWidget" name="stackedWidget"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="palette"> + <palette> + <active> + <colorrole role="Base"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </brush> + </colorrole> + <colorrole role="Window"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> + <red>145</red> + <green>145</green> + <blue>145</blue> + </color> + </brush> + </colorrole> + </active> + <inactive> + <colorrole role="Base"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </brush> + </colorrole> + <colorrole role="Window"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> + <red>145</red> + <green>145</green> + <blue>145</blue> + </color> + </brush> + </colorrole> + </inactive> + <disabled> + <colorrole role="Base"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> + <red>145</red> + <green>145</green> + <blue>145</blue> + </color> + </brush> + </colorrole> + <colorrole role="Window"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> + <red>145</red> + <green>145</green> + <blue>145</blue> + </color> + </brush> + </colorrole> + </disabled> + </palette> + </property> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="viewfinderPage"> + <layout class="QGridLayout" name="gridLayout_5"> + <item row="0" column="0"> + <widget class="QVideoWidget" name="viewfinder" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="previewPage"> + <layout class="QGridLayout" name="gridLayout_4"> + <item row="0" column="0"> + <widget class="QLabel" name="lastImagePreviewLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::Box</enum> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menubar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>668</width> + <height>22</height> + </rect> + </property> + <widget class="QMenu" name="menuFile"> + <property name="title"> + <string>File</string> + </property> + <addaction name="actionStartCamera"/> + <addaction name="actionStopCamera"/> + <addaction name="separator"/> + <addaction name="actionSettings"/> + <addaction name="separator"/> + <addaction name="actionExit"/> + </widget> + <widget class="QMenu" name="menuDevices"> + <property name="title"> + <string>Devices</string> + </property> + </widget> + <addaction name="menuFile"/> + <addaction name="menuDevices"/> + </widget> + <widget class="QStatusBar" name="statusbar"/> + <action name="actionExit"> + <property name="text"> + <string>Close</string> + </property> + </action> + <action name="actionStartCamera"> + <property name="text"> + <string>Start Camera</string> + </property> + </action> + <action name="actionStopCamera"> + <property name="text"> + <string>Stop Camera</string> + </property> + </action> + <action name="actionSettings"> + <property name="text"> + <string>Change Settings</string> + </property> + </action> + </widget> + <customwidgets> + <customwidget> + <class>QVideoWidget</class> + <extends>QWidget</extends> + <header>qvideowidget.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections> + <connection> + <sender>recordButton</sender> + <signal>clicked()</signal> + <receiver>Camera</receiver> + <slot>record()</slot> + <hints> + <hint type="sourcelabel"> + <x>647</x> + <y>149</y> + </hint> + <hint type="destinationlabel"> + <x>61</x> + <y>238</y> + </hint> + </hints> + </connection> + <connection> + <sender>stopButton</sender> + <signal>clicked()</signal> + <receiver>Camera</receiver> + <slot>stop()</slot> + <hints> + <hint type="sourcelabel"> + <x>647</x> + <y>225</y> + </hint> + <hint type="destinationlabel"> + <x>140</x> + <y>236</y> + </hint> + </hints> + </connection> + <connection> + <sender>pauseButton</sender> + <signal>clicked()</signal> + <receiver>Camera</receiver> + <slot>pause()</slot> + <hints> + <hint type="sourcelabel"> + <x>647</x> + <y>187</y> + </hint> + <hint type="destinationlabel"> + <x>234</x> + <y>237</y> + </hint> + </hints> + </connection> + <connection> + <sender>actionExit</sender> + <signal>triggered()</signal> + <receiver>Camera</receiver> + <slot>close()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>154</x> + <y>130</y> + </hint> + </hints> + </connection> + <connection> + <sender>takeImageButton</sender> + <signal>clicked()</signal> + <receiver>Camera</receiver> + <slot>takeImage()</slot> + <hints> + <hint type="sourcelabel"> + <x>625</x> + <y>132</y> + </hint> + <hint type="destinationlabel"> + <x>603</x> + <y>169</y> + </hint> + </hints> + </connection> + <connection> + <sender>muteButton</sender> + <signal>toggled(bool)</signal> + <receiver>Camera</receiver> + <slot>setMuted(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>647</x> + <y>377</y> + </hint> + <hint type="destinationlabel"> + <x>5</x> + <y>280</y> + </hint> + </hints> + </connection> + <connection> + <sender>exposureCompensation</sender> + <signal>valueChanged(int)</signal> + <receiver>Camera</receiver> + <slot>setExposureCompensation(int)</slot> + <hints> + <hint type="sourcelabel"> + <x>559</x> + <y>367</y> + </hint> + <hint type="destinationlabel"> + <x>665</x> + <y>365</y> + </hint> + </hints> + </connection> + <connection> + <sender>actionSettings</sender> + <signal>triggered()</signal> + <receiver>Camera</receiver> + <slot>configureCaptureSettings()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>333</x> + <y>210</y> + </hint> + </hints> + </connection> + <connection> + <sender>actionStartCamera</sender> + <signal>triggered()</signal> + <receiver>Camera</receiver> + <slot>startCamera()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>333</x> + <y>210</y> + </hint> + </hints> + </connection> + <connection> + <sender>actionStopCamera</sender> + <signal>triggered()</signal> + <receiver>Camera</receiver> + <slot>stopCamera()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>333</x> + <y>210</y> + </hint> + </hints> + </connection> + </connections> + <slots> + <slot>record()</slot> + <slot>pause()</slot> + <slot>stop()</slot> + <slot>enablePreview(bool)</slot> + <slot>configureCaptureSettings()</slot> + <slot>takeImage()</slot> + <slot>startCamera()</slot> + <slot>toggleLock()</slot> + <slot>setMuted(bool)</slot> + <slot>stopCamera()</slot> + <slot>setExposureCompensation(int)</slot> + </slots> +</ui> diff --git a/examples/multimedia/camera/doc/camera.rst b/examples/multimedia/camera/doc/camera.rst index 8ef9f6700..7fc75a387 100644 --- a/examples/multimedia/camera/doc/camera.rst +++ b/examples/multimedia/camera/doc/camera.rst @@ -1,6 +1,8 @@ Camera Example =============== +.. tags:: Android + The Camera Example shows how to use the API to capture a still image or video. The Camera Example demonstrates how you can use Qt Multimedia to implement some diff --git a/examples/multimedia/camera/ui_camera.py b/examples/multimedia/camera/ui_camera.py index 92e115c77..690cf3352 100644 --- a/examples/multimedia/camera/ui_camera.py +++ b/examples/multimedia/camera/ui_camera.py @@ -3,7 +3,7 @@ ################################################################################ ## Form generated from reading UI file 'camera.ui' ## -## Created by: Qt User Interface Compiler version 6.5.0 +## Created by: Qt User Interface Compiler version 6.7.0 ## ## WARNING! All changes made in this file will be lost when recompiling UI file! ################################################################################ @@ -47,7 +47,7 @@ class Ui_Camera(object): self.tab_2.setObjectName(u"tab_2") self.gridLayout = QGridLayout(self.tab_2) self.gridLayout.setObjectName(u"gridLayout") - self.verticalSpacer_2 = QSpacerItem(20, 161, QSizePolicy.Minimum, QSizePolicy.Expanding) + self.verticalSpacer_2 = QSpacerItem(20, 161, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) self.gridLayout.addItem(self.verticalSpacer_2, 3, 0, 1, 1) @@ -92,7 +92,7 @@ class Ui_Camera(object): self.gridLayout_2.addWidget(self.stopButton, 2, 0, 1, 1) - self.verticalSpacer = QSpacerItem(20, 76, QSizePolicy.Minimum, QSizePolicy.Expanding) + self.verticalSpacer = QSpacerItem(20, 76, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) self.gridLayout_2.addItem(self.verticalSpacer, 3, 0, 1, 1) @@ -114,7 +114,7 @@ class Ui_Camera(object): self.stackedWidget = QStackedWidget(self.centralwidget) self.stackedWidget.setObjectName(u"stackedWidget") - sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) + sizePolicy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.stackedWidget.sizePolicy().hasHeightForWidth()) @@ -147,7 +147,7 @@ class Ui_Camera(object): self.gridLayout_4.setObjectName(u"gridLayout_4") self.lastImagePreviewLabel = QLabel(self.previewPage) self.lastImagePreviewLabel.setObjectName(u"lastImagePreviewLabel") - sizePolicy1 = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.MinimumExpanding) + sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.MinimumExpanding) sizePolicy1.setHorizontalStretch(0) sizePolicy1.setVerticalStretch(0) sizePolicy1.setHeightForWidth(self.lastImagePreviewLabel.sizePolicy().hasHeightForWidth()) diff --git a/examples/multimedia/camera/ui_camera_mobile.py b/examples/multimedia/camera/ui_camera_mobile.py new file mode 100644 index 000000000..5cdd81f1e --- /dev/null +++ b/examples/multimedia/camera/ui_camera_mobile.py @@ -0,0 +1,251 @@ +# -*- coding: utf-8 -*- + +################################################################################ +## Form generated from reading UI file 'camera_mobile.ui' +## +## Created by: Qt User Interface Compiler version 6.7.0 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, + QMetaObject, QObject, QPoint, QRect, + QSize, QTime, QUrl, Qt) +from PySide6.QtGui import (QAction, QBrush, QColor, QConicalGradient, + QCursor, QFont, QFontDatabase, QGradient, + QIcon, QImage, QKeySequence, QLinearGradient, + QPainter, QPalette, QPixmap, QRadialGradient, + QTransform) +from PySide6.QtMultimediaWidgets import QVideoWidget +from PySide6.QtWidgets import (QApplication, QFrame, QGridLayout, QHBoxLayout, + QLabel, QMainWindow, QMenu, QMenuBar, + QPushButton, QSizePolicy, QSlider, QSpacerItem, + QStackedWidget, QStatusBar, QTabWidget, QVBoxLayout, + QWidget) + +class Ui_Camera(object): + def setupUi(self, Camera): + if not Camera.objectName(): + Camera.setObjectName(u"Camera") + Camera.resize(668, 429) + self.actionExit = QAction(Camera) + self.actionExit.setObjectName(u"actionExit") + self.actionStartCamera = QAction(Camera) + self.actionStartCamera.setObjectName(u"actionStartCamera") + self.actionStopCamera = QAction(Camera) + self.actionStopCamera.setObjectName(u"actionStopCamera") + self.actionSettings = QAction(Camera) + self.actionSettings.setObjectName(u"actionSettings") + self.centralwidget = QWidget(Camera) + self.centralwidget.setObjectName(u"centralwidget") + self.gridLayout_3 = QGridLayout(self.centralwidget) + self.gridLayout_3.setObjectName(u"gridLayout_3") + self.captureWidget = QTabWidget(self.centralwidget) + self.captureWidget.setObjectName(u"captureWidget") + sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.captureWidget.sizePolicy().hasHeightForWidth()) + self.captureWidget.setSizePolicy(sizePolicy) + self.tab_2 = QWidget() + self.tab_2.setObjectName(u"tab_2") + self.gridLayout = QGridLayout(self.tab_2) + self.gridLayout.setObjectName(u"gridLayout") + self.exposureCompensation = QSlider(self.tab_2) + self.exposureCompensation.setObjectName(u"exposureCompensation") + self.exposureCompensation.setMinimum(-4) + self.exposureCompensation.setMaximum(4) + self.exposureCompensation.setPageStep(2) + self.exposureCompensation.setOrientation(Qt.Horizontal) + self.exposureCompensation.setTickPosition(QSlider.TicksAbove) + + self.gridLayout.addWidget(self.exposureCompensation, 4, 0, 1, 1) + + self.label = QLabel(self.tab_2) + self.label.setObjectName(u"label") + sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed) + sizePolicy1.setHorizontalStretch(0) + sizePolicy1.setVerticalStretch(0) + sizePolicy1.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) + self.label.setSizePolicy(sizePolicy1) + + self.gridLayout.addWidget(self.label, 3, 0, 1, 1) + + self.takeImageButton = QPushButton(self.tab_2) + self.takeImageButton.setObjectName(u"takeImageButton") + self.takeImageButton.setEnabled(False) + icon = QIcon() + icon.addFile(u":/images/shutter.svg", QSize(), QIcon.Normal, QIcon.Off) + self.takeImageButton.setIcon(icon) + + self.gridLayout.addWidget(self.takeImageButton, 0, 0, 1, 1) + + self.captureWidget.addTab(self.tab_2, "") + self.tab = QWidget() + self.tab.setObjectName(u"tab") + self.gridLayout_2 = QGridLayout(self.tab) + self.gridLayout_2.setObjectName(u"gridLayout_2") + self.horizontalLayout = QHBoxLayout() + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.verticalLayout = QVBoxLayout() + self.verticalLayout.setObjectName(u"verticalLayout") + self.recordButton = QPushButton(self.tab) + self.recordButton.setObjectName(u"recordButton") + + self.verticalLayout.addWidget(self.recordButton) + + self.pauseButton = QPushButton(self.tab) + self.pauseButton.setObjectName(u"pauseButton") + + self.verticalLayout.addWidget(self.pauseButton) + + self.stopButton = QPushButton(self.tab) + self.stopButton.setObjectName(u"stopButton") + + self.verticalLayout.addWidget(self.stopButton) + + + self.horizontalLayout.addLayout(self.verticalLayout) + + self.verticalLayout_2 = QVBoxLayout() + self.verticalLayout_2.setObjectName(u"verticalLayout_2") + self.verticalSpacer = QSpacerItem(20, 10, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) + + self.verticalLayout_2.addItem(self.verticalSpacer) + + self.muteButton = QPushButton(self.tab) + self.muteButton.setObjectName(u"muteButton") + self.muteButton.setCheckable(True) + + self.verticalLayout_2.addWidget(self.muteButton) + + self.metaDataButton = QPushButton(self.tab) + self.metaDataButton.setObjectName(u"metaDataButton") + self.metaDataButton.setCheckable(True) + + self.verticalLayout_2.addWidget(self.metaDataButton) + + + self.horizontalLayout.addLayout(self.verticalLayout_2) + + + self.gridLayout_2.addLayout(self.horizontalLayout, 0, 0, 1, 1) + + self.captureWidget.addTab(self.tab, "") + + self.gridLayout_3.addWidget(self.captureWidget, 1, 1, 1, 2) + + self.stackedWidget = QStackedWidget(self.centralwidget) + self.stackedWidget.setObjectName(u"stackedWidget") + sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + sizePolicy2.setHorizontalStretch(1) + sizePolicy2.setVerticalStretch(0) + sizePolicy2.setHeightForWidth(self.stackedWidget.sizePolicy().hasHeightForWidth()) + self.stackedWidget.setSizePolicy(sizePolicy2) + palette = QPalette() + brush = QBrush(QColor(255, 255, 255, 255)) + brush.setStyle(Qt.SolidPattern) + palette.setBrush(QPalette.Active, QPalette.Base, brush) + brush1 = QBrush(QColor(145, 145, 145, 255)) + brush1.setStyle(Qt.SolidPattern) + palette.setBrush(QPalette.Active, QPalette.Window, brush1) + palette.setBrush(QPalette.Inactive, QPalette.Base, brush) + palette.setBrush(QPalette.Inactive, QPalette.Window, brush1) + palette.setBrush(QPalette.Disabled, QPalette.Base, brush1) + palette.setBrush(QPalette.Disabled, QPalette.Window, brush1) + self.stackedWidget.setPalette(palette) + self.viewfinderPage = QWidget() + self.viewfinderPage.setObjectName(u"viewfinderPage") + self.gridLayout_5 = QGridLayout(self.viewfinderPage) + self.gridLayout_5.setObjectName(u"gridLayout_5") + self.viewfinder = QVideoWidget(self.viewfinderPage) + self.viewfinder.setObjectName(u"viewfinder") + sizePolicy3 = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + sizePolicy3.setHorizontalStretch(0) + sizePolicy3.setVerticalStretch(0) + sizePolicy3.setHeightForWidth(self.viewfinder.sizePolicy().hasHeightForWidth()) + self.viewfinder.setSizePolicy(sizePolicy3) + + self.gridLayout_5.addWidget(self.viewfinder, 0, 0, 1, 1) + + self.stackedWidget.addWidget(self.viewfinderPage) + self.previewPage = QWidget() + self.previewPage.setObjectName(u"previewPage") + self.gridLayout_4 = QGridLayout(self.previewPage) + self.gridLayout_4.setObjectName(u"gridLayout_4") + self.lastImagePreviewLabel = QLabel(self.previewPage) + self.lastImagePreviewLabel.setObjectName(u"lastImagePreviewLabel") + sizePolicy4 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.MinimumExpanding) + sizePolicy4.setHorizontalStretch(0) + sizePolicy4.setVerticalStretch(0) + sizePolicy4.setHeightForWidth(self.lastImagePreviewLabel.sizePolicy().hasHeightForWidth()) + self.lastImagePreviewLabel.setSizePolicy(sizePolicy4) + self.lastImagePreviewLabel.setFrameShape(QFrame.Box) + + self.gridLayout_4.addWidget(self.lastImagePreviewLabel, 0, 0, 1, 1) + + self.stackedWidget.addWidget(self.previewPage) + + self.gridLayout_3.addWidget(self.stackedWidget, 0, 2, 1, 1) + + Camera.setCentralWidget(self.centralwidget) + self.menubar = QMenuBar(Camera) + self.menubar.setObjectName(u"menubar") + self.menubar.setGeometry(QRect(0, 0, 668, 22)) + self.menuFile = QMenu(self.menubar) + self.menuFile.setObjectName(u"menuFile") + self.menuDevices = QMenu(self.menubar) + self.menuDevices.setObjectName(u"menuDevices") + Camera.setMenuBar(self.menubar) + self.statusbar = QStatusBar(Camera) + self.statusbar.setObjectName(u"statusbar") + Camera.setStatusBar(self.statusbar) + + self.menubar.addAction(self.menuFile.menuAction()) + self.menubar.addAction(self.menuDevices.menuAction()) + self.menuFile.addAction(self.actionStartCamera) + self.menuFile.addAction(self.actionStopCamera) + self.menuFile.addSeparator() + self.menuFile.addAction(self.actionSettings) + self.menuFile.addSeparator() + self.menuFile.addAction(self.actionExit) + + self.retranslateUi(Camera) + self.recordButton.clicked.connect(Camera.record) + self.stopButton.clicked.connect(Camera.stop) + self.pauseButton.clicked.connect(Camera.pause) + self.actionExit.triggered.connect(Camera.close) + self.takeImageButton.clicked.connect(Camera.takeImage) + self.muteButton.toggled.connect(Camera.setMuted) + self.exposureCompensation.valueChanged.connect(Camera.setExposureCompensation) + self.actionSettings.triggered.connect(Camera.configureCaptureSettings) + self.actionStartCamera.triggered.connect(Camera.startCamera) + self.actionStopCamera.triggered.connect(Camera.stopCamera) + + self.captureWidget.setCurrentIndex(0) + self.stackedWidget.setCurrentIndex(0) + + + QMetaObject.connectSlotsByName(Camera) + # setupUi + + def retranslateUi(self, Camera): + Camera.setWindowTitle(QCoreApplication.translate("Camera", u"Camera", None)) + self.actionExit.setText(QCoreApplication.translate("Camera", u"Close", None)) + self.actionStartCamera.setText(QCoreApplication.translate("Camera", u"Start Camera", None)) + self.actionStopCamera.setText(QCoreApplication.translate("Camera", u"Stop Camera", None)) + self.actionSettings.setText(QCoreApplication.translate("Camera", u"Change Settings", None)) + self.label.setText(QCoreApplication.translate("Camera", u"Exposure Compensation:", None)) + self.takeImageButton.setText(QCoreApplication.translate("Camera", u"Capture Photo", None)) + self.captureWidget.setTabText(self.captureWidget.indexOf(self.tab_2), QCoreApplication.translate("Camera", u"Image", None)) + self.recordButton.setText(QCoreApplication.translate("Camera", u"Record", None)) + self.pauseButton.setText(QCoreApplication.translate("Camera", u"Pause", None)) + self.stopButton.setText(QCoreApplication.translate("Camera", u"Stop", None)) + self.muteButton.setText(QCoreApplication.translate("Camera", u"Mute", None)) + self.metaDataButton.setText(QCoreApplication.translate("Camera", u"Set metadata", None)) + self.captureWidget.setTabText(self.captureWidget.indexOf(self.tab), QCoreApplication.translate("Camera", u"Video", None)) + self.lastImagePreviewLabel.setText("") + self.menuFile.setTitle(QCoreApplication.translate("Camera", u"File", None)) + self.menuDevices.setTitle(QCoreApplication.translate("Camera", u"Devices", None)) + # retranslateUi + diff --git a/examples/multimedia/camera/ui_imagesettings.py b/examples/multimedia/camera/ui_imagesettings.py index aa7505f8f..a3fba7789 100644 --- a/examples/multimedia/camera/ui_imagesettings.py +++ b/examples/multimedia/camera/ui_imagesettings.py @@ -3,7 +3,7 @@ ################################################################################ ## Form generated from reading UI file 'imagesettings.ui' ## -## Created by: Qt User Interface Compiler version 6.5.0 +## Created by: Qt User Interface Compiler version 6.7.0 ## ## WARNING! All changes made in this file will be lost when recompiling UI file! ################################################################################ @@ -65,7 +65,7 @@ class Ui_ImageSettingsUi(object): self.gridLayout.addWidget(self.groupBox_2, 0, 0, 1, 1) - self.verticalSpacer = QSpacerItem(20, 14, QSizePolicy.Minimum, QSizePolicy.Expanding) + self.verticalSpacer = QSpacerItem(20, 14, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) self.gridLayout.addItem(self.verticalSpacer, 1, 0, 1, 1) diff --git a/examples/multimedia/camera/ui_videosettings.py b/examples/multimedia/camera/ui_videosettings.py index c84c93d78..eec626f27 100644 --- a/examples/multimedia/camera/ui_videosettings.py +++ b/examples/multimedia/camera/ui_videosettings.py @@ -3,7 +3,7 @@ ################################################################################ ## Form generated from reading UI file 'videosettings.ui' ## -## Created by: Qt User Interface Compiler version 6.5.0 +## Created by: Qt User Interface Compiler version 6.7.0 ## ## WARNING! All changes made in this file will be lost when recompiling UI file! ################################################################################ @@ -84,7 +84,7 @@ class Ui_VideoSettingsUi(object): self.widget = QWidget(VideoSettingsUi) self.widget.setObjectName(u"widget") - sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) + sizePolicy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.widget.sizePolicy().hasHeightForWidth()) @@ -151,7 +151,7 @@ class Ui_VideoSettingsUi(object): self.gridLayout_3.addWidget(self.widget, 2, 0, 1, 1) - self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) + self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) self.gridLayout_3.addItem(self.verticalSpacer, 3, 0, 1, 1) diff --git a/examples/multimedia/camera/ui_videosettings_mobile.py b/examples/multimedia/camera/ui_videosettings_mobile.py new file mode 100644 index 000000000..50fb8e081 --- /dev/null +++ b/examples/multimedia/camera/ui_videosettings_mobile.py @@ -0,0 +1,176 @@ +# -*- coding: utf-8 -*- + +################################################################################ +## Form generated from reading UI file 'videosettings_mobile.ui' +## +## Created by: Qt User Interface Compiler version 6.7.0 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, + QMetaObject, QObject, QPoint, QRect, + QSize, QTime, QUrl, Qt) +from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, + QFont, QFontDatabase, QGradient, QIcon, + QImage, QKeySequence, QLinearGradient, QPainter, + QPalette, QPixmap, QRadialGradient, QTransform) +from PySide6.QtWidgets import (QAbstractButton, QApplication, QComboBox, QDialog, + QDialogButtonBox, QGridLayout, QGroupBox, QHBoxLayout, + QLabel, QSizePolicy, QSlider, QSpinBox, + QVBoxLayout, QWidget) + +class Ui_VideoSettingsUi(object): + def setupUi(self, VideoSettingsUi): + if not VideoSettingsUi.objectName(): + VideoSettingsUi.setObjectName(u"VideoSettingsUi") + VideoSettingsUi.resize(329, 591) + self.gridLayout_3 = QGridLayout(VideoSettingsUi) + self.gridLayout_3.setObjectName(u"gridLayout_3") + self.widget = QWidget(VideoSettingsUi) + self.widget.setObjectName(u"widget") + sizePolicy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.widget.sizePolicy().hasHeightForWidth()) + self.widget.setSizePolicy(sizePolicy) + self.verticalLayout_3 = QVBoxLayout(self.widget) + self.verticalLayout_3.setObjectName(u"verticalLayout_3") + self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) + self.groupBox_3 = QGroupBox(self.widget) + self.groupBox_3.setObjectName(u"groupBox_3") + self.verticalLayout_2 = QVBoxLayout(self.groupBox_3) + self.verticalLayout_2.setObjectName(u"verticalLayout_2") + self.label_2 = QLabel(self.groupBox_3) + self.label_2.setObjectName(u"label_2") + + self.verticalLayout_2.addWidget(self.label_2) + + self.audioCodecBox = QComboBox(self.groupBox_3) + self.audioCodecBox.setObjectName(u"audioCodecBox") + + self.verticalLayout_2.addWidget(self.audioCodecBox) + + self.label_5 = QLabel(self.groupBox_3) + self.label_5.setObjectName(u"label_5") + + self.verticalLayout_2.addWidget(self.label_5) + + self.audioSampleRateBox = QSpinBox(self.groupBox_3) + self.audioSampleRateBox.setObjectName(u"audioSampleRateBox") + + self.verticalLayout_2.addWidget(self.audioSampleRateBox) + + + self.verticalLayout_3.addWidget(self.groupBox_3) + + self.groupBox = QGroupBox(self.widget) + self.groupBox.setObjectName(u"groupBox") + self.verticalLayout = QVBoxLayout(self.groupBox) + self.verticalLayout.setObjectName(u"verticalLayout") + self.label_3 = QLabel(self.groupBox) + self.label_3.setObjectName(u"label_3") + + self.verticalLayout.addWidget(self.label_3) + + self.qualitySlider = QSlider(self.groupBox) + self.qualitySlider.setObjectName(u"qualitySlider") + self.qualitySlider.setMaximum(4) + self.qualitySlider.setOrientation(Qt.Horizontal) + + self.verticalLayout.addWidget(self.qualitySlider) + + self.label_4 = QLabel(self.groupBox) + self.label_4.setObjectName(u"label_4") + + self.verticalLayout.addWidget(self.label_4) + + self.containerFormatBox = QComboBox(self.groupBox) + self.containerFormatBox.setObjectName(u"containerFormatBox") + + self.verticalLayout.addWidget(self.containerFormatBox) + + + self.verticalLayout_3.addWidget(self.groupBox) + + + self.gridLayout_3.addWidget(self.widget, 2, 0, 1, 1) + + self.groupBox_2 = QGroupBox(VideoSettingsUi) + self.groupBox_2.setObjectName(u"groupBox_2") + self.gridLayout_2 = QGridLayout(self.groupBox_2) + self.gridLayout_2.setObjectName(u"gridLayout_2") + self.label = QLabel(self.groupBox_2) + self.label.setObjectName(u"label") + + self.gridLayout_2.addWidget(self.label, 2, 0, 1, 1) + + self.videoCodecBox = QComboBox(self.groupBox_2) + self.videoCodecBox.setObjectName(u"videoCodecBox") + + self.gridLayout_2.addWidget(self.videoCodecBox, 6, 0, 1, 2) + + self.label_8 = QLabel(self.groupBox_2) + self.label_8.setObjectName(u"label_8") + + self.gridLayout_2.addWidget(self.label_8, 0, 0, 1, 2) + + self.label_6 = QLabel(self.groupBox_2) + self.label_6.setObjectName(u"label_6") + + self.gridLayout_2.addWidget(self.label_6, 5, 0, 1, 2) + + self.videoFormatBox = QComboBox(self.groupBox_2) + self.videoFormatBox.setObjectName(u"videoFormatBox") + + self.gridLayout_2.addWidget(self.videoFormatBox, 1, 0, 1, 2) + + self.buttonBox = QDialogButtonBox(self.groupBox_2) + self.buttonBox.setObjectName(u"buttonBox") + self.buttonBox.setOrientation(Qt.Horizontal) + self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok) + + self.gridLayout_2.addWidget(self.buttonBox, 7, 0, 1, 1) + + self.horizontalLayout = QHBoxLayout() + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.fpsSpinBox = QSpinBox(self.groupBox_2) + self.fpsSpinBox.setObjectName(u"fpsSpinBox") + self.fpsSpinBox.setMinimum(8) + self.fpsSpinBox.setMaximum(30) + + self.horizontalLayout.addWidget(self.fpsSpinBox) + + self.fpsSlider = QSlider(self.groupBox_2) + self.fpsSlider.setObjectName(u"fpsSlider") + self.fpsSlider.setOrientation(Qt.Horizontal) + + self.horizontalLayout.addWidget(self.fpsSlider) + + + self.gridLayout_2.addLayout(self.horizontalLayout, 3, 0, 1, 1) + + + self.gridLayout_3.addWidget(self.groupBox_2, 3, 0, 1, 1) + + + self.retranslateUi(VideoSettingsUi) + self.buttonBox.accepted.connect(VideoSettingsUi.accept) + self.buttonBox.rejected.connect(VideoSettingsUi.reject) + + QMetaObject.connectSlotsByName(VideoSettingsUi) + # setupUi + + def retranslateUi(self, VideoSettingsUi): + VideoSettingsUi.setWindowTitle(QCoreApplication.translate("VideoSettingsUi", u"Video Settings", None)) + self.groupBox_3.setTitle(QCoreApplication.translate("VideoSettingsUi", u"Audio", None)) + self.label_2.setText(QCoreApplication.translate("VideoSettingsUi", u"Audio Codec:", None)) + self.label_5.setText(QCoreApplication.translate("VideoSettingsUi", u"Sample Rate:", None)) + self.label_3.setText(QCoreApplication.translate("VideoSettingsUi", u"Quality:", None)) + self.label_4.setText(QCoreApplication.translate("VideoSettingsUi", u"File Format:", None)) + self.groupBox_2.setTitle(QCoreApplication.translate("VideoSettingsUi", u"Video", None)) + self.label.setText(QCoreApplication.translate("VideoSettingsUi", u"Frames per second:", None)) + self.label_8.setText(QCoreApplication.translate("VideoSettingsUi", u"Camera Format:", None)) + self.label_6.setText(QCoreApplication.translate("VideoSettingsUi", u"Video Codec:", None)) + # retranslateUi + diff --git a/examples/multimedia/camera/videosettings.py b/examples/multimedia/camera/videosettings.py index 5aab973b6..a88cb39ed 100644 --- a/examples/multimedia/camera/videosettings.py +++ b/examples/multimedia/camera/videosettings.py @@ -1,11 +1,17 @@ # Copyright (C) 2023 The Qt Company Ltd. # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +import os from PySide6.QtMultimedia import (QCameraFormat, QMediaFormat, QMediaRecorder, QVideoFrameFormat) from PySide6.QtWidgets import QDialog -from ui_videosettings import Ui_VideoSettingsUi +is_android = os.environ.get('ANDROID_ARGUMENT') + +if is_android: + from ui_videosettings_mobile import Ui_VideoSettingsUi +else: + from ui_videosettings import Ui_VideoSettingsUi def box_value(box): diff --git a/examples/multimedia/camera/videosettings_mobile.ui b/examples/multimedia/camera/videosettings_mobile.ui new file mode 100644 index 000000000..6584f07f9 --- /dev/null +++ b/examples/multimedia/camera/videosettings_mobile.ui @@ -0,0 +1,207 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>VideoSettingsUi</class> + <widget class="QDialog" name="VideoSettingsUi"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>329</width> + <height>591</height> + </rect> + </property> + <property name="windowTitle"> + <string>Video Settings</string> + </property> + <layout class="QGridLayout" name="gridLayout_3"> + <item row="2" column="0"> + <widget class="QWidget" name="widget" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QGroupBox" name="groupBox_3"> + <property name="title"> + <string>Audio</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Audio Codec:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="audioCodecBox"/> + </item> + <item> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string>Sample Rate:</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="audioSampleRateBox"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox"> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Quality:</string> + </property> + </widget> + </item> + <item> + <widget class="QSlider" name="qualitySlider"> + <property name="maximum"> + <number>4</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>File Format:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="containerFormatBox"/> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + <item row="3" column="0"> + <widget class="QGroupBox" name="groupBox_2"> + <property name="title"> + <string>Video</string> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="2" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Frames per second:</string> + </property> + </widget> + </item> + <item row="6" column="0" colspan="2"> + <widget class="QComboBox" name="videoCodecBox"/> + </item> + <item row="0" column="0" colspan="2"> + <widget class="QLabel" name="label_8"> + <property name="text"> + <string>Camera Format:</string> + </property> + </widget> + </item> + <item row="5" column="0" colspan="2"> + <widget class="QLabel" name="label_6"> + <property name="text"> + <string>Video Codec:</string> + </property> + </widget> + </item> + <item row="1" column="0" colspan="2"> + <widget class="QComboBox" name="videoFormatBox"/> + </item> + <item row="7" column="0"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + <item row="3" column="0"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QSpinBox" name="fpsSpinBox"> + <property name="minimum"> + <number>8</number> + </property> + <property name="maximum"> + <number>30</number> + </property> + </widget> + </item> + <item> + <widget class="QSlider" name="fpsSlider"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>VideoSettingsUi</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>322</x> + <y>272</y> + </hint> + <hint type="destinationlabel"> + <x>44</x> + <y>230</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>VideoSettingsUi</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>405</x> + <y>262</y> + </hint> + <hint type="destinationlabel"> + <x>364</x> + <y>227</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/examples/multimedia/player/player.py b/examples/multimedia/player/player.py index 88be50cc3..d28f2887e 100644 --- a/examples/multimedia/player/player.py +++ b/examples/multimedia/player/player.py @@ -7,7 +7,7 @@ import sys from PySide6.QtCore import QStandardPaths, Qt, Slot from PySide6.QtGui import QAction, QIcon, QKeySequence from PySide6.QtWidgets import (QApplication, QDialog, QFileDialog, - QMainWindow, QSlider, QStyle, QToolBar) + QMainWindow, QSlider, QStyle, QToolBar) from PySide6.QtMultimedia import (QAudioOutput, QMediaFormat, QMediaPlayer) from PySide6.QtMultimediaWidgets import QVideoWidget @@ -44,43 +44,43 @@ class MainWindow(QMainWindow): self.addToolBar(tool_bar) file_menu = self.menuBar().addMenu("&File") - icon = QIcon.fromTheme("document-open") + icon = QIcon.fromTheme(QIcon.ThemeIcon.DocumentOpen) open_action = QAction(icon, "&Open...", self, shortcut=QKeySequence.Open, triggered=self.open) file_menu.addAction(open_action) tool_bar.addAction(open_action) - icon = QIcon.fromTheme("application-exit") + icon = QIcon.fromTheme(QIcon.ThemeIcon.ApplicationExit) exit_action = QAction(icon, "E&xit", self, shortcut="Ctrl+Q", triggered=self.close) file_menu.addAction(exit_action) play_menu = self.menuBar().addMenu("&Play") style = self.style() - icon = QIcon.fromTheme("media-playback-start.png", + icon = QIcon.fromTheme(QIcon.ThemeIcon.MediaPlaybackStart, style.standardIcon(QStyle.SP_MediaPlay)) self._play_action = tool_bar.addAction(icon, "Play") self._play_action.triggered.connect(self._player.play) play_menu.addAction(self._play_action) - icon = QIcon.fromTheme("media-skip-backward-symbolic.svg", + icon = QIcon.fromTheme(QIcon.ThemeIcon.MediaSkipBackward, style.standardIcon(QStyle.SP_MediaSkipBackward)) self._previous_action = tool_bar.addAction(icon, "Previous") self._previous_action.triggered.connect(self.previous_clicked) play_menu.addAction(self._previous_action) - icon = QIcon.fromTheme("media-playback-pause.png", + icon = QIcon.fromTheme(QIcon.ThemeIcon.MediaPlaybackPause, style.standardIcon(QStyle.SP_MediaPause)) self._pause_action = tool_bar.addAction(icon, "Pause") self._pause_action.triggered.connect(self._player.pause) play_menu.addAction(self._pause_action) - icon = QIcon.fromTheme("media-skip-forward-symbolic.svg", + icon = QIcon.fromTheme(QIcon.ThemeIcon.MediaSkipForward, style.standardIcon(QStyle.SP_MediaSkipForward)) self._next_action = tool_bar.addAction(icon, "Next") self._next_action.triggered.connect(self.next_clicked) play_menu.addAction(self._next_action) - icon = QIcon.fromTheme("media-playback-stop.png", + icon = QIcon.fromTheme(QIcon.ThemeIcon.MediaPlaybackStop, style.standardIcon(QStyle.SP_MediaStop)) self._stop_action = tool_bar.addAction(icon, "Stop") self._stop_action.triggered.connect(self._ensure_stopped) @@ -99,8 +99,9 @@ class MainWindow(QMainWindow): self._volume_slider.valueChanged.connect(self._audio_output.setVolume) tool_bar.addWidget(self._volume_slider) + icon = QIcon.fromTheme(QIcon.ThemeIcon.HelpAbout) about_menu = self.menuBar().addMenu("&About") - about_qt_act = QAction("About &Qt", self, triggered=qApp.aboutQt) + about_qt_act = QAction(icon, "About &Qt", self, triggered=qApp.aboutQt) # noqa: F821 about_menu.addAction(about_qt_act) self._video_widget = QVideoWidget() @@ -168,8 +169,7 @@ class MainWindow(QMainWindow): @Slot("QMediaPlayer::PlaybackState") def update_buttons(self, state): media_count = len(self._playlist) - self._play_action.setEnabled(media_count > 0 - and state != QMediaPlayer.PlayingState) + self._play_action.setEnabled(media_count > 0 and state != QMediaPlayer.PlayingState) self._pause_action.setEnabled(state == QMediaPlayer.PlayingState) self._stop_action.setEnabled(state != QMediaPlayer.StoppedState) self._previous_action.setEnabled(self._player.position() > 0) diff --git a/examples/multimedia/screencapture/doc/screencapture.rst b/examples/multimedia/screencapture/doc/screencapture.rst index 69b1ec166..116d7773b 100644 --- a/examples/multimedia/screencapture/doc/screencapture.rst +++ b/examples/multimedia/screencapture/doc/screencapture.rst @@ -1,35 +1,42 @@ Screen Capture Example ====================== -The Screen Capture Example demonstrates how to capture a screen or window using -QScreenCapture. It shows a list of screens and and displays a live preview of -the selected item using a ``QMediaCaptureSession`` and a ``QVideoWidget``. -There is a button to start and stop the capturing. +Screen Capture demonstrates how to capture a screen or window using +``QScreenCapture`` and ``QWindowCapture``. The example shows a list of screens +and windows and displays a live preview of the selected item using a +``QMediaCaptureSession`` and a ``QVideoWidget``. Capturing can be started and +stopped with a ``QPushButton``. Application Structure +++++++++++++++++++++ -The example consists of two custom classes. The UI and all screen capture +The example consists of three custom classes. The UI and all screen capture functionality is implemented in the class ``ScreenCapturePreview``. The classes -``ScreenListModel`` serves as model behind the ``QListView``. The main function -creates a ``ScreenCapturePreview`` object, which in turn creates an instance of -``QScreenCapture``, ``QMediaCaptureSession`` and ``QVideoWidget`` in addition -to all the UI widgets. - -The list model is populated with the return values of ``QGuiApplication.screens()``. - -When a list item is selected it is connected to the ``QScreenCapture`` object -with ``QScreenCapture.setScreen()``. The ``QScreenCapture`` object is connected -to the ``QMediaCaptureSession`` object with -``QMediaCaptureSession.setScreenCapture()``, which in turn is connected to the -``QVideoWidget`` object with ``QMediaCaptureSession.setVideoOutput()`` Thus the -screen capture output is previewed in the video widget on the right hand side -of the UI. - -The start/stop button calls ``QScreenCapture.start()`` and ``QScreenCapture.stop()``. - -A ``QMessageBox`` pops up if the ``QScreenCapture.errorOccurred()`` signal is emitted. - -.. image:: screencapture.webp +``ScreenListModel`` and ``WindowListModel`` only serve as models behind the two +``QListView`` widgets. The main function creates a ``ScreenCapturePreview`` +object, which in turn creates instances of ``QScreenCapture`` and +``QWindowCapture``, and a ``QMediaCaptureSession`` and ``QVideoWidget``, in +addition to all the UI widgets. + +The screen and window models are populated with the return values of +``QGuiApplication.screens()`` and ``QWindowCapture.capturableWindows()``, +respectively. + +When a list item is selected, it is connected to the ``QScreenCapture`` object +with ``QScreenCapture.setScreen()``, or to the ``QWindowCapture`` object with +``QWindowCapture.setWindow().`` The capture object is connected to the +``QMediaCaptureSession`` object with +``QMediaCaptureSession.setScreenCapture()`` and +``QMediaCaptureSession.setWindowCapture()``, respectively. The capture session +in turn is connected to the ``QVideoWidget`` object with +``QMediaCaptureSession.setVideoOutput()``. Thus, the capture output is +previewed in the video widget on the right hand side of the UI. + +The start/stop button calls ``QScreenCapture.start()`` and ``QScreenCapture.stop()``, +or ``QWindowCapture.start()`` and ``QWindowCapture.stop()``. + +A QMessageBox pops up if an ``errorOccurred`` signal is emitted. + +.. image. screencapture.webp :width: 600 :alt: screen capture example diff --git a/examples/multimedia/screencapture/doc/screencapture.webp b/examples/multimedia/screencapture/doc/screencapture.webp Binary files differindex 2723b1d53..58ad36c7f 100644 --- a/examples/multimedia/screencapture/doc/screencapture.webp +++ b/examples/multimedia/screencapture/doc/screencapture.webp diff --git a/examples/multimedia/screencapture/main.py b/examples/multimedia/screencapture/main.py index dce30186c..f445bac03 100644 --- a/examples/multimedia/screencapture/main.py +++ b/examples/multimedia/screencapture/main.py @@ -5,6 +5,7 @@ import sys +from PySide6.QtCore import QCoreApplication from PySide6.QtWidgets import QApplication from screencapturepreview import ScreenCapturePreview @@ -12,6 +13,8 @@ from screencapturepreview import ScreenCapturePreview if __name__ == "__main__": app = QApplication(sys.argv) + QCoreApplication.setApplicationName("screencapture") + QCoreApplication.setOrganizationName("QtProject") screen_capture_preview = ScreenCapturePreview() screen_capture_preview.show() sys.exit(app.exec()) diff --git a/examples/multimedia/screencapture/screencapture.pyproject b/examples/multimedia/screencapture/screencapture.pyproject index 9b18fa093..dfec6c901 100644 --- a/examples/multimedia/screencapture/screencapture.pyproject +++ b/examples/multimedia/screencapture/screencapture.pyproject @@ -1,3 +1,3 @@ { - "files": ["main.py", "screencapturepreview.py", "screenlistmodel.py"] + "files": ["main.py", "screencapturepreview.py", "screenlistmodel.py", "windowlistmodel.py"] } diff --git a/examples/multimedia/screencapture/screencapturepreview.py b/examples/multimedia/screencapture/screencapturepreview.py index 72fe77c64..c7e0c596a 100644 --- a/examples/multimedia/screencapture/screencapturepreview.py +++ b/examples/multimedia/screencapture/screencapturepreview.py @@ -1,14 +1,23 @@ # Copyright (C) 2023 The Qt Company Ltd. # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +from enum import Enum, auto + from PySide6.QtMultimediaWidgets import QVideoWidget -from PySide6.QtMultimedia import QScreenCapture, QMediaCaptureSession +from PySide6.QtMultimedia import (QCapturableWindow, QMediaCaptureSession, + QScreenCapture, QWindowCapture) from PySide6.QtWidgets import (QGridLayout, QLabel, QListView, QMessageBox, QPushButton, QWidget) -from PySide6.QtGui import QGuiApplication -from PySide6.QtCore import Slot +from PySide6.QtGui import QAction, QGuiApplication +from PySide6.QtCore import QItemSelection, Qt, Slot from screenlistmodel import ScreenListModel +from windowlistmodel import WindowListModel + + +class SourceType(Enum): + Screen = auto() + Window = auto() class ScreenCapturePreview(QWidget): @@ -16,58 +25,138 @@ class ScreenCapturePreview(QWidget): def __init__(self, parent=None): super().__init__(parent) + self._source = SourceType.Screen + self._screen_capture = QScreenCapture(self) self._media_capture_session = QMediaCaptureSession(self) self._video_widget = QVideoWidget(self) self._screen_list_view = QListView(self) - self._screen_label = QLabel("Double-click screen to capture:", self) - self._video_widget_label = QLabel("QScreenCapture output:", self) - self._start_stop_button = QPushButton("Stop screencapture", self) + self._screen_label = QLabel("Select screen to capture:", self) + self._video_widget_label = QLabel("Capture output:", self) + self._start_stop_button = QPushButton(self) + self._status_label = QLabel(self) self._screen_list_model = ScreenListModel(self) # Setup QScreenCapture with initial source: - self.set_screen(QGuiApplication.primaryScreen()) + self.setScreen(QGuiApplication.primaryScreen()) self._screen_capture.start() self._media_capture_session.setScreenCapture(self._screen_capture) self._media_capture_session.setVideoOutput(self._video_widget) self._screen_list_view.setModel(self._screen_list_model) + self._window_list_view = QListView(self) + self._window_capture = QWindowCapture(self) + self._media_capture_session.setWindowCapture(self._window_capture) + self._window_label = QLabel("Select window to capture:", self) + + self._window_list_model = WindowListModel(self) + self._window_list_view.setModel(self._window_list_model) + update_action = QAction("Update windows List", self) + update_action.triggered.connect(self._window_list_model.populate) + self._window_list_view.addAction(update_action) + self._window_list_view.setContextMenuPolicy(Qt.ActionsContextMenu) + grid_layout = QGridLayout(self) grid_layout.addWidget(self._screen_label, 0, 0) grid_layout.addWidget(self._screen_list_view, 1, 0) - grid_layout.addWidget(self._start_stop_button, 2, 0) + grid_layout.addWidget(self._start_stop_button, 4, 0) grid_layout.addWidget(self._video_widget_label, 0, 1) - grid_layout.addWidget(self._video_widget, 1, 1, 2, 1) + grid_layout.addWidget(self._video_widget, 1, 1, 4, 1) + grid_layout.addWidget(self._window_label, 2, 0) + grid_layout.addWidget(self._window_list_view, 3, 0) + grid_layout.addWidget(self._status_label, 5, 0, 1, 2) grid_layout.setColumnStretch(1, 1) grid_layout.setRowStretch(1, 1) grid_layout.setColumnMinimumWidth(0, 400) grid_layout.setColumnMinimumWidth(1, 400) + grid_layout.setRowMinimumHeight(3, 1) + + selection_model = self._screen_list_view.selectionModel() + selection_model.selectionChanged.connect(self.on_current_screen_selection_changed) + selection_model = self._window_list_view.selectionModel() + selection_model.selectionChanged.connect(self.on_current_window_selection_changed) - self._screen_list_view.activated.connect(self.on_screen_selection_changed) self._start_stop_button.clicked.connect(self.on_start_stop_button_clicked) - self._screen_capture.errorOccurred.connect(self.on_screen_capture_error_occured) + self._screen_capture.errorOccurred.connect(self.on_screen_capture_error_occured, + Qt.QueuedConnection) + self._window_capture.errorOccurred.connect(self.on_window_capture_error_occured, + Qt.QueuedConnection) + self.update_active(SourceType.Screen, True) + + @Slot(QItemSelection) + def on_current_screen_selection_changed(self, selection): + self.clear_error_string() + indexes = selection.indexes() + if indexes: + self._screen_capture.setScreen(self._screen_list_model.screen(indexes[0])) + self.update_active(SourceType.Screen, self.is_active()) + self._window_list_view.clearSelection() + else: + self._screen_capture.setScreen(None) + + @Slot(QItemSelection) + def on_current_window_selection_changed(self, selection): + self.clear_error_string() + indexes = selection.indexes() + if indexes: + window = self._window_list_model.window(indexes[0]) + if not window.isValid(): + m = "The window is no longer valid. Update the list of windows?" + answer = QMessageBox.question(self, "Invalid window", m) + if answer == QMessageBox.Yes: + self.update_active(SourceType.Window, False) + self._window_list_view.clearSelection() + self._window_list_model.populate() + return + self._window_capture.setWindow(window) + self.update_active(SourceType.Window, self.is_active()) + self._screen_list_view.clearSelection() + else: + self._window_capture.setWindow(QCapturableWindow()) - def set_screen(self, screen): - self._screen_capture.setScreen(screen) - self.setWindowTitle(f"Capturing {screen.name()}") + @Slot(QWindowCapture.Error, str) + def on_window_capture_error_occured(self, error, error_string): + self.set_error_string("QWindowCapture: Error occurred " + error_string) - @Slot() - def on_screen_selection_changed(self, index): - self.set_screen(self._screen_list_model.screen(index)) + @Slot(QScreenCapture.Error, str) + def on_screen_capture_error_occured(self, error, error_string): + self.set_error_string("QScreenCapture: Error occurred " + error_string) - @Slot() - def on_screen_capture_error_occured(self, error, errorString): - QMessageBox.warning(self, "QScreenCapture: Error occurred", - errorString) + def set_error_string(self, t): + self._status_label.setStyleSheet("background-color: rgb(255, 0, 0);") + self._status_label.setText(t) + + def clear_error_string(self): + self._status_label.clear() + self._status_label.setStyleSheet("") @Slot() def on_start_stop_button_clicked(self): - if self._screen_capture.isActive(): - self._screen_capture.stop() - self._start_stop_button.setText("Start screencapture") - else: - self._screen_capture.start() - self._start_stop_button.setText("Stop screencapture") + self.clear_error_string() + self.update_active(self._source_type, not self.is_active()) + + def update_start_stop_button_text(self): + active = self.is_active() + if self._source_type == SourceType.Window: + m = "Stop window capture" if active else "Start window capture" + self._start_stop_button.setText(m) + elif self._source_type == SourceType.Screen: + m = "Stop screen capture" if active else "Start screen capture" + self._start_stop_button.setText(m) + + def update_active(self, source_type, active): + self._source_type = source_type + self._screen_capture.setActive(active and source_type == SourceType.Screen) + self._window_capture.setActive(active and source_type == SourceType.Window) + + self.update_start_stop_button_text() + + def is_active(self): + if self._source_type == SourceType.Window: + return self._window_capture.isActive() + if self._source_type == SourceType.Screen: + return self._screen_capture.isActive() + return False diff --git a/examples/multimedia/screencapture/screenlistmodel.py b/examples/multimedia/screencapture/screenlistmodel.py index d3553aa27..72bb306e3 100644 --- a/examples/multimedia/screencapture/screenlistmodel.py +++ b/examples/multimedia/screencapture/screenlistmodel.py @@ -9,7 +9,7 @@ class ScreenListModel(QAbstractListModel): def __init__(self, parent=None): super().__init__(parent) - app = qApp + app = qApp # noqa: F821 app.screenAdded.connect(self.screens_changed) app.screenRemoved.connect(self.screens_changed) app.primaryScreenChanged.connect(self.screens_changed) diff --git a/examples/multimedia/screencapture/windowlistmodel.py b/examples/multimedia/screencapture/windowlistmodel.py new file mode 100644 index 000000000..079040ec2 --- /dev/null +++ b/examples/multimedia/screencapture/windowlistmodel.py @@ -0,0 +1,30 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +from PySide6.QtCore import QAbstractListModel, Qt, Slot +from PySide6.QtMultimedia import QWindowCapture + + +class WindowListModel(QAbstractListModel): + + def __init__(self, parent=None): + super().__init__(parent) + self._window_list = QWindowCapture.capturableWindows() + + def rowCount(self, QModelIndex): + return len(self._window_list) + + def data(self, index, role): + if role == Qt.DisplayRole: + window = self._window_list[index.row()] + return window.description() + return None + + def window(self, index): + return self._window_list[index.row()] + + @Slot() + def populate(self): + self.beginResetModel() + self._window_list = QWindowCapture.capturableWindows() + self.endResetModel() |