Thanks to Rob and Tony for the answers to the channel question.
I'm trying to implement a class within my C++ app that presents a stream interface to the MAD decoder, i.e. it does buffering and provides a Tick() method that returns the next decoded sample in the stream as a floating point number. My first attempt uses the high-level API but I've stumbled on a problem I can't seem to get around.
The logic I'm using in Tick is something like the following:
1. Check PCM buffer. 2. If data present, just return next sample. 3. If buffer empty, go away and decode some more to fill buffer. 4. When buffer is full, stop decoding and return first sample in buffer.
I need to stop and start decoding the same stream at regular intervals depending on the PCM buffer size. So at stage 3 above, I call mad_decoder_run on the properly initialised decoder, and in the output callback, I return MAD_FLOW_STOP when I've been given enough frames to fill the buffer.
Up until now everything's fine. But, it seems that the next time the buffer gets empty and I restart by calling mad_decoder_run again on the same decoder, the decoder doesn't remember the input last given to it by the input callback. So the first thing it does is call the input callback for more input. The mad_stream->next_frame passed into the input callback is always 0 after a restart.
This causes problems because the input callback has no way of knowing how far into the previous chunk MAD has decoded. Is there any way to find this out from the decoder itself?
I haven't looked at the low-level API yet, will I maybe need to use that to achieve what I want?
Hope the above makes sense, I've only just started using MAD so might have overlooked something blindingly obvious.
Many thanks, Erik
On Mar 26, 2004, at 4:54 AM, Erik Jälevik wrote:
I need to stop and start decoding the same stream at regular intervals depending on the PCM buffer size. So at stage 3 above, I call mad_decoder_run on the properly initialised decoder, and in the output callback, I return MAD_FLOW_STOP when I've been given enough frames to fill the buffer.
Up until now everything's fine. But, it seems that the next time the buffer gets empty and I restart by calling mad_decoder_run again on the same decoder, the decoder doesn't remember the input last given to it by the input callback. So the first thing it does is call the input callback for more input. The mad_stream->next_frame passed into the input callback is always 0 after a restart.
This causes problems because the input callback has no way of knowing how far into the previous chunk MAD has decoded. Is there any way to find this out from the decoder itself?
Only if you record the position yourself, perhaps in the filter callback. But you will encounter a more serious problem, which is that all the other decoder state (synthesis filterbank, Layer III overlap, etc.) is destroyed when mad_decoder_run() returns.
I haven't looked at the low-level API yet, will I maybe need to use that to achieve what I want?
I think you will indeed. It's not terribly difficult; for some guidance, have a look at Bertrand Petit's madlld:
http://www.bsd-dk.dk/%7Eelrond/audio/madlld/
Cheers,
On Fri, Mar 26, 2004 at 05:03:00PM -0800, Rob Leslie wrote:
I think you will indeed. It's not terribly difficult; for some guidance, have a look at Bertrand Petit's madlld:
http://www.bsd-dk.dk/%7Eelrond/audio/madlld/
By the way, there is a new release available there since March 19th. The most notable change is the explanation of the use of the MAD_BUFFER_GUARD constant, which is paramount if one does want do decode the last frame of a bit-stream.
Is there any support for VBR headers in MAD?
I'm trying to calculate the length of files and for CBR fileSize/(header.bitrate/8) works fine. For VBR, this obviously gives an incorrect answer.
If reading VBR headers is fiddly, I was also thinking of checking the bitrate in say 10 or so frames at the start, take their average bit rate and use that in the calculation above. Would that be even remotely accurate for VBR?
Thanks, Erik
Is there any support for VBR headers in MAD?
There's no support for reading Xing/LAME VBR header tags in libmad, but the code to do it can be found in madplay (see tag.c).
I'm trying to calculate the length of files and for CBR fileSize/(header.bitrate/8) works fine. For VBR, this obviously gives an incorrect answer.
If reading VBR headers is fiddly, I was also thinking of checking the bitrate in say 10 or so frames at the start, take their average bit rate and use that in the calculation above. Would that be even remotely accurate for VBR?
Probably not, considering the first 10 frames are likely to be pretty quiet compared to the rest of the stream. (10 frames is about 1/4 second of audio in Layer III at 44100 Hz.)
The only other option guaranteed to obtain correct results is to scan the entire file, decoding headers only, to calculate the total playing time.
On Tue, Mar 30, 2004 at 11:50:26AM -0800, Rob Leslie wrote:
Is there any support for VBR headers in MAD?
There's no support for reading Xing/LAME VBR header tags in libmad, but the code to do it can be found in madplay (see tag.c).
Note that this code doesn't parse "Info" tags, which are just Xing tags but are usually written for CBR files (probably to not confuse players which assume existance a Xing tag means VBR). The information is less useful for CBR, but parsing it can avoid an extra frame of silence at the beginning of files, etc.
Probably not, considering the first 10 frames are likely to be pretty quiet compared to the rest of the stream. (10 frames is about 1/4 second of audio in Layer III at 44100 Hz.)
I did a similar thing at one point: seek to the middle of the stream and decode a few headers, which is more likely to give a sane result. In addition to estimating file length, I used the result to optimize fast seek-to-timestamps.
However, this slowed down file opening (extra seek + read + seek), the results were still inaccurate, it's an edge case (most VBR MP3s have Xing tags), and using that table to seek is more accurate (low-resolution, but more reliable), so I removed it.
On Mar 30, 2004, at 2:17 PM, Glenn Maynard wrote:
There's no support for reading Xing/LAME VBR header tags in libmad, but the code to do it can be found in madplay (see tag.c).
Note that this code doesn't parse "Info" tags, which are just Xing tags but are usually written for CBR files (probably to not confuse players which assume existance a Xing tag means VBR).
Actually since version 0.15.1b, it does -- at your suggestion, in fact. It also reads any LAME tag following the Xing info, which contains Replay Gain information.
Cheers,
----- Original Message ----- From: "Erik Jälevik" erik.jalevik@ntlworld.com
If reading VBR headers is fiddly, I was also thinking of checking the bitrate
in
say 10 or so frames at the start, take their average bit rate and use that in the calculation above. Would that be even remotely accurate for VBR?
I should have held off posting until I'd tried. I tried both 10 and 20 and it turned out to be wildly inaccurate.
Erik