How to generate video file from QImage sequence using QMediaRecorder in Qt5 C++

3.4k Views Asked by At

Basically what I want is to encode a video using QMediaRecorder by supplying as a source a sequence of QImages that I generate in custom code at run-time.

So far I have found no easy way to do this, and everything points at the solution where I have to somehow implement my own subclass of QMediaService and/or QMediaControl that takes QImage as input, register them and somehow make QMediaRecorder use them. But according to this page in the official Qt documentation on the subject, this is a road less traveled and I am on my own:

In general, implementing a QMediaService is outside of the scope of this documentation and support on the relevant mailing lists or IRC channels should be sought.

I am with this post hoping someone who possesses this knowledge may shed some light on how this would be done. I think documenting this set of features will open up many useful possibilities for the users of Qt5.

Update 2020-06-16: It has been almost 4 years and still not a single answer. I will put a bounty on this question and accept the best answer with working example code for recent Qt5.

4

There are 4 best solutions below

3
JoeA On

It is quite simple to do this directly with ffmpeg. You can either save the images on disk then use an ffmpeg filter from the command line, via QProcess. You can also create a video stream in the code, therefore avoiding the loss of time and performance due to the images being saved on the disk, save the images in that stream

0
M. Galib Uludag On

You can try libqtavi. It is a wrapper around the libgwavi. API looking simple and good integration with Qt classes. But only support MJPG codec and avi format and its bigger output size than mpeg/mp4, hevc/mkv...

QAviWriter writer("demo.avi", QSize(800, 600), 24, "MJPG");// set framerate to 24 fps and 'MJPG' codec 
writer.setAudioFileName("audio.wav"); // set audio track
writer.open();
writer.addFrame(QImage("file.png"));
//...add all other video frames here
writer.close();
1
SpammerSpam SPAM On

Directly using ffmpeg to accomplish this is really easy. Either use QProcess or store the photos to disc before using a ffmpeg filter from the command line. You can alternatively establish a video stream in the code and save the photos there to avoid the performance and time penalties associated with saving the images to the disc.

2
Ihtsham Minhas On

Here is an example of how you can generate a video using QMediaRecorder

#include <QApplication>
#include <QImage>
#include <QMediaRecorder>
#include <QCamera>
#include <QCameraViewfinder>
#include <QCameraImageCapture>

class VideoRecorder : public QObject
{
    Q_OBJECT

public:
    VideoRecorder()
    {
        camera = new QCamera;
        viewFinder = new QCameraViewfinder;
        camera->setViewfinder(viewFinder);
        imageCapture = new QCameraImageCapture(camera);

        mediaRecorder = new QMediaRecorder(camera);
        mediaRecorder->setOutputLocation(QUrl::fromLocalFile("test.avi"));

        QVideoEncoderSettings videoSettings;
        videoSettings.setCodec("video/x-msvideo");
        videoSettings.setQuality(QMultimedia::HighQuality);
        mediaRecorder->setVideoSettings(videoSettings);
    }

    ~VideoRecorder()
    {
        delete camera;
        delete viewFinder;
        delete imageCapture;
        delete mediaRecorder;
    }

    void startRecording()
    {
        camera->start();

        for (int i = 0; i < 100; ++i) {
            QImage image(640, 480, QImage::Format_RGB32);
            // populate the image with data
            imageCapture->capture(QString::number(i) + ".jpg");
            mediaRecorder->record();
        }

        mediaRecorder->stop();
        camera->stop();
    }

private:
    QCamera *camera;
    QCameraViewfinder *viewFinder;
    QCameraImageCapture *imageCapture;
    QMediaRecorder *mediaRecorder;
};

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

    VideoRecorder videoRecorder;
    videoRecorder.startRecording();

    return a.exec();
}