[mad-dev] frame decoding questions
Rob Leslie
rob@mars.org
Fri, 24 May 2002 21:56:22 -0700
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