4

How to create a .mp4 video out of multiple QImages in a Qt application.

Looking at QMediaRecorder examples, it only knows how to grab frames from camera. There seems to be no way to pass multiple QImages or some other image data type into QMediaRecorder simply to make a video out of them which has nothing to do with the camera.

Development Environment:
Using Qt 5.9.1 commercial version with app working on Android, iOS & OSX.

TheWaterProgrammer
  • 7,055
  • 12
  • 70
  • 159
  • 1
    Qt provides no such functionality. – dtech Oct 01 '17 at 10:47
  • So, do I need to use `FFmpeg` for this? Build FFmpeg into my Qt app & create the `.mp4` video by somehow passing these QImages in some way? – TheWaterProgrammer Oct 01 '17 at 10:53
  • 1
    Yes, ffmpeg or gstreamer or libav or libvnc, plenty of choices. – dtech Oct 01 '17 at 10:53
  • do you have an example or snippet of how to pass QImages into FFmpeg? If you say this is a different question then ok. just asking if you have any examples handy – TheWaterProgrammer Oct 01 '17 at 10:54
  • 1
    Also, you can please post the answer saying Qt offers no such functionality. the answer is **acceptable** to me. I **wanted to confirm this** before taking the huge learning curve of building `FFmpeg` with my *Qt app* & then figuring out how to use to achieve my goal with `QImage`s – TheWaterProgrammer Oct 01 '17 at 10:59
  • Sorry but such an answer does not pass my own standards for usefulness. I don't think there are many examples, I recall there is a Qt wrapper for gstreamer, but IIRC it hasn't been maintained for years. – dtech Oct 01 '17 at 11:45

1 Answers1

2

It is hard to ascertain exactly what you need to do here, considering it is not clear just how many images you are processing.

That being said, this is possible if you use a tool such as ffmpeg to generate the video, however it will require you to at the very least, write those images to disc.

Here is a working example I use to generate slideshows videos for youtube. The concatenation of images is ascertained by their naming scheme as saved on the drive.

    sl << "-i" << md.sku(true) + "##%03d.png"; // Images input,

as such,

mysku##001.png // First Slide
mysku##002.png // Second Slide
mysku##003.png // Third Slide
mysku##004.png // Fourth Slide

VideoConvert::VideoConvert(Metadata &md, QFile &oggFile, QObject *parent) : QObject(parent)
{
    QStringList sl;
    tt.warning(md.duration());
    tt.warning(md.length());
    QString framerate = md.duration(true);
    int hour   = QString(md.length()).split(":").at(0).toInt();
    int minute = QString(md.length()).split(":").at(1).toInt();
    int second = QString(md.length()).split(":").at(2).toInt();

    framerate.remove(".");
    framerate.remove(QRegularExpression("^[0]*"));

    sl << "-y"; // overwrite
    sl << "-framerate" << QString::number(md.images().length()) 
        + "/" + QString::number(((hour * 60) * 60) + (minute * 60) + second);
    sl << "-i" << md.sku(true) + "##%03d.png"; // Images input,
    sl << "-i" << oggFile.fileName();
    sl << "-c" << "copy";
    sl << "/home/akiva/FrogCast/" + md.title(true) + " ⟪WikiBook⟫.mp4";
    md.setName(sl.last());

    QEventLoop convertEvent;
    m_Convert.setReadChannelMode(QProcess::MergedChannels);
    connect(&m_Convert, SIGNAL(readyRead()), this, SLOT(convert()));
    connect(this, SIGNAL(converted()), &convertEvent, SLOT(quit()));
    tt.process("Converting Video File");
    for (int i=0; i < sl.length(); i++) {
        QTextStream(stdout) << "\t" << sl.at(i) << endl;
    }
    if (QFile("/home/akiva/FrogCast/Cereproc/ffmpeg").exists()) {
        m_Convert.start("/home/akiva/FrogCast/Cereproc/ffmpeg", sl);
    } else {
        m_Convert.start("ffmpeg", sl);
    }
    convertEvent.exec();
    disconnect(&m_Convert, SIGNAL(finished(int)), this, SLOT(convert()));
    disconnect(this, SIGNAL(converted()), &convertEvent, SLOT(quit()));
    m_Convert.waitForFinished();
}
Anon
  • 2,267
  • 3
  • 34
  • 51
  • I have looked into this technique earlier. Writing each of the image on the disc is not a option because as it would take too much of time hitting the filesystem everytime. if there are 90 QImages, then it will hit the filesystem 90 times? then save the video again?. I am looking for a way to do this within the application main memory & hit the filesystem only when creating the `.mp4`. my requirement is very simple though "*How to create a video out of multiple QImages*" – TheWaterProgrammer Oct 03 '17 at 07:46
  • @Programist The one interesting thing to note is that the `ffmpeg` configuration you see above actually does not have any rendering overhead, unlike when you say, convert `avi` to `mp4` which can take hours. Here, a 2 hour long video with 90 slides would take a few seconds. That might offset the filesystem write penalty, especially if the alternative you seek does require rendering overhead. – Anon Oct 03 '17 at 07:51
  • you missed to provide the link to the video with 90 slides – TheWaterProgrammer Oct 03 '17 at 18:26