qtqt6qtmultimediaqvideowidgetqcamera

How to receive frame from QCamera directly in Qt6?


I am trying to capture image without QVideoWidget. But it seems does not work. When I call capture() after camera->start() , it gives me an error: Camera is not ready.

// Search camera and display in list
QObject::connect(ui->search, &QPushButton::clicked, [this] {
    camlist = QMediaDevices::videoInputs();
    qDebug() << camlist;

    foreach (auto cam, camlist) {
      QListWidgetItem *item = new QListWidgetItem(ui->list);
      item->setText(QString("%1:%2").arg(cam.id()).arg(cam.description()));
      item->setData(Qt::UserRole, QVariant::fromValue(cam));
      ui->list->addItem(item);
    }
  });

// start camera
  QObject::connect(ui->start, &QPushButton::clicked, [this]() {
    auto item = ui->list->currentItem();
    auto cam = item->data(Qt::UserRole).value<QCameraDevice>();
    if (capturesession.camera() && capturesession.camera()->isActive()) {
      capturesession.camera()->stop();
    }
    capturesession.setCamera(new QCamera(cam));
    capturesession.setImageCapture(new QImageCapture);
    capturesession.camera()->start();
  });
  
// stop camera
  QObject::connect(ui->stop, &QPushButton::clicked, [this]() {
    if (capturesession.camera()) {
      capturesession.camera()->stop();
    }
  });

QObject::connect(ui->capture, &QPushButton::clicked, [this]() {
    if (capturesession.camera()) {
        // debug camera status 
        ui->text->appendPlainText(
          QString("camera[%1]:isActive=%2, isAvailable=%3, isFlashReady=%4.\n")
              .arg(capturesession.camera()->cameraDevice().id())
              .arg(capturesession.camera()->isActive())
              .arg(capturesession.camera()->isAvailable())
                .arg(capturesession.camera()->isFlashReady())
            );

        // capture
        capturesession.imageCapture()->capture();
    }
  });


connect(&capturesession, &QMediaCaptureSession::imageCaptureChanged, [this]
  {
   
    
    connect(capturesession.imageCapture(), &QImageCapture::imageCaptured,
            [this](int id, const QImage &preview) {
              ui->text->appendPlainText(QString("Image Captured:%1").arg(id));
              ui->label->setPixmap(QPixmap::fromImage(preview));
            });

    connect(
        capturesession.imageCapture(), &QImageCapture::errorOccurred,
        [this](int id, QImageCapture::Error error, const QString &errorString) {
          ui->text->appendPlainText(
              QString("[%1]error:%2").arg(id).arg(errorString));
        });
  });

Is it possible to receive frame from QCamera directly? I don't want to use QVideoWidget. I just need to receive frames one by one, and process every frame, display on QLabel or QGrachiphisView.


Solution

  • I found the way to get frames directly without setting QVideoWidget.

    // set video sink to QMediaCaptureSession
    QVideoSink * sink = new QVideoSink;
    capturesession.setVideoSink(sink);
    
    // set `QCamera` instance to `QMediaCaptureSession`
    captureSession.setCamera(new QCamera(cameraDevice));
    // set `QImageCapture` instance to `QMediaCaptureSession`
    captureSession.setImageCapture(new QImageCapture);
    

    you have two options to get frame from camera:

    1. connect QImageCapture::imageCaptured(int id, const QImage &preview) signal. call QImageCapture::capture() method;

    2. connectQVideoSink::videoFrameChanged signal.

    don't forget start camera: QCamera::start().