Qt : How to create a video from multiple QImages - qt

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.

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) + " ⟪Wiki🔊Book⟫.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();
}

Related

Unexplained time offset in QApplication event loop

I'm currently working with a program for predicting the locations of satellites in real-time. Something similar to this. The underlying library uses system time as input.
time_t now(time(0));
This program accurately predicts the real-time position of satellites when I run it on a C++ console application using Qt Creator.
The problem is when I use it in a fully-fledged Qt Gui application with a QApplication object in the main function. In the program, the prediction function is periodically by the timer event function. That way I update the positions every 2 seconds. Unfortunately, The output doesn't match (either on the GUI or when I print it). It is like the orbital propagator is using a different time when calculating the satellite positions.
void TrackingManager::timerEvent(QTimerEvent *event)
{
int nNumSats = m_Satellites.size() ;
//std::cout << __func__ << " - Number of satellites = " << nNumSats << std::endl;
std::vector<SatPosition> vSatPositions;
if (nNumSats >= 0)
{
time_t now(time(0));
std::cout << __func__ << "time(0) = " << asctime(gmtime(&now)) << std::endl;
for(int i = 0; i < nNumSats; i++)
{
// Get satellite names and calculate position, altitude etc
SatPosition spPos;
GetInstantPredict(m_Satellites[i], now, spPos);
vSatPositions.push_back(spPos);
}
emit UpdateSatPosition(vSatPositions);
}
}
Even more confusing, the program works fine when I run the debugger (GDB on Ubuntu). It is as if GDB somehow manages to "fix" the problem. Does this make any sense?

QAudioBuffer providing different data of the same song in different computers

