65

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.

Mr. Developerdude
  • 9,118
  • 10
  • 57
  • 95
  • 1
    Hi @Lennart, I believe you may have been misled by the naming of the class, as Q*Media*Recorder can lead to consider this is a base close that could be used for recording video. Nevertheless, you can see in [Qt documentation](http://doc.qt.io/archives/qt-5.5/qmediarecorder.html#details) this class has audio only methods (such as _audioCodecDescription()_) and is only inherited by QAudioRecorder. I would suggest for you to take a look at [QVideoProbe](https://doc.qt.io/qt-5.6/qvideoprobe.html), which allow you to probe frames from a QMediaPlayer. – diogoslima Sep 19 '18 at 21:35
  • 1
    You could try just using ffmpeg, it's quite portable. Just run it as an external application from your code. It should be quite easy to generate a video from still images with that. Ask if you need help with that. – 0xbaadf00d Apr 10 '19 at 12:14
  • 0xbaadf00d - Thank you, but I think you missed the point of the question. I am perfectly capable of handling video. I have used ffmpeg for a long time. What I am after is how use Qt to do the same. This has the benefit that I would have one less dependency to worry about. For simple video stuff I could just rely on video support in Qt instead of having to bundle ffmpeg. – Mr. Developerdude Apr 14 '19 at 11:51
  • @LennartRolland It looks like `QMediaRecorder` only works on macOS, Linux, mobile platforms and Windows XP. Are you opened to other solutions using Qt? – karlphillip Jun 20 '20 at 23:56
  • @karlphillip: I think you listed all platforms except modern windows. Actually focus for me is on linux and mobile platforms. – Mr. Developerdude Jun 21 '20 at 17:20
  • On QMediaService documentation page it says: "This class is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code." I don't know which class replace it, but I think there should be an alternative. Are you sure you want to do it this way? – Doch88 Jun 21 '20 at 19:41
  • 1
    @Doch88: I didn't see that, I think it was not the case when I first asked the question. Thanks! – Mr. Developerdude Jun 22 '20 at 14:11
  • If in Windows, it's way easier with media foundation. – Michael Chourdakis Nov 04 '22 at 04:42

4 Answers4

1

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();
M. Galib Uludag
  • 369
  • 2
  • 8
0

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

JoeA
  • 1
  • I know it is easy in ffmpeg, I have been using ffmpeg since 2002, I was kind of hoping to avoid the dependency – Mr. Developerdude Jul 03 '20 at 17:04
  • @LennartRolland You would actually still be dependant either on libffmpeg library or gstreamer infrastructure. Or both. There are very few portable options. ffmpeg utility can be run standalone usually, or you could use the library directly. Qt's stuff uses gstreamer and libffmpeg indirectly. – Swift - Friday Pie Nov 24 '22 at 08:17
  • @Swift-FridayPie I know that under the hood that is definitely the case. But if Qt wraps it, I want to use the Qt wrapper and not interface directly with ffmpeg/gstreamer. The reason is that build time dependencies is a big deal in many projects. I am asking this question mostly to avoid that dependency (the dependency will be there but hidden behind Qt api) – Mr. Developerdude Dec 31 '22 at 15:57
0

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.

Zinavo
  • 1
  • 2
  • The problems are a) embedded platforms may have issue with allowing this b) there is a number of issues with actually stopping ffmpeg in a way it wouldn't generate broken container, it limits container type to those which me be arbitrary cut. Only newer versions of ffmpeg support proper close of file on SOME platforms. – Swift - Friday Pie Nov 24 '22 at 08:15
0

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();
}
Ihtsham Minhas
  • 1,415
  • 1
  • 19
  • 31
  • 1
    I am afraid you might have misread the question. Getting frames from the camera is easy enough as you have demonstrated, however we want to encode a video stream from QImages. – Mr. Developerdude Feb 08 '23 at 20:31
  • @LennartRolland It is unfortunate that the QMediaRecorder does not possess a direct method for encoding a video from a sequence of QImage objects. However, a custom solution can be developed by utilizing a library such as OpenCV, which provides the cv2.VideoWriter class for writing video files by writing the image sequence – Ihtsham Minhas Feb 09 '23 at 11:54