How can I use Qt to encrypt/decrypte/play a video? - qt

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).

Related

writeCharacters() of QXmlStreamWriter crashed when writting the content of a big file to QBuffer

The following code use writeCharacters with small buffer size to writing the content of big file, but it seems it only works when writing the content to a xml file, but writeCharacters() will crash when writting the content of a big file to QBuffer, any solution? Thanks.
env: qt opensource 4.8.7; Visual Studio 2010; Windows 10;
big file: https://1drv.ms/u/s!Ap_EAuwC9QkXijbujBQcQk4Hat_O?e=KemgUY
#include <QtCore/QCoreApplication>
#include <QFile>
#include <QXmlStreamWriter>
#include <QBuffer>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QByteArray mContentBuffer;
QByteArray arr;
int pos, filesize;
QFile file("C:\\Work\\bigfile.xar"); //Szie: 300Mb
if(!file.open(QFile::ReadOnly))
{
return -1;
}
mContentBuffer = file.readAll();
file.close();
//QFile profile("C:\\Work\\profile.xml");
//if(!profile.open(QFile::WriteOnly|QFile::Truncate))
//{
// return -1;
//}
QBuffer buffer;
buffer.open(QBuffer::ReadWrite);
QXmlStreamWriter stream(&buffer);
stream.setAutoFormatting(true);
stream.writeStartDocument();
stream.writeStartElement("Profile");
//stream.writeTextElement("Content", mContentBuffer.toBase64());
stream.writeStartElement("Content");
pos = 0;
filesize = mContentBuffer.size();
while(pos<filesize){
arr = mContentBuffer.mid(pos, 2000000);
stream.writeCharacters(arr.toBase64());
pos+=arr.size();
}
stream.writeEndElement();
stream.writeEndElement(); // Profile
stream.writeEndDocument();
return 0;
}
Here is the goal for writing a big file into a QBuffer.
bool profileModified()
{
bool result = true;
QFile profile("C:\\Work\\profile.xml");
if(profile.exists())
{
QBuffer buffer;
buffer.open(QBuffer::ReadWrite);
QXmlStreamWriter stream(&buffer);
exportProfile(stream);
profile.open(QFile::ReadOnly);
QByteArray profileArr = profile.readAll();
buffer.seek(0);
QByteArray bufferArr = buffer.buffer();
result = (array_compare(profileArr, bufferArr) != 0);
profile.close();
}
return result;
}

How to implement simple audio loopback in QT

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();
}

Qt 4.8 Why my QIODevice not output a text in this code?

If used QTextStream console(stdout) - all work just fine, but if I wrote custom IODevice, after qInstallMsgHandler() no text in console
main.cpp
#include "remoteconsole.h"
#include <QCoreApplication>
#include <QDateTime>
#include <QTimer>
QTextStream *out;
void logOutput(QtMsgType type, const char *msg)
{
QString debugdate = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz");
*out << debugdate << " " << type << msg << endl;
}
int main(int argc, char *argv[])
{
int i;
QCoreApplication a(argc, argv);
RemoteConsole * remote = new RemoteConsole(&a);
QTextStream console((QIODevice *)remote);
out = &console;
qDebug() << "start qInstallMsgHandler";
qInstallMsgHandler(logOutput);
qDebug() << "end qInstallMsgHandler"<<endl;
for(i=0;i<10;i++){
qDebug() << i<<endl;
}
QTimer *timer = new QTimer();
a.connect(timer, SIGNAL(timeout()), &a, SLOT(quit()));
timer->start(5000);
a.exec();
return 0;
}
my IODevice implementation in file remoteconsole.h .cpp
#ifndef REMOTECONSOLE_H
#define REMOTECONSOLE_H
#include <QIODevice>
#include <QDebug>
class RemoteConsole: public QIODevice
{
Q_OBJECT
public:
RemoteConsole(QObject *parent);
~RemoteConsole();
private:
Q_DISABLE_COPY(RemoteConsole)
protected:
qint64 readData(char* data, qint64 maxSize);
qint64 writeData(const char* data, qint64 maxSize);
};
#endif // REMOTECONSOLE_H
#include "remoteconsole.h"
RemoteConsole::RemoteConsole(QObject* parent=0) :
QIODevice(parent)
{
}
RemoteConsole::~RemoteConsole(){}
qint64 RemoteConsole::readData(char *data, qint64 maxlen){
qDebug() << data <<endl;
return maxlen;
}
qint64 RemoteConsole::writeData(const char *data, qint64 len){
printf("writeData");
qDebug() << data <<endl;
return len;
}
In future I want to expand this code with QTCPServer, that send debug outputs to client connected to the device by telnet or nc.
You don't get any text in console after qInstallMsgHandler call because you send all debug data into your RemoteConsole object.
Also you've got some other problems in your code.
You should call QIODevice::open before you can operate on that device.
In the RemoteConsole::writeData function you will have an infinite loop because you use qDebug() there. qDebug() will call logOutput which will call RemoteConsole::writeData again.

QProcess disable stdout redirection

I want to start a process from a QT app and catch its termination event. Its done with the method QProcess::start(). But unlike in startDetached(), the standard output of the process is redirected to a buffer. I don't want that.
I can't find how to disable it. An ugly workaround is to call setStandardOutputFile("/dev/stdout")
test.h
#ifndef MY_TEST_H
#define MY_TEST_H
#include <QCoreApplication>
class MyApp : public QCoreApplication {
Q_OBJECT
private Q_SLOTS:
void subprocessStarted();
void subprocessFinished(int);
public:
MyApp( int & argc, char ** argv );
};
#endif
test.cpp
#include "test.h"
#include <QProcess>
#include <QCoreApplication>
#include <stdio.h>
#define ENTRY printf("%s\n", __PRETTY_FUNCTION__)
MyApp::MyApp( int & argc, char ** argv ) : QCoreApplication(argc, argv) {
ENTRY;
QProcess *process = new QProcess();
//process->setStandardOutputFile("/dev/stdout");
process->start("/bin/echo aaa");
bool b;
b = connect(process, SIGNAL(started()), SLOT(subprocessStarted()));
printf("connect started %d\n", b);
b = connect(process, SIGNAL(finished(int)), SLOT(subprocessFinished(int)));
printf("connect finished %d\n", b);
}
void MyApp::subprocessStarted() {
ENTRY;
}
void MyApp::subprocessFinished(int ret) {
ENTRY;
printf("%d\n", ret);
}
int main(int argc, char *argv[]) {
ENTRY;
MyApp a(argc, argv);
return a.exec();
}
Does QProcess::closeReadChannel(ProcessChannel channel) work for you?
Closes the read channel channel. After calling this function, QProcess
will no longer receive data on the channel. Any data that has already
been received is still available for reading. Call this function to
save memory, if you are not interested in the output of the process.
Like this-
QProcess *process = new QProcess();
process->start("/bin/echo aaa");
process->closeReadChannel(QProcess::StandardOutput);
process->closeReadChannel(QProcess::StandardError);

Save QList<int> to QSettings

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) ...

Resources