c++qtqcamera

Have two QCameraViewFinder for one QCamera


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!


Solution

  • 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.