Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Qcamera supportedViewfinderPixelFormats doesn't return the full list



  • Hi,
    I'm trying to capture a still image from my camera, my camera isn AUKEY brand, viewing the camera in a program like guvcview and playing with the settings it seems like the camera can be set to 1920x1080 only if the format is set to H264, RGB3 or MJPEG.

    unfortunately the list of formats returned by supportedViewfinderPixelFormats only shows Format_YUYV which for my camera only support 640x480 and 1280x720.

    supported formats returned by v4l2-ctrl:

    ╰─➤  v4l2-ctl --list-formats -d /dev/video0 
    ioctl: VIDIOC_ENUM_FMT
            Type: Video Capture
    
            [0]: 'MJPG' (Motion-JPEG, compressed)
            [1]: 'H264' (H.264, compressed)
            [2]: 'YUYV' (YUYV 4:2:2)
    

    my sample program:

    import sys
    import os
    import signal
    import traceback
    from PyQt5 import QtWidgets as qtw
    from PyQt5 import QtCore as qtc
    from PyQt5 import QtGui as qtg
    
    from PyQt5.QtMultimedia import QCameraInfo, QCamera, QCameraImageCapture,QImageEncoderSettings
    
    from PyQt5.QtMultimediaWidgets import QCameraViewfinder
    
    
    class mainwindow(qtw.QMainWindow):
    
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.centralwidget = qtw.QWidget()
            self.setCentralWidget(self.centralwidget)
            self.gridLayout = qtw.QGridLayout(self.centralwidget)
            self.avatarLayout = qtw.QHBoxLayout()
            self.gridLayout.addLayout(self.avatarLayout, 0, 0, 1, 1)
            self.avatar = qtw.QLabel()
            self.avatar.setText("")
            self.avatar.setStyleSheet("background-color:#c7dcff")
            self.start_cam = qtw.QPushButton("start camera")
            self.capture_cam = qtw.QPushButton("capture camera")
            self.viewFinderContainer = qtw.QWidget()
            self.viewFinderContainer_layout =qtw.QGridLayout(self.viewFinderContainer)
            
            self.viewFinder = QCameraViewfinder()
            self.viewFinderContainer.setStyleSheet("background-color:#98b8ed")
            self.viewFinderContainer_layout.addWidget(self.viewFinder)
            self.viewFinderContainer.setMinimumHeight(400)
            self.viewFinderContainer.setMinimumWidth(400)
            self.avatar.setMinimumHeight(600)
            self.avatar.setMinimumWidth(400)
    
            self.avatarLayout.addWidget(self.viewFinderContainer)
            self.avatarLayout.addWidget(self.avatar)
            self.gridLayout.addWidget(self.start_cam,1,0,1,1)
            self.gridLayout.addWidget(self.capture_cam,2,0,1,1)
            
            self.statusbar = qtw.QStatusBar(self)
            self.setStatusBar(self.statusbar)
            
            self.start_cam.clicked.connect(self.get_webcam)
            self.capture_cam.clicked.connect(self.capture_img)
            self.online_webcams = QCameraInfo.availableCameras()
            self.show()
    
    
                
        @qtc.pyqtSlot()
        def get_webcam(self):
            if not self.online_webcams:
                self.statusbar.showMessage("you didn't connect a camera")
            else:
                print("getting webcam")
            self.my_webcam = QCamera(self.online_webcams[0])
            self.my_webcam.statusChanged.connect(self.status_changed)
            self.my_webcam.setViewfinder(self.viewFinder)
            self.my_webcam.setCaptureMode(QCamera.CaptureStillImage)
            self.my_webcam.error.connect(lambda: print(self.my_webcam.errorString()))
    
            print("starting webcam")
            self.my_webcam.start()
    
            self.capture = QCameraImageCapture(self.my_webcam)
            self.cap_end_settings = QImageEncoderSettings()
            # self.cap_end_settings.setResolution(qtc.QSize(1080,1920))
            self.capture.setEncodingSettings(self.cap_end_settings)
            self.capture.setCaptureDestination(self.capture.CaptureToBuffer)
            self.capture.error.connect(lambda i, e, s: print(s))
            self.capture.imageCaptured.connect(self.captured)
    
            self.current_camera_name = self.online_webcams[0].description()
            
        
        def captured(self,d,i):
            print('captured')
            print("scale the pixmap")
            pixmap = qtg.QPixmap.fromImage(i.convertToFormat(qtg.QImage.Format_ARGB32)).scaledToHeight(600,qtc.Qt.SmoothTransformation)
            self.avatar.setPixmap(pixmap)
        
        @qtc.pyqtSlot(QCamera.Status)
        def status_changed(self,status):
            print("status changed, new status: ",status)
    
            # Camera is loaded and we can query and set settings
            if status == QCamera.LoadedStatus:
                print("printing supported camera PixelFormats")
                print(self.my_webcam.supportedViewfinderPixelFormats())
                print("setting pixel format")
                self.my_webcam.viewfinderSettings().setPixelFormat(30)
                print(self.my_webcam.viewfinderSettings().pixelFormat())
                
                print("printing supported camera resolutions")
                print(self.my_webcam.supportedViewfinderResolutions())
                
                # print("setting resolution")
                # self.my_webcam.viewfinderSettings().setResolution(1080,1920)
                # print("printing supported camera resolutions")
                # print(self.my_webcam.viewfinderSettings().resolution())
                # print("printing current camera resolutions")
                # print(self.my_webcam.viewfinderSettings().resolution())
    
    
    
        @qtc.pyqtSlot()
        def capture_img(self):
            if (self.capture.isReadyForCapture()):
                self.capture.capture()
    
    def setup_interrupt_handling():
        """Setup handling of KeyboardInterrupt (Ctrl-C) for PyQt."""
        signal.signal(signal.SIGINT, _interrupt_handler)
        # Regularly run some (any) python code, so the signal handler gets a
        # chance to be executed:
        safe_timer(50, lambda: None)
    
    
    # Define this as a global function to make sure it is not garbage
    # collected when going out of scope:
    def _interrupt_handler(signum, frame):
        """Handle KeyboardInterrupt: quit application."""
        w.cleanup()
        qtw.QApplication.quit()
    
    
    def safe_timer(timeout, func, *args, **kwargs):
        """
        Create a timer that is safe against garbage collection and overlapping
        calls. See: http://ralsina.me/weblog/posts/BB974.html
        """
        def timer_event():
            try:
                func(*args, **kwargs)
            finally:
                qtc.QTimer.singleShot(timeout, timer_event)
        qtc.QTimer.singleShot(timeout, timer_event)
    
    
    def excepthook(exc_type, exc_value, exc_tb):
        tb = "".join(traceback.format_exception(exc_type, exc_value, exc_tb))
        print("error catched!:")
        print("error message:\n", tb)
        qtw.QApplication.quit()
    
    
    if __name__ == '__main__':
        os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
        
        sys.excepthook = excepthook
        try:
            qtw.QApplication.setAttribute(qtc.Qt.AA_EnableHighDpiScaling)
        except AttributeError:  # Attribute only exists for Qt>=5.6.
            pass
        app = qtw.QApplication(sys.argv)
        setup_interrupt_handling()
    
        w = mainwindow()
        ret = app.exec_()
        sys.exit(ret)
    
    

  • Lifetime Qt Champion

    Hi,

    Which version of PyQt5 ?
    How did you install it ?
    Which distribution are you using ?
    Do you get the same result with PySide2/6 ?



  • @SGaist said in Qcamera supportedViewfinderPixelFormats doesn't return the full list:

    Hi,

    Which version of PyQt5 ?

    PyQt5==5.15.4
    PyQt5-sip==12.9.0

    How did you install it ?

    pip install PyQt5

    Which distribution are you using ?

    Manjaro linux

    Do you get the same result with PySide2/6 ?

    On, Pyside2 the problem is the same, I couldn't port it to PySide6 however, still have no experience in the version 6 bindings


Log in to reply