On Friday, May 24, 2002, at 08:01 PM, Russell O'Connor wrote:
I'm trying to implement better seeking in my application.
First, easy question: I believe after calling mad_decode_header, the amount of (decoded) data in the next frame is:
64*MAD_NSBSAMPLES(&(sync.frame.header))*MAD_NCHANNELS(&(sync.frame.header) )
I'm not sure what units you're using, so to clarify: the number of samples per channel in a frame is generally
32 * MAD_NSBSAMPLES(&frame.header)
however after synthesis it is best to use the value in synth.pcm.length instead. (The above expression is wrong if MAD_OPTION_HALFSAMPLERATE is in effect.)
Sometimes it's better to think in terms of playing time duration. After decoding the frame header, the playing time of the frame is stored in frame.header.duration. Another way to calculate the number of samples per channel would be:
mad_timer_count(frame.header.duration, frame.header.samplerate)
The number of channels of course is MAD_NCHANNELS(&frame.header) or, after synthesis, synth.pcm.channels. After synthesis you should also use synth.pcm.samplerate rather than frame.header.samplerate.
Next question:
after calling mad_decode_header, am I allowed to call mad_decode_frame to actually decode the frame? The idea being to seek to where I want be by calling decode_header a bunch of time till I get to where I want to be.
Yes, it is explicitly permitted to call mad_frame_decode() after mad_header_decode() to continue decoding the same frame.
There are actually three ways to use these routines:
1. Quickly scan frame headers only:
do { mad_header_decode(&header, &stream); } while (...);
2. Decode full frames:
do { mad_frame_decode(&frame, &stream); } while (...);
3. Decode full frames, but with opportunity to inspect each frame header prior to decoding the rest of the frame:
do { mad_header_decode(&frame.header, &stream); /* inspect header, decide whether to continue decoding the frame */ mad_frame_decode(&frame, &stream); } while (...);
The high-level API uses method 3 if you specify a header callback, otherwise it uses method 2. You can effect method 1 with the high-level API by returning MAD_FLOW_IGNORE from your header callback routine.
I think decode_frame returns -1 after I call decode_header. I'm not sure if this the the behaviour to expect, or if I'm doing something wrong.
Probably this is due to a real decoding error. If you're seeking around a Layer III stream, the bit reservoir may not have had an opportunity to be refilled, and it's normal to get errors on a few frames in this case.
Note that calling mad_header_decode() alone does not update the bit reservoir, so you will probably want to stop scanning headers and fully decode a few frames before your seek point. This will also update the Layer III overlap-add buffers for a smoother audio entry to the seek point. You will also want to call mad_synth_frame() on the frame immediately before your seek point and discard the resulting PCM in order to update the synthesis buffers, again for a smoother audio entry.
-- Rob Leslie rob@mars.org