Qt -- How to play audio files stored in QByteArray? - qt

I am working on a special application in Qt that stores its .mp3 audio files in a QSQLITE database as BLOB data.
With the following code I create a QByteArray:
QByteArray array = query->value(0).toByteArray();
Then I try to play the sound with a QMediaPlayer:
mediaPlayer.setMedia( QMediaContent( QUrl::fromEncoded(array) ) );
mediaPlayer.play();
But I unfortunately get this error:
DirectShowPlayerService::doSetUrlSource: Unresolved error code 800c000d
The main thing that I would like to achieve is to be able to play these .mp3 files that are stored in the QByteArray.
Note: Storing the pathway only in the database is not possible in that special circumstance.
I would really-very appreciate your help.
Thank you very much!

You need to provide the QByteArray as a QIODevice to the stream parameter of QMediaPlayer::setMedia(const QMediaContent & media, QIODevice * stream = 0).
Try the following:
QBuffer mediaStream(&array);
mediaPlayer.setMedia(QMediaContent(), &buffer);
mediaPlayer.play();

Related

QSoundEffect does not reload source

In my program it is possible to select a sound for an action. the sound is changeable, which means the .wav file gets replaced by another file.
This may cause the problem. When i replace the file and set the source of the QSoundEffect the sound does not change.
At the moment i am having a source like this:
//variable in .h
QUrl sound = "file:///"+soundDirectory+"sound.wav";
QUrl newSound = "file:///"+soundDirectory+"newSound.wav"; ;
QSoundEffect soundeffect;
//called in setSound() in .cpp
soundEffect.setSource(sound);
the sound loads without problem and i can play that sound.
i can change that sound with this code
// changing the sound in changeSound()
soundEffect.setSource(newSound);
this also works fine. the new sound is loaded and i can play it.
But it is also possible to change the sound files in the directory:
//changeSoundFile()
QFile::remove(sound.toLocalFile());
QFile::copy(anyPossibleSound.toLocalFile(), sound.toLocalFile());
This also works and replaces the sound file in its directory with another.
If I call setSound() after changing the file. It seems like the file does not get reload. and the sound is not changed. This is also the problem if changed the sound in between (call setSound on startup, then changeSound, then changeSoundFile and the setSound again)
Am I overlooking something?
It's not mentioned in the official docs, but you can find the implementation on GitHub:
void QSoundEffect::setSource(const QUrl &url) {
if (d->source() == url)
return;
d->setSource(url);
emit sourceChanged();
}
The file does not get reloaded because the URL is the same. The implementation holds an internal cache with the data that has been loaded before, so when you play the file, nothing change.
The API does not provide a way of forcing the reset of the data source. You have two alternatives:
Re-creating the QSoundEffect instance each time you modify the file.
Changing the file name:
// Create a temporal file
const auto uuid = QUuid::createUuid();
const auto new_filename = uuid.toString() + ".wav";
// Copy the file
QFile::remove(sound.toLocalFile());
QFile::copy(anyPossibleSound.toLocalFile(), new_filename);
sound = QUrl(new_filename);
// Use it
soundEffect.setSource(sound);

Import an External SQLite database to my project

I'm interested in importing an external SQLite database to my project.
When using the QT Quick Local Storage:
LocalStorage.openDatabaseSync("QQmlExampleDB", "1.0", "The Example QML SQL!", 1000000);
The problem is that, the program generates a NEW database, and if it's possible I'm interested in open an existing database.
Any idea?
Thank you very much!
Thanks all of you, with the information you have got me I could solve my problem, all the things I have had to do are:
First of all in main.cpp I set my offline Storage Path:
engine.setOfflineStoragePath(QString("./"));
Then I also add this code:
QDir dir("./Databases");
if (!dir.exists()) {
dir.mkpath(".");
}
QString new_name = QString(QCryptographicHash::hash(("nameofthecopiedDB"),QCryptographicHash::Md5).toHex());
QFile file(":/SQLite/nameofsourceDB.sqlite");
file.copy("./Databases/" + new_name + ".sqlite");
file.close();
Since I have the DB I would to use in my project in SQLite folder from my resources (:, indicates resources).
And then, in QML file, the openDatabaseSync() function:
basedades = Sql.LocalStorage.openDatabaseSync('nameofthecopiedDB',"1.0","Els meus entrenaments",1000000,"QSQLITE")
Thank you!
openDatabaseSync searches or creates dbs in the directory used for storing offline data.
That directory is identified by the data member offlineStoragePath of the QQmlEngine class.
To change it, you can use the the member method setOfflineStoragePath (see here for further details).
The first argument for openDatabaseSync is:
The name of the database passed to openDatabase()
See here for further details.

openDDS not generating typesupportc header

Im running into an issue with getting TAO_idl not generating typesupportc header. the dds_TAOv2_all.sln builds just fine and all the examples generate their respectful typesupport files including the typesupportc.h file that is necessary for the typesupport_var in my IDL file.
module X {
#pragma DCPS_DATA_TYPE "X::packet"
#pragma DCPS_DATA_KEY "X::packet from"
typedef sequence<octet> binary;
struct packet {
string from;
long packet_id;
long count;
long timer;
binary mydata;
};
};
the Xtypesupportc.h was genereated before, but ever since I had to reload DDS(DDS is compiled configured etc) when I run tao_idl and openDDS_idl with the x.idl file the xtypesupportc and xtypesupports don't get created and thus I can't register the type. any obvious thing that I am doing wrong? thank you.

Qt5: download a file without saving to HDD

I'm trying to download a file in Qt5, but the file must not be located on the HDD after download.
To clarify> My app will use a downloaded file to update some firmware, and I don't want the downloaded update to remain on the user's hard drive because it could get stolen.
So, I'm trying to make a QFile from QNetworkReply* but without saving it to some path on a hard drive.
I'm downloading a file using QNetworkAccessManager and storing the data into QNetworkReply. I always used to make a QFile with QNetworkReply*, but now I can't do that.
I have found the QTemporaryFile class where a file gets removed right after using it, but that still leaves user with some options of finding the file later.
I tried typecasting that QNetworkReply* as a QFile, but didn't manage to get that to work, seems like QFile can't be without a path on HDD.
Does anyone have any ideas how to do this, and how?
Thanks everyone.
Again not sure your intended end use case but since your data is small enough to hold in memory you can use a QByteArray or QBuffer and write into it from your QNetworkReply. QBuffer provides a QIODevice interface for the QByteArray so it may be a bit easier for you to work with.
Make sure to open the QBuffer for read/write. See the simple example below from the Qt documentation, http://doc.qt.io/qt-5/qbuffer.html#details, below:
QBuffer buffer;
char ch;
buffer.open(QBuffer::ReadWrite);
buffer.write("Qt rocks!");
buffer.seek(0);
buffer.getChar(&ch); // ch == 'Q'
buffer.getChar(&ch); // ch == 't'
buffer.getChar(&ch); // ch == ' '
buffer.getChar(&ch); // ch == 'r'
That should allow you to read back the data and use as required without creating a file on the system.

Qt: read video dimension without creating a video player

I need to read the dimensions of a given video file (its width and height), without constructing a video player, like Phonon, e.g. My question is which class I should use to get access to this data. I have already tried using QPixmap and QMovie, but niether of them supports *.mov.
Thank you!
Pavlo, you can try this:
QMediaContent media("myMovie.mov");
QSize resolution = media.canonicalResource().resolution();
The code uses QMediaResource class from Qt Mobility project. I haven't tried it yet and I suppose you need at least a correct backend (plugin that is capable of reading MOV format). I'm giving this answer only from API overview.
Hope this helps.
I finally solved my problem and I thought I'd share my solution with everybody else.
In the class constructor I initialize the following two variables:
media = new Phonon::MediaObject(this);
videoWidget = new Phonon::VideoWidget;
I connect a signal of media to a slot in my class:
connect(media,SIGNAL(stateChanged(Phonon::State,Phonon::State)),
this,SLOT(videoState(Phonon::State,Phonon::State)));
I let the user choose a video file:
QString filename = QFileDialog::getOpenFileName(this,tr("Choose video file"),QDir().homePath(),tr("Video files (*.mov *.mpg *.avi)"));
And apply this file to the media object:
media->setCurrentSource(filename);
Phonon::createPath(media,videoWidget);
Because media object is already connected to a slot, every change in media can be monitored with its help.
void VideoModuleDialog::videoState(Phonon::State newState, Phonon::State oldState)
{
if(newState == Phonon::PlayingState || newState == Phonon::StoppedState)
{
width->setText(QString().number(videoWidget->sizeHint().width()));
height->setText(QString().number(videoWidget->sizeHint().height()));
}
if(newState == Phonon::ErrorState)
{
QMessageBox::critical(this,tr("Video file error!"),
tr("Video file error: ") + media->errorString(),QMessageBox::Ok);
}
}
I must admit, however, that this code seems to me to be quite slow. Phonon library is used in my program only in one place, and this is here, in a dialog window where user can choose a video clip to embed, and i want the video dimensions to be read from file. It takes some time until this dialog window opens, so I guess, this solution is a bit too harsh for my problem. However, I was not able to find another solution. If there are different opinions as to the subject of this post, I'd be glad to hear them.

Resources