I'm creating a music player for PC. I want to visualize the FFT of the song. I've crated an entire class that buffers 1024 points of data does the FFT and displays it (this is handled by another class). My program was developed in my laptop which uses Debian Testing x64. My work pc uses Centos 7 x64. When I compiled my program (both use Qt 5.7.0) on my work PC the FFT visualization was garbage. Snooping into my code I found that the sample type provided by QAudioBuffer from QAudioProbe was Signed (in my work PC) while it was float in my Laptop. Here is the code that is called whenever QAudioProbe emits that data has been buffered:
void SpectrumController::setAudioBuffer(QAudioBuffer buffer){
// Used to momentarily stop the process.
if (!enableBuffering) return;
// Only process stereo frames
if (buffer.format().channelCount() != 2) return;
if (buffer.format().sampleType() == QAudioFormat::SignedInt){
//qWarning() << "Signed";
QAudioBuffer::S16S *data = buffer.data<QAudioBuffer::S16S>();
bufferData(data,buffer.frameCount());
}
else if (buffer.format().sampleType() == QAudioFormat::UnSignedInt){
//qWarning() << "Unsigned";
QAudioBuffer::S16U *data = buffer.data<QAudioBuffer::S16U>();
bufferData(data,buffer.frameCount());
}
else if(buffer.format().sampleType() == QAudioFormat::Float){
//qWarning() << "Float";
QAudioBuffer::S32F *data = buffer.data<QAudioBuffer::S32F>();
bufferData(data,buffer.frameCount());
}
}
template<typename T>
void SpectrumController::bufferData(T *data, qint32 N){
for (qint32 i = 0; i < N; i++){
//if (qAbs(data[i].left) > largest){largest = qAbs(data[i].left); qDebug() << "Largest" << largest;}
//currentBuffer << ((qreal)data[i].left/(largest));
//qWarning() << "Added data" << currentBuffer.last();
currentBuffer << data[i].left;
if (datcounter < 100000){
*writer << data[i].left;
*writer << "\n";
datcounter++;
}
else if (writeFile->isOpen()){
qWarning() << "Closed file";
writeFile->close();
}
if (currentBuffer.size() == FFT_SIZE){
dataBuffer << currentBuffer;
currentBuffer.clear();
if (!isRunning) run();
}
What I ended up doing is writing, to a file, the first 100.000 points of data gathered by both my laptop and my work PC in order to plot them.
This is what I've got
What I think is that difference is in the base system's handling of the the mp3, which, in turn, is what Qt uses. I think is gstreamer. Centos uses a much older version. The plot on the right corresponds to my laptop while the plot on the left corresponds to my work pc.
Any ideas on how to fix this? Or am I just stuck with no way of accessising the raw audio data correctly?
UPDATE:
Even though this is not a Fix or anything like that, the data in the other channel (data[i].right) did have more appropiate data. I'm using the right channnel, for now.

Mouse click event in qt 3.0.3

Mouse button clicki am trying to create an automatic mouse click event at a particular co ordinate.
This source code moves the mouse pointer to the co ordinate region but it is not clicking.
please help me to solve this problem or suggest any new idea to automate mouse click event.
Note: i am using QT 3.0.3
void mMouseClickFunction()
{
QWidget *d = QApplication::desktop()->screen();
int w=d->width(); // returns desktop width
int h=d->height();
printf("w=%d\nh=%d\n",w,h);
int x,y;
printf("Enter the points...\n");
scanf("%d%d",&x,&y);
QApplication::desktop()->cursor().setPos(x,y);
QPoint pt(x,y);
std::cout << pt.x() << " " << pt.y() << std::endl;
QMouseEvent *e = new QMouseEvent(QEvent::MouseButtonPress, pt,Qt::LeftButton, 0);
QApplication::sendEvent(d, e);
std::cout << "in contentsMousePressEvent"<< e->x() << " " << e->y() << std::endl;
QMouseEvent *p = new QMouseEvent(QEvent::MouseButtonRelease, pt,Qt::LeftButton, 0);
QApplication::sendEvent(d, p);
std::cout << "in contentsMouseReleaseEvent"<< p->x() << " " << p->y() << std::endl;
}
QApplication::sendEvent sends an event internal to the QApplication, not a system wide event. You probably need to be system specific to send out an event like that. Here is the function call for windows:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646310(v=vs.85).aspx
But even with that kind of call, you will be limited to certain windows, unless you have UIAccess to be true, and your program is a signed application located in the right part of the harddrive.
EDIT: Here is a page that has some examples for sending input in Linux:
http://www.linuxquestions.org/questions/programming-9/simulating-a-mouse-click-594576/
Hope that helps.

Read exif metadata of images in Qt

In my Qt app I want to read exif data of images. QImage or QPixmap don't seem to provide such hooks.
Is there any API in Qt that allows reading exif without using external libraries like libexif?
EDIT: This is a duplicate of this
For me, the best choice was easyexif by Mayank Lahiri. You only need to add two files exif.cpp and exif.h to your project.
int main(int argc, char *argv[])
{
for (int i=1; i<argc; ++i){
QFile file(argv[i]);
if (file.open(QIODevice::ReadOnly)){
QByteArray data = file.readAll();
easyexif::EXIFInfo info;
if (int code = info.parseFrom((unsigned char *)data.data(), data.size())){
qDebug() << "Error parsing EXIF: code " << code;
continue;
}
qDebug() << "Camera model : " << info.Model.c_str();
qDebug() << "Original date/time : " << info.DateTimeOriginal.c_str();
} else
qDebug() << "Can't open file:" << argv[i];
}
return 0;
}
Try QExifImageHeader from qt extended framework. qtextended.org is not available for me? but you may search for other download mirrows.
QImageReader has a method named transformation() which is introduced in version 5.5, first you should try that.
You can also check the following link to see how it's done using Windows GDI in Qt, http://amin-ahmadi.com/2015/12/17/how-to-read-image-orientation-in-qt-using-stored-exif/

QFileSystemModel and QFileSystemWatcher delete from disk

I have a QTreeView which is populated through a reimplementation of QFileSystemModel. As far as I know, QFileSystemModel installs a QFileSystemWatcher on the rootPath. What I'm trying to do is notify in my program when a file is being deleted directicly on the rootPath but i havent found any signal o reimplemented function which provides me that information.
My application upload some files thrugh an ftp connection and when the file is fully uploaded i remove it from the location, so i want a notification from the reimplementation of QFileSystemModel when the file is deleted directicly (not from the remove method or something similar).
I Hope you can help me. I have searched a lot on the web but I cant find anything.
Cheers.
You can use the FileSystemModel's rowsAboutToBeRemoved signal (inherited from QAbstractItemModel).
It will be fired whenever a row is removed from the model. The parent, start and end parameters allow you to get to the filename (in column 0 of the children).
Sample code:
// once you have your model set up:
...
QObject::connect(model, SIGNAL(rowsAboutToBeRemoved(const QModelIndex&, int, int)),
receiver, SLOT(toBeRemoved(const QModelIndex&, int, int)));
...
// in receiver class:
public slots:
void toBeRemoved(const QModelIndex &parent, int start, int end) {
std::cout << start << " -> " << end << std::endl;
std::cout << parent.child(start, 0).data().typeName() << std::endl;
std::cout << qPrintable(parent.child(start, 0).data().toString()) << std::endl;
}
(Using std::cout isn't good practice with Qt I think, this is just to get you started.)
The other aboutToBe... signals from QAbstractItemModel can be used for the other events that happen on the filesystem.

Resources