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!
Related
I am trying to use libav to convert an MP4 file to an MP3 file. Basically trying to achieve what ffmpeg -i filename.mp4 filename.mp3 does. I've found this official example. But when I run it with an input MP4 and an output MP3 I get an error:
Invalid audio stream. Exactly one MP3 audio stream is required.
I am not at all familiar with this library but I think I have narrowed the problem down to this line:
ret = avcodec_parameters_copy(out_stream->codecpar, in_codecpar);
It seems to copy all streams for a video file but we only need one for the MP3 file? I am not sure. There doesn't seem to be a function to copy only the parameters relevant to audio. I checked the sources, avcodec_parameters_copy does a simple memcpy.
Questions:
Is this the actual problem?
How do I solve it?
Am I on the right track to achieve the goal of extracting audio from a video file? I've seen this question (and other similar questions like this and this) on here but none seem to have a complete code example. The C API documentation for this library is also a little lacking.
You can have multiple audio tracks in mp4 file, but only one such track in an mp3 file. The easiest fix for the remuxing example would be to replace lines 101-103:
if (in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
stream_index != 0) {
This, naturally, is relevant only if the output is mp3.
PS, make sure that your input mp4 uses the MP3 audio codec. If it does not (and most have AAC or AC3 these days), it's not enough to remux the file, you also need to decode and re-encode the audio stream.
I am trying to develop an application using the JUCE library that can record an audio or open an audio file. The audio file is to be passed into the openSMILE program to have its feature values extracted. All audio files are in wave format and the application is to be finally built for the iPhone platform.
I have developed the part of the application that allows the application to record audio and open an audio file from the file directory. I am able to pass some audio files into openSMILE to have their feature values extracted, but not others. All those recorded from the JUCE application itself all cannot be passed in.
The error produced when passing those audio files that cannot be passed is as follows:
smilePcm: Riff: 46464952
Format: 45564157
Subchunk1ID: 4b4e554a
Subchunk2ID: 0
AudioFormat: 0
Subchunk1Size: 34smilePcm: bogus wave/riff header or file in wrong format ('Audio/Audio Recording.wav')! (maybe you are trying to read a 32-bit wave file which is not yet supported (new header type...)?)(ERROR) [1] in cWaveSource: failed reading wave header from file 'Audio/Audio Recording.wav'! Maybe this is not a WAVE file?
To try to find the cause of the error, I then extracted information about the wave headers of the passable and non-passable audio files using Riffpad.
In the audio files that could be passed into the openSMILE program, the wave file header information are as follows:
Audio 1
RIFF-WAVE - (len= 180260, off= 12)
fmt - (len=16, off=20)
data - (len=180224, off=44)
Audio 2
RIFF-WAVE - (len= 19236, off= 12)
fmt - (len=16, off=20)
data - (len=19200, off=44)
And the non-passable ones are as follows:
Audio 3 <---Recorded from my JUCE application
RIFF-WAVE - (len= 128096, off= 12)
JUNK - (len=52, off=20)
fmt - (len=16, off=80)
data - (len=128000, off=104)
Audio 4 <---A random audio file that also can't be passed into openSMILE
RIFF-WAVE - (len= 21289308, off= 12)
fmt - (len=40, off=20)
fact - (len = 4, off=68)
data - (len=21289248, off=80)
I am guessing (correct me if I am wrong) that the error would be removed if I can remove the JUNK subchunk from the wave file recorded, i.e. Audio 3, so that the headers will be similar to that in the passable audio files.
I thought of 2 possibilities that might be able to resolve this issue:
Record Juce Audio with a header format similar to the passable audio file headers (most straightforward and preferred method, if workable)
Convert the Audio file after recording, so that the headers will be similar (I have read that using libsndfile and Audio Compression Manager (ACM) might work, but I am not sure if they are workable for cross platform that JUCE can build to, e.g. iPhone)
For the first way, is there any way I can record Audio in the 'right' format as with the passable audio files?
For the second way, could I use a library that can be built for cross platform, or somehow take out the data chunk of the recorded audio, and add a header with the 'right' format to it? (What i gathered from what I read is that, the JUNK allows for information to be included, and if it is not required, can be skipped. I presume that removing it would not be a problem, as long as i edit the total length from the RIFF-WAVE subchunk.)
Are any of the methods above possible, and if so, how should I carry them out?
Thanks!
Solved: Apparently there was a comment in wavAudioFormat.cpp on enabling JUCE_WAV_DO_NOT_PAD_HEADER_SIZE to remove JUNK padding.
Leaving the steps here for anybody who want to record audio in wavAudioFormat but have "crappy wav players" that cannot read the padded recorded audio:
go to Debug > Project Properties > Configuration Properties > C/C++ > Preprocessor > Preprocessor Definition.
Click Edit
Add in JUCE_WAV_DO_NOT_PAD_HEADER_SIZE to the list.
Thanks for taking some time to read my question.
I'm developping a C++ application using Qt and windows API.
I'm recording the microphone output in small 10s audio files in raw format, and I want to convert them to aac format.
I have tried to read as many things as I could, and thought it would be a great idea to start from windows media foundation transcode API.
Problem is, I can't seem to use a .raw or .pcm file in the "CreateObjectFromUrl" function, and so I'm pretty much stuck here for the moment. It keeps on failing. The hr return code equals 3222091460. I have tried to pass an .mp3 file to the function and of course it works, so no url-human-failure involved.
MF_OBJECT_TYPE ObjectType = MF_OBJECT_INVALID;
IMFSourceResolver* pSourceResolver = NULL;
IUnknown* pUnkSource = NULL;
// Create the source resolver.
hr = MFCreateSourceResolver(&pSourceResolver);
if (FAILED(hr))
{
qDebug() << "Failed !";
}
// Use the source resolver to create the media source.
hr = pSourceResolver->CreateObjectFromURL(
sURL, // URL of the source.
MF_RESOLUTION_MEDIASOURCE, // Create a source object.
NULL, // Optional property store.
&ObjectType, // Receives the created object type.
&pUnkSource // Receives a pointer to the media source.
);
The MFCreateSourceResolver works fine, but CreateObjectFromURL does not succeed :(
So I have two questions for you folks :
Is it possible to encode raw audio files to aac files using windows media foundation ?
If yes, what should I read to accomplish what I want ?
I want to point out that I can't just use ffmpeg or libav because I can't afford any license for my software, and don't want it to be under the GPL license. But if there are alternatives to windows media foundations to encode raw audio files to aac, I would be glad to hear them.
And finally, sorry for my bad english, this is obviously not my native language and I'm sorry if I made your eyes bleed. (and happy if I made you laugh)
Have a nice day
The hr return code equals 3222091460
Those are HRESULT codes. Use this "ShowHresult" tool to have them conveniently decoded for you. The code means 0xC00D36C4 MF_E_UNSUPPORTED_BYTESTREAM_TYPE "The byte stream type of the given URL is unsupported."
The problem is basically that there is no support for these raw files, .WAV is a good source for raw audio - the file holds both format descriptor and the payload.
You can obviously read data from the raw audio file yourself and compress into AAC using Media Foundation's AAC Encoder via its IMFTransform interface. This is reasonably easy and you have AAC data on the output to e.g. write into raw .AAC.
Alternate options to Media Foundation is DirectShow (there are suitable codecs, though I thought it might be not so easy to start), libfaac, FFmpeg's libavcodec (available under LGPL, not GPL).
I'm trying to write a very simple video player using QT and Phonon, on Windows. My backend is phonon_ds94. First of all, here is the code when I click on "Play" :
if (!this->_files.empty()) {
QString file = this->_files.front();
this->_files.pop();
Phonon::MediaSource _src(file);
this->ui.videoPlayer->play(_src);
}
(Here, file is a std::queue of files to read)
If I want to play a .avi ou .wmv, everything works fine. My video play, it's perfect.
But when I want to play a .mp4 file, nothing happen. The videoPlayer stay black.
I've search on the web and see that there is a BackendCapabilities::availableMimeTypes, so I've try it to be sure that my backend is compatible with mp4 - it's in the list. Here is the list of available mime types:
application/vnd.ms-wpl application/x-mplayer2 application/x-ms-wmd
application/x-ms-wmz audio/3gpp audio/3gpp2 audio/aiff audio/basic
audio/mid audio/midi audio/mp3 audio/mp4 audio/mpeg audio/mpegurl
audio/mpg audio/vnd.dlna.adts audio/wav audio/x-aiff audio/x-mid
audio/x-midi audio/x-mp3 audio/x-mpeg audio/x-mpegurl audio/x-mpg
audio/x-ms-wax audio/x-ms-wma audio/x-wav midi/mid unknown video/3gpp
video/3gpp2 video/avi video/mp4 video/mpeg video/mpg video/msvideo
video/quicktime video/vnd.dlna.mpeg-tts video/x-mpeg video/x-mpeg2a
video/x-ms-asf video/x-ms-asf-plugin video/x-ms-wm video/x-ms-wmv
video/x-ms-wmx video/x-ms-wvx video/x-msvideo vnd.ms.wmhtml
I've also connected the stateChanged signal of the mediaObject to a slot, and when I try to read my video, there is an error saying that file format is not supported.
How can I have Phonon to support it? Should I install a codec pack, even if mp4 is in my list?
I recently had a similar problem and after trying a number of codec packs, here is the one that worked.
K Lite Mega Codec Pack
If you go into the advanced install, you can uncheck the "Tools", "Program" (Windows Media Player Classic), "Shell Extension", and later uncheck the free browser toolbars that come with it, you end up with just the codecs.
Afterwards I have been able to play anything on Windows using the qmediaplayer example program included in the Demos folder of the QtSDK.
Is it possible to change the frame rate of an avi file using the Video for windows library? I tried the following steps but did not succeed.
AviFileInit
AviFileOpen(OF_READWRITE)
pavi1 = AviFileGetStream
avi_info = AviStreamInfo
avi_info.dwrate = 15
EditStreamSetInfo(dwrate) returns -2147467262.
I'm pretty sure the AVIFile* APIs don't support this. (Disclaimer: I was the one who defined those APIs, but it was over 15 years ago...)
You can't just call EditStreamSetInfo on an plain AVIStream, only one returned from CreateEditableStream.
You could use AVISave, then, but that would obviously re-copy the whole file.
So, yes, you would probably want to do this by parsing the AVI file header enough to find the one DWORD you want to change. There are lots of documents on the RIFF and AVI file formats out there, such as http://www.opennet.ru/docs/formats/avi.txt.
I don't know anything about VfW, but you could always try hex-editing the file. The framerate is probably a field somewhere in the header of the AVI file.
Otherwise, you can script some tool like mencoder[1] to copy the stream to a new file under a different framerate.
[1] http://www.mplayerhq.hu/
HRESULT: 0x80004002 (2147500034)
Name: E_NOINTERFACE
Description: The requested COM interface is not available
Severity code: Failed
Facility Code: FACILITY_NULL (0)
Error Code: 0x4002 (16386)
Does it work if you DON'T call EditStreamSetInfo?
Can you post up the code you use to set the stream info?