In QT5 we have QVideoFrame::Format_RGB24 format (i have RGB images without alpha channel).
In QT6 (6.2.0) this format is missing.
Why this format has been removed?
What's the best way to convert RGB -> RGBX (A) in QT6?
If you are using QImage (or you can convert it to QImage) then you can convert the format to QImage::Format_RGBX8888 and then copy the bits:
#include <QGuiApplication>
#include <QImage>
#include <QVideoFrame>
#include <QVideoFrameFormat>
int main(int argc, char *argv[])
{
QGuiApplication a(argc, argv);
QImage image(100, 100, QImage::Format_RGB888);
image.fill(QColor(50, 100, 200));
if(image.format() == QImage::Format_Invalid)
return EXIT_FAILURE;
QVideoFrameFormat video_frame_format(image.size(), QVideoFrameFormat::Format_RGBX8888);
QImage rgbx = image.convertToFormat(QVideoFrameFormat::imageFormatFromPixelFormat(video_frame_format.pixelFormat()));
QVideoFrame video_frame(video_frame_format);
if(!video_frame.isValid() || !video_frame.map(QVideoFrame::WriteOnly)){
qWarning() << "QVideoFrame is not valid or not writable";
return EXIT_FAILURE;
}
int plane = 0;
std::memcpy(video_frame.bits(plane), rgbx.bits(), video_frame.mappedBytes(plane));
video_frame.unmap();
qDebug() << video_frame << rgbx.format();
return EXIT_SUCCESS;
}
Related
I need to loopback audio recorded from the microphone straight to the speaker using QT (qt 5.7 on Windows...) - assume I can't use window's internal mic->speaker loopback (enable "listen to this device" on the microphone panel).
Any direction how to do that?
Based on the discussion on https://forum.qt.io/topic/19960/qaudioinput-redirect-to-qaudiooutput/3
#include <iostream>
#include <QCoreApplication>
#include <QAudioInput>
#include <QAudioOutput>
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
const auto decideAudioFormat = [](const QAudioDeviceInfo& devInfo)
{
QAudioFormat format;
format.setSampleRate(8000);
format.setChannelCount(1);
format.setSampleSize(16);
format.setCodec("audio/pcm");
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt);
if (devInfo.isFormatSupported(format))
{
return format;
}
else
{
std::cerr << "Raw audio format not supported by backend, cannot play audio.\n";
throw 0;
}
};
QAudioInput audioInput(decideAudioFormat(QAudioDeviceInfo::defaultInputDevice()));
QAudioOutput audioOutput(decideAudioFormat(QAudioDeviceInfo::defaultOutputDevice()));
audioOutput.start(audioInput.start());
return app.exec();
}
Adding a buffer in-between
I've encountered this issue before. If I'm not mistaken, the read() and write() functions share the same pos() tracker. This is what happens:
QBuffer buffer;
buffer.open(QBuffer::ReadWrite); // buffer.pos() == 0
buffer.write(someData, 5); // Writes in positions 0 -- 4, buffer.pos() == 5;
buffer.write(someData, 5); // Writes in positions 5 -- 9, buffer.pos() == 10;
buffer.read(otherBuffer.data(), 10); // Tries to read from position 10 onwards. No data found
2 solutions:
Implement your own, separate read-position and write-position trackers. Then, call seek() in readData() and writeData() to set pos() -- point to the end of the data before writing, but point to the middle of the data before reading
Use 2 separate buffers, and copy bytes from the input buffer into the output buffer
So, with separate buffers:
#include <iostream>
#include <cassert>
#include <QCoreApplication>
#include <QAudioInput>
#include <QAudioOutput>
#include <QBuffer>
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QBuffer rdBuff;
QBuffer wrBuff;
wrBuff.open(QBuffer::WriteOnly);
rdBuff.open(QBuffer::ReadOnly);
QObject::connect(&wrBuff, &QIODevice::bytesWritten, [&wrBuff, &rdBuff](qint64)
{
// remove all data that was already read
rdBuff.buffer().remove(0, rdBuff.pos());
// set pointer to the beginning of the unread data
const auto res = rdBuff.seek(0);
assert(res);
// write new data
rdBuff.buffer().append(wrBuff.buffer());
// remove all data that was already written
wrBuff.buffer().clear();
wrBuff.seek(0);
});
const auto decideAudioFormat = [](const QAudioDeviceInfo& devInfo)
{
QAudioFormat format;
format.setSampleRate(8000);
format.setChannelCount(1);
format.setSampleSize(16);
format.setCodec("audio/pcm");
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt);
if (devInfo.isFormatSupported(format))
{
return format;
}
else
{
std::cerr << "Raw audio format not supported by backend, cannot play audio.\n";
throw 0;
}
};
QAudioInput audioInput(decideAudioFormat(QAudioDeviceInfo::defaultInputDevice()));
QAudioOutput audioOutput(decideAudioFormat(QAudioDeviceInfo::defaultOutputDevice()));
audioInput.start(&wrBuff);
audioOutput.start(&rdBuff);
return app.exec();
}
Is there a way to convert between these datatypes? I'm working with Qt but still need some of glib capabilities and I haven't found a way to do this. I need to get a list of the installed applications with GAppInfo and show it in a QListView and to do so I need to get the icon for those applications. Extracting it using g_app_info_get_icon returns a GIcon and what I need to work with is a QIcon in order to get it's QVariant.
GIcon does not provide the actual pixmap for the icon.
You need to load an actual pixmap by requesting icon of certain size.
#include <gio/gdesktopappinfo.h>
#include <gtk/gtk.h>
#include <QtGui>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QIcon icon;
GAppInfo *appInfo = (GAppInfo *)g_desktop_app_info_new("vlc.desktop");
GIcon *gicon = g_app_info_get_icon(appInfo);
QList<int> sizes; sizes << 16 << 24 << 32 << 48 << 64;
foreach (int size, sizes) {
GtkIconInfo *iconInfo = gtk_icon_theme_lookup_by_gicon(gtk_icon_theme_get_default(), gicon, size, (GtkIconLookupFlags)0);
GdkPixbuf *pixbuf = gtk_icon_info_load_icon(iconInfo, NULL);
if (pixbuf == NULL)
continue;
QImage image(
gdk_pixbuf_get_pixels(pixbuf),
gdk_pixbuf_get_width(pixbuf),
gdk_pixbuf_get_height(pixbuf),
gdk_pixbuf_get_rowstride(pixbuf),
QImage::Format_ARGB32);
g_object_unref(pixbuf);
image.save("icon-" + QString::number(size) + ".png");
icon.addPixmap(QPixmap::fromImage(image));
}
g_object_unref(gicon);
return 0;
}
I am looking for a way to encrypt an video file and then use decrypt it to ram and play it directly.
setMedia takes a QIOdevice as second argument:
#include <QMediaPlayer>
#include <QApplication>
#include <QFile>
int main(int argc, char ** argv)
{
QApplication app(argc,argv);
QString fileName = app.arguments().at(1);
QFile io(fileName);
io.open(QFile::ReadOnly);
QMediaPlayer player;
player.setMedia(QUrl("test.mp3"), &io);
player.play();
return app.exec();
}
but just in case you really mean QDataStream:
QDataStream is buffered io, QIODevice is direct io, they're not compatible, so you have to double buffer like this:
#include <QMediaPlayer>
#include <QApplication>
#include <QFile>
#include <QBuffer>
#include <QDataStream>
int main(int argc, char ** argv)
{
QApplication app(argc,argv);
QString fileName = app.arguments().at(1);
// our double buffer
QByteArray bufferSpace;
// our stream on which we can put "media" data
QDataStream stream(&bufferSpace, QIODevice::WriteOnly);
// this is just demo data
QFile io(fileName);
io.open(QFile::ReadOnly);
stream << io.readAll();
// open an IO Device on our buffer
QBuffer buffer(&bufferSpace);
buffer.open(QBuffer::ReadOnly);
// give the IO to the media player
QMediaPlayer player;
player.setMedia(QUrl("test.mp3"), &buffer);
player.play();
return app.exec();
}
edit
here's a faster version of that "crypto" code you posted without using a buffer for the entire file:
#include <QMediaPlayer>
#include <QApplication>
#include <QFile>
#include <QBuffer>
#include <QDataStream>
static const unsigned char key = 0xAB;
class MyFunnyCrypto : public QFile /*or subclass any other IO*/
{
protected:
virtual qint64 readData(char *data, qint64 maxSize)
{
qint64 r = QFile::readData(data, maxSize);
if (r > 0) {
for (qint64 i = 0; i < r; i++) {
data[i] = data[i]^key;
}
}
return r;
}
};
int main(int argc, char ** argv)
{
QApplication app(argc,argv);
QString fileName = app.arguments().at(1);
MyFunnyCrypto io;
io.setFileName(fileName);
io.open(QFile::ReadOnly);
// give the IO to the media player
QMediaPlayer player;
player.setMedia(QUrl("test.mp3"), &io);
player.play();
return app.exec();
}
Thanks to #aep .
It doesn't have anything to do with QDataStream, and it's quite simple.
Encryption:
unsigned char key = 0xAB;
QFile file("test.mp3");
file.open(QIODevice::ReadOnly);
QByteArray byteArray = file.readAll();
for(int i=1024;i<byteArray.length();i++){
byteArray[i] = byteArray[i]^key;
}
file.close();
QFile encrypted("encrypted.mp3");
encrypted.open(QIODevice::WriteOnly);
encrypted.write(byteArray);
encrypted.close();
And decryption:
unsigned char key = 0xAB;
QFile file("encrypted.mp3");
file.open(QIODevice::ReadOnly);
auto byteArray = file.readAll();
for(int i=1024;i<byteArray.length();i++){
byteArray[i] = byteArray[i]^key;
}
QBuffer buffer(&byteArray);
buffer.open(QBuffer::ReadOnly);
// give the IO to the media player
QMediaPlayer player;
player.setMedia(QUrl(), &buffer);
player.play();
In the for-loop, I want to declare i as qint64 rather than int. But the compiler shows QByteArray::operator[](int i).
I'm working with a buffer and I'm trying to get a string from it, but isnt working...
Example:
*void myFunc(QDataStream& in)
{
quint8 v;
in >> v;
// Ok, I caught v value successfuly
QString s;
in >> s;
// Didnt work :<
}*
The string lenght is stored on 2 first bytes...
Thanks
If the string was not written as a QString, you need to read its length and content separately.
quint8 v;
in >> v;
quint16 length = 0;
in >> length;
// the string is probably utf8 or latin
QByteArray buffer(length, Qt::Uninitialized);
in.readRawData(buffer.data(), length);
QString string(buffer);
You might have to change the endianness of the QDataStream with QDataStream::setByteOrder before reading the 16-bit length.
We should really see the writing code and how you create the QDataStream. I tried with the following sample, and in this case your function works very well:
#include <QCoreApplication>
#include <QDebug>
#include <QDataStream>
#include <QBuffer>
void myFunc(QDataStream& in)
{
quint8 v;
in >> v;
qDebug() << v;
// Ok, I caught v value successfuly
QString s;
in >> s;
qDebug() << s;
// Didnt work :<
}
int main(int argc, char ** argv) {
QCoreApplication a(argc, argv);
QBuffer buffer;
buffer.open(QBuffer::ReadWrite);
// write test data into the buffer
QDataStream out(&buffer);
quint8 ival = 42;
QString sval = "Qt";
out << ival;
out << sval;
// read back data
buffer.seek(0);
myFunc(out);
return a.exec();
}
Output when executed:
$ ./App
42
"Qt"
I want to save a QList<int> to my QSettings without looping through it.
I know that I could use writeArray() and a loop to save all items or to write the QList to a QByteArray and save this but then it is not human readable in my INI file..
Currently I am using the following to transform my QList<int> to QList<QVariant>:
QList<QVariant> variantList;
//Temp is the QList<int>
for (int i = 0; i < temp.size(); i++)
variantList.append(temp.at(i));
And to save this QList<Variant> to my Settings I use the following code:
QVariant list;
list.setValue(variantList);
//saveSession is my QSettings object
saveSession.setValue("MyList", list);
The QList is correctly saved to my INI file as I can see (comma seperated list of my ints)
But the function crashes on exit.
I already tried to use a pointer to my QSettings object instead but then it crashes on deleting the pointer ..
QSettings::setValue() needs QVariant as a second parameter. To pass QList as QVariant, you have to declare it as a Qt meta type. Here's the code snippet that demonstrates how to register a type as meta type:
#include <QCoreApplication>
#include <QDebug>
#include <QMetaType>
#include <QSettings>
#include <QVariant>
Q_DECLARE_METATYPE(QList<int>)
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qRegisterMetaTypeStreamOperators<QList<int> >("QList<int>");
QList<int> myList;
myList.append(1);
myList.append(2);
myList.append(3);
QSettings settings("Moose Soft", "Facturo-Pro");
settings.setValue("foo", QVariant::fromValue(myList));
QList<int> myList2 = settings.value("foo").value<QList<int> >();
qDebug() << myList2;
return 0;
}
You might have to register QList as a meta-type of its own for it to work. This is a good starting point to read up on meta-types in Qt: http://qt.nokia.com/doc/4.6/qmetatype.html#details .
I was also struggling with this ... and I believe I now have a decent solution.
I hope this saves someone the trouble, it caused me.
#include <QCoreApplication>
#include <QSettings>
#include <QList>
#include <QDataStream>
#include <QVariant>
#include <QVariantList>
#include <QDebug>
#include <deque>
template <class T> static QVariant toVariant(const QList<T> &list)
{
QVariantList variantList;
variantList.reserve(list.size());
for (const auto& v : list)
{
variantList.append(v);
}
return variantList;
}
template <class T> static QList<T> toList(const QVariant &qv)
{
QList <T> dataList;
foreach(QVariant v, qv.value<QVariantList>()) {
dataList << v.value<T>();
}
return dataList;
}
void Gen()
{
QList<QString> data {"hello", "world","how", "are", "you"};
QList<int> ages {10,20,30,40};
QSettings setup("stuff.ini", QSettings::IniFormat);
setup.beginWriteArray("rules");
for (int groups=0;groups<3;groups++)
{
setup.setArrayIndex(groups);
setup.setValue("rule",QString("Rule-%1").arg(groups));
setup.setValue("data", toVariant (data));
setup.setValue("ages", toVariant (ages));
}
setup.endArray();
setup.sync();
}
void Read()
{
QSettings setupR("stuff.ini", QSettings::IniFormat);
int rule_count = setupR.beginReadArray("rules");
for (int groups=0;groups<rule_count;groups++)
{
setupR.setArrayIndex(groups);
QString nameRead = setupR.value("rule").toString();
QList<QString> dataRead = toList<QString>(setupR.value("data"));
qDebug() << "Rule " << groups;
qDebug() << "Rule Read" << nameRead;
qDebug() << "Data Read2" << dataRead;
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// Write
Gen();
// Read
Read();
exit(0);
//return a.exec();
}
You should end up with an INI file which looks like this ...
[rules]
1\ages=10, 20, 30, 40
1\data=hello, world, how, are, you
1\rule=Rule-0
2\ages=10, 20, 30, 40
2\data=hello, world, how, are, you
2\rule=Rule-1
3\ages=10, 20, 30, 40
3\data=hello, world, how, are, you
3\rule=Rule-2
size=3
The nice thing here is you can edit this outside of QT (Just be careful) ...