5

I create an app with the cross-platform Qt and on this app, I need to display the result of one QCamera on two different screens. This involve to link two QCameraViewFinder on the same QCamera.

My code is :

QCameraViewFinder* viewfinder = new QCameraViewFinder(); 
QCamera* camera = new QCamera();
viewfinder->setSizePolicy(QSizePolicy::Maximum,QSizePolicy::Maximum);
camera->setViewfinder(ui->viewfinder);
QCamera::CaptureModes captureMode =  QCamera::CaptureStillImage  ;
camera->setCaptureMode(captureMode);

The problem here is that I can't use another QCameraViewFinder to track my QCamera. And I need to do that because I would like to display two QCameraViewFinder on two different screens.

I'm really stuck on this topic so if some people have a solution, that would be great!

Bugs
  • 4,491
  • 9
  • 32
  • 41
tagry
  • 63
  • 7

1 Answers1

3

You can actually create two distinct instances of QCamera, and set two distinct viewfinders to them, but you'll not be able to start the camera twice (i.e. you will end up with some kind of busy device error).

If all you need is a simple viewfinder implementation, you can subclass QAbstractVideoSurface and forward video frames through signals, this way:

sharedviewfinder.h

#include <QAbstractVideoSurface>
#include <QPixmap>

class SharedViewfinder : public QAbstractVideoSurface
{
    Q_OBJECT
public:
    SharedViewfinder();

    QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const;
    bool present(const QVideoFrame &frame);

signals:
    void frameReady(QPixmap);
};

sharedviewfinder.cpp

#include "sharedviewfinder.h"

SharedViewfinder::SharedViewfinder() : QAbstractVideoSurface(nullptr){}

QList<QVideoFrame::PixelFormat> SharedViewfinder::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const
{
    QList<QVideoFrame::PixelFormat> list;
    if (handleType == QAbstractVideoBuffer::NoHandle)
    {
        list.append(QVideoFrame::Format_RGB32);
    }
    return list;
}

bool SharedViewfinder::present(const QVideoFrame &frame)
{
    QVideoFrame copy(frame);
    copy.map(QAbstractVideoBuffer::ReadOnly);
    QImage image(copy.bits(), copy.width(), copy.height(), copy.bytesPerLine(), QImage::Format_RGB32);
    copy.unmap();

    emit frameReady(QPixmap::fromImage(image));

    return true;
}

To show the forwarded frames, in a widget of your choice, have a QLabel and a slot like this:

void Widget::frameReady(QPixmap pixmap)
{
    label->setPixmap(pixmap);
    label->update();
}

You can now set the shared viewfinder to a camera object, and connect it with more than one view:

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    SharedViewfinder viewfinder;
    Widget mirror1;
    Widget mirror2;

    QObject::connect(&viewfinder, &SharedViewfinder::frameReady, &mirror1, &Widget::frameReady);
    QObject::connect(&viewfinder, &SharedViewfinder::frameReady, &mirror2, &Widget::frameReady);

    QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
    QCamera camera(cameras[0]);
    camera.setViewfinder(&viewfinder);

    mirror1.move(0, 0);
    mirror1.show();

    mirror2.move(1920, 0);
    mirror2.show();

    camera.start();

    return a.exec();
}

I hope this works out of the box, anyway you may want to change the color format I set to RGB32. Also, notice I move the views to show them on both the screens I have. The example code I'm providing has been successfully tested (but in a very shallow way) on a Ubuntu 16.10 Asus laptop.

p-a-o-l-o
  • 9,807
  • 2
  • 22
  • 35
  • Thank you very much for your answer ! I quickly looked and I try this way. I let you know. – tagry Mar 05 '18 at 16:39
  • 1
    I tried your code but I have a segmentation fault when the format is RGB32 . This error is when I doing `label->setPixmap(pixmap);` . I tried some other formats but there are not which works proprely. Some have strange color or crash. I didn't try all formats. Do you have any idea about which format is the best to solve my problem ? Thank you. – tagry Mar 06 '18 at 09:50
  • I fixed the problem : `QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(copy.pixelFormat());` Thank you again the topic is solved ! – tagry Mar 06 '18 at 10:11
  • i can confirm that the above works, even when your destinations are multiple QGraphicsVideoItems in multiple different scenes. you can just forward the QVideoFrame directly to them, no need to convert into a pixmap or use signals. note i did need to use the videoSurface api, not the videoItem one – David M. Cotter Nov 03 '20 at 19:47