I tried to play .wav file in Qt by using QSound::play
I've tried this code:
QSound::play("airplane.wav");
No error when build but when run there is no sound?!
This rang a bell for me, so I found the code I use to handle sounds. Our platform is Windows, so this is what works for us. I wrapped all this up in a player class. My notes to myself said that QSound wants absolute paths, in platform format (found by examining the QSound code). So try getting the file path by something like this
// (note the "sSoundPath" variable is set to where we store our sound files).
static const QString sSoundPath("./resources/sounds/");
elsewhere...
// QSound wants absolute paths, in platform format
QFileInfo fileInfo(soundFile);
if (fileInfo.isRelative())
{
// we assume one of our own sound files in a relative path
fileInfo.setFile(sSoundPath + soundFile);
fileInfo.makeAbsolute();
}
if (!fileInfo.exists())
{
return false;
}
mSoundFile = QDir::toNativeSeparators(fileInfo.filePath());
Now you can go ahead and try to play the sound file.
I have spent countless days on a similar issue. Basically, I found out that QSound does not support wave files with 44100 Hz sample rate. Check out my discovery at QT5 QSound does not play all wave files
A side note, QSound does not support QT resources, in case you are using one. A workaround is to copy the resource into a file, and then play that file with QSound from the hard drive. Hopefully this info helps.
Related
How can I add chapters to MP4 files with GStreamer 1.18?
I have a Visual Studio 2015 C++ project that writes a video (H264) and audio (aac) stream to the disk using mp4mux. Now I would like to add chapters to the MP4 file that are compatible with regular video players like VLC.
I have tried to follow the documentation to create a GstToc and a dummy GstTocEntry, but it doesn't appear to be written to the file:
GstToc* toc = gst_toc_new(GstTocScope::GST_TOC_SCOPE_CURRENT);
GstTocEntry* new_entry = gst_toc_entry_new(GstTocEntryType::GST_TOC_ENTRY_TYPE_CHAPTER, "some_uid");
gst_toc_entry_set_start_stop_times(new_entry, 0, 50);
gst_toc_append_entry(toc, new_entry);
I then also tried to generate a new toc event and pass it to the video GstElement vin:
gboolean result = gst_element_send_event(vin, gst_event_new_toc(toc, true));
Did I miss anything in order to map the GstToc to the video stream? Do I need to tell mp4mux to process the toc? Or is this not supported?
GStreamer documentation seems to imply, that there is GstToc support in mp4mux:
Below hollow bullet point o indicate no support and filled bullets ***
indicate that this feature is handled.
MP4: * elst
The elst atom contains a list of edits. Each edit consists of (length, start, play-back speed).
I didn't find much on the elst atom or what an edit is. I tried using GST_TOC_ENTRY_TYPE_EDITION instead of GST_TOC_ENTRY_TYPE_CHAPTER, but that didn't change anything.
This page mentions "preliminary code in MP4 supporting chapters" in GStreamer.
I have seen ways to inject metadata files into existing mp4 files with ffmpeg and other tools which are not available on our system unfortunately. I could try to inject the chapters into the mp4 file header manually, but I'd very much like to avoid this post-processing step for obvious reasons. Any help would be greatly appreciated!
I want to make a music player and I want to filter out files not audio file on opening.
Should I use QAudioDecoder?
But every file I checked with QAudioDecoder tells me the same codec "audio/pcm".
QAudioDecoder decoder;
decoder.setSourceFilename(fileUrl.toLocalFile());
qDebug() << decoder.audioFormat().codec();
How do I know if the audio file's format is supported by Qt media player by not just checking if the file's name ends with ".mp3" or ".wav"?
And I found that some files' duration incorrect when playing on my music player.
But when I play the file with other music player apps, it gives correct duration on other music players.
Or my app can't play some files but others can.
the console says :
DirectShowPlayerService::doSetUrlSource: Unresolved error code
0x80070002 (?t?Χ??????w?????C)
but after I change the file name, it can be opened.
How should I fix those on my music player instead of fixing the files' probably wrong or unsupported formats one by one?
I wrote this code to check if the file I opened is a supported audio file.
QMediaPlayer audioChecker;
audioChecker.setMedia(fileUrl);
qDebug() << audioChecker.media().canonicalUrl().fileName();
qDebug() << audioChecker.isAudioAvailable();
if(audioChecker.error() == QMediaPlayer::NoError) {
qDebug() << "no error";
}
if(audioChecker.error() == QMediaPlayer::FormatError) {
qDebug() << "format error";
}
and it tells me no error no matter what file I tested.
console:
"musicplayer.exe"
false
no error
"musicplayer.exe"
false
no error
"musicplayer.ilk"
false
no error
"musicplayer.exe"
false
no error
"a song.mp3"
false
no error
But how can files not audio file get no error?
Why do audio file's audio not available?
Never mind. I just read that setMedia() return immediately and doesn't wait for the media to be loaded. so it's normal it gets no audio and no error because it's not loaded.
I guess I'll make a thread class to check my file.
By the way, incorrect duration of the file is fixed somehow. Does it relate to LAV Splitter?
From Qt's documentation:
For playing media or audio files that are not simple, uncompressed audio, you can use the QMediaPlayer C++ class […] The compressed audio formats supported does depend on the operating system environment, and also what media plugins the user may have installed.
A simple example of how to use the QMediaPlayer class:
player = new QMediaPlayer;
// ...
player->setMedia(QUrl::fromLocalFile("/Users/me/Music/coolsong.mp3"));
player->setVolume(50);
player->play();
To verify that the codec is supported, you can use the error() method of the QMediaPlayer class which will return you an error code (see the documentation).
So, after calling setMedia(), you can do something like:
if (player->error() == QMediaPlayer::FormatError)
{
// Codec/format unsupported
}
About the error code you get when opening files:
check that you have no \ characters in your path (if you have some, escape them with another \)
check if you have spaces, special characters, etc.
About how to check audio format in file without check its suffix, there's a tool names mediainfo, with the command line tool run as below:
mediainfo -f [filepath]
You'll get the full information about the file, both video and audio if they exists. And among these parameters, there's a "format" value under "Audio" category, that indicates the actual audio format inside. eg. AAC/AC3
About the file can be played after name changed, I consider maybe there are some space characters in the filename, or the Player just can't access the file specified by name.
I know that this question is a duplicate. But in other questions, people advise Phonon which is not available in Qt 5+ (I'm using 5.4).
I also tried to use QAudioOutput:
QFile inputFile;
inputFile.setFileName("/home/efog/G6_Build/sound.wav");
inputFile.open(QIODevice::ReadOnly);
QAudioFormat format;
format.setSampleRate(44100);
format.setChannelCount(2);
format.setSampleSize(16);
format.setCodec("audio/wav");
QAudioOutput *audio = new QAudioOutput( format, 0);
audio->start(&inputFile);
But it is not working, same as QSound:
QSound::play("/home/efog/G6_Build/sound.wav");
NAS and GStreamer are installed. So, how can I play wav files?
Sometimes QSound takes some time to play when it first loads the file. Try creating a QSound object with the file, and playing it afterwards, and maybe give it a little time.
QSound *sound = new QSound("/home/efog/G6_Build/sound.wav");
sound->play();
And are you sure, your wav file is really a wav file? I've seen audio files with wav extension, but actually they were mp3 files. Maybe try with another audio file first.
Below is the code I am using to play a video
QFile* file =new QFile(“C:\\Video\\test.avi”);
media->setCurrentSource(Phonon::MediaSource(file));
media->play();
Using this code the playback fails -what I see is the play bar at the bottom but the video never starts.
If I change the code to the following everything works as expected
media->setCurrentSource(Phonon::MediaSource(“C:\\Video\\test.avi”));
media->play();
Are there additional initialization steps required when using an iodevice? Ultimately my code will be using a custom iodevice which is not working as well.
This is an old post, but I wanted to clear up any confusion out in case it will help someone in the future.
QT does allow you to pass Phonon::MediaSource() a QIODevice. We successfully deployed our solution by creating our own subclass of QIODevice.
The reason it was not working for me was QT was having an issue with the codec I was using. When you use the QIO device you don't get the same format support as you would if you pass a string.
One other thing to note, while this solution works great on windows. On a mac when using the QIO device the entire file will be loaded into memory before it plays. In my case this was a deal breaker. Having an encrypted file is usless if the first thing you do is de-crypt the entire file and load it into memory.
From the Phonon::MediaSource documentation:
Warning: On Windows, we only support QIODevices containing the avi,
mp3, or mpg formats. Use the constructor that takes a file name to
open files (the Qt backend does not use a QFile internally).
I think that the last line should answer your question. Instead of a QFile, you can use a QString, or call the function QFile::fileName like this:
QFile* file =new QFile(“C:\\Video\\test.avi”);
media->setCurrentSource(Phonon::MediaSource(file->fileName()));
media->play();
If you take a careful look in the [Phonon Module docu][1], you will see that MediaSource cannot be constructed with QFile*.
By the way I don't see in your code any phonon paths. At least you should create audio sink and connect it with the mediaobject:
Phonon::AudioOutput *audioOut = new PhononAudioOutpu(Phonon::MusicCategory);//or the category you need
Phonon::createPath(mediaObject, audioOutput);
mediaObject->play();
Works fine with QFile
I would like to open a small video file and map every frames in memory (to apply some custom filter). I don't want to handle the video codec, I would rather let the library handle that for me.
I've tried to use Direct Show with the SampleGrabber filter (using this sample http://msdn.microsoft.com/en-us/library/ms787867(VS.85).aspx), but I only managed to grab some frames (not every frames!). I'm quite new in video software programming, maybe I'm not using the best library, or I'm doing it wrong.
I've pasted a part of my code (mainly a modified copy/paste from the msdn example), unfortunately it doesn't grabb the 25 first frames as expected...
[...]
hr = pGrabber->SetOneShot(TRUE);
hr = pGrabber->SetBufferSamples(TRUE);
pControl->Run(); // Run the graph.
pEvent->WaitForCompletion(INFINITE, &evCode); // Wait till it's done.
// Find the required buffer size.
long cbBuffer = 0;
hr = pGrabber->GetCurrentBuffer(&cbBuffer, NULL);
for( int i = 0 ; i < 25 ; ++i )
{
pControl->Run(); // Run the graph.
pEvent->WaitForCompletion(INFINITE, &evCode); // Wait till it's done.
char *pBuffer = new char[cbBuffer];
hr = pGrabber->GetCurrentBuffer(&cbBuffer, (long*)pBuffer);
AM_MEDIA_TYPE mt;
hr = pGrabber->GetConnectedMediaType(&mt);
VIDEOINFOHEADER *pVih;
pVih = (VIDEOINFOHEADER*)mt.pbFormat;
[...]
}
[...]
Is there somebody, with video software experience, who can advise me about code or other simpler library?
Thanks
Edit:
Msdn links seems not to work (see the bug)
Currently these are the most popular video frameworks available on Win32 platforms:
Video for Windows: old windows framework coming from the age of Win95 but still widely used because it is very simple to use. Unfortunately it supports only AVI files for which the proper VFW codec has been installed.
DirectShow: standard WinXP framework, it can basically load all formats you can play with Windows Media Player. Rather difficult to use.
Ffmpeg: more precisely libavcodec and libavformat that comes with Ffmpeg open- source multimedia utility. It is extremely powerful and can read a lot of formats (almost everything you can play with VLC) even if you don't have the codec installed on the system. It's quite complicated to use but you can always get inspired by the code of ffplay that comes shipped with it or by other implementations in open-source software. Anyway I think it's still much easier to use than DS (and much faster). It needs to be comipled by MinGW on Windows, but all the steps are explained very well here (in this moment the link is down, hope not dead).
QuickTime: the Apple framework is not the best solution for Windows platform, since it needs QuickTime app to be installed and also the proper QuickTime codec for every format; it does not support many formats, but its quite common in professional field (so some codec are actually only for QuickTime). Shouldn't be too difficult to implement.
Gstreamer: latest open source framework. I don't know much about it, I guess it wraps over some of the other systems (but I'm not sure).
All of this frameworks have been implemented as backend in OpenCv Highgui, except for DirectShow. The default framework for Win32 OpenCV is using VFW (and thus able only to open some AVI files), if you want to use the others you must download the CVS instead of the official release and still do some hacking on the code and it's anyway not too complete, for example FFMPEG backend doesn't allow to seek in the stream.
If you want to use QuickTime with OpenCV this can help you.
I have used OpenCV to load video files and process them. It's also handy for many types of video processing including those useful for computer vision.
Using the "Callback" model of SampleGrabber may give you better results. See the example in Samples\C++\DirectShow\Editing\GrabBitmaps.
There's also a lot of info in Samples\C++\DirectShow\Filters\Grabber2\grabber_text.txt and readme.txt.
I know it is very tempting in C++ to get a proper breakdown of the video files and just do it yourself. But although the information is out there, it is such a long winded process building classes to hand each file format, and make it easily alterable to take future structure changes into account, that frankly it just is not worth the effort.
Instead I recommend ffmpeg. It got a mention above, but says it is difficult, it isn't difficult. There are a lot more options than most people would need which makes it look more difficult than it is. For the majority of operations you can just let ffmpeg work it out for itself.
For example a file conversion
ffmpeg -i inputFile.mp4 outputFile.avi
Decide right from the start that you will have ffmpeg operations run in a thread, or more precisely a thread library. But have your own thread class wrap it so that you can have your own EventAgs and methods of checking the thread is finished. Something like :-
ThreadLibManager()
{
List<MyThreads> listOfActiveThreads;
public AddThread(MyThreads);
}
Your thread class is something like:-
class MyThread
{
public Thread threadForThisInstance { get; set; }
public MyFFMpegTools mpegTools { get; set; }
}
MyFFMpegTools performs many different video operations, so you want your own event
args to tell your parent code precisely what type of operation has just raised and
event.
enum MyFmpegArgs
{
public int thisThreadID { get; set; } //Set as a new MyThread is added to the List<>
public MyFfmpegType operationType {get; set;}
//output paths etc that the parent handler will need to find output files
}
enum MyFfmpegType
{
FF_CONVERTFILE = 0, FF_CREATETHUMBNAIL, FF_EXTRACTFRAMES ...
}
Here is a small snippet of my ffmpeg tool class, this part collecting information about a video.
I put FFmpeg in a particular location, and at the start of the software running it makes sure that it is there. For this version I have moved it to the Desktop, I am fairly sure I have written the path correctly for you (I really hate MS's special folders system, so I ignore it as much as I can).
Anyway, it is an example of using windowless ffmpeg.
public string GetVideoInfo(FileInfo fi)
{
outputBuilder.Clear();
string strCommand = string.Concat(" -i \"", fi.FullName, "\"");
string ffPath =
System.Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\ffmpeg.exe";
string oStr = "";
try
{
Process build = new Process();
//build.StartInfo.WorkingDirectory = #"dir";
build.StartInfo.Arguments = strCommand;
build.StartInfo.FileName = ffPath;
build.StartInfo.UseShellExecute = false;
build.StartInfo.RedirectStandardOutput = true;
build.StartInfo.RedirectStandardError = true;
build.StartInfo.CreateNoWindow = true;
build.ErrorDataReceived += build_ErrorDataReceived;
build.OutputDataReceived += build_ErrorDataReceived;
build.EnableRaisingEvents = true;
build.Start();
build.BeginOutputReadLine();
build.BeginErrorReadLine();
build.WaitForExit();
string findThis = "start";
int offset = 0;
foreach (string str in outputBuilder)
{
if (str.Contains("Duration"))
{
offset = str.IndexOf(findThis);
oStr = str.Substring(0, offset);
}
}
}
catch
{
oStr = "Error collecting file information";
}
return oStr;
}
private void build_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
string strMessage = e.Data;
if (outputBuilder != null && strMessage != null)
{
outputBuilder.Add(string.Concat(strMessage, "\n"));
}
}
Try using the OpenCV library. It definitely has the capabilities you require.
This guide has a section about accessing frames from a video file.
If it's for AVI files I'd read the data from the AVI file myself and extract the frames. Now use the video compression manager to decompress it.
The AVI file format is very simple, see: http://msdn.microsoft.com/en-us/library/dd318187(VS.85).aspx (and use google).
Once you have the file open you just extract each frame and pass it to ICDecompress() to decompress it.
It seems like a lot of work but it's the most reliable way.
If that's too much work, or if you want more than AVI files then use ffmpeg.
OpenCV is the best solution if video in your case only needs to lead to a sequence of pictures. If you're willing to do real video processing, so ViDeo equals "Visual Audio", you need to keep up track with the ones offered by "martjno". New windows solutions also for Win7 include 3 new possibilities additionally:
Windows Media Foundation: Successor of DirectShow; cleaned-up interface
Windows Media Encoder 9: It does not only include the programm, it also ships libraries for coding
Windows Expression 4: Successor of 2.
Last 2 are commercial-only solutions, but the first one is free. To code WMF, you need to install the Windows SDK.
I would recommend FFMPEG or GStreamer. Try and stay away from openCV unless you plan to utilize some other functionality than just streaming video. The library is a beefy build and a pain to install from source to configure FFMPEG/+GStreamer options.