Hi folks,
I've just started writing an audio processing utility, using libmad to read from MP3 files.
I've modelled my code on minimad.c and it works fine, but as I'm decoding each file all at once, I want to provide a progress meter. In minimad.c the whole file is mmapped, so the read function only gets called once. I figured I would change my read function to make available a small fraction of the data, update the progress bar, then make the next block available, etc.
Unfortunately this doesn't work, I get "lost synchronisation" , "reserved sample frequency value", "bad main_data_begin pointer", "forbidden bitrate value" and "Huffman data overrun" errors each time I return a new block of data. As far as I can tell, my code is doing the right thing (I've included it below). In madllc.c, there is provision for when a frame is not wholly included by a buffer, but I would expect in the case of the high-level functions that this would be detected by mad_decoder_run and the input function would be polled for more data automatically.
Am I missing something obvious? Also, is there a better way to implement a progress bar?
Thanks in advance, Hamish
P.S. this code is in Objective-C: "[inputData length]" does what the C++ "inputdata.length()" would do, and "id" is like "NSObject *" (NSObject is the root object).
struct dataDescriptor { NSData *inputData; NSMutableData *outputData; unsigned int bytesRead; unsigned int byteChunk; // number of bytes to read at a time id progressObject; };
static enum mad_flow madInput(void *data, struct mad_stream *stream) { struct dataDescriptor *descriptor = data; NSData *inputData = descriptor->inputData; unsigned int bytesTotal = [inputData length]; unsigned int bytesLeft = bytesTotal - descriptor->bytesRead; double progress = (double)(descriptor->bytesRead) / (double)bytesTotal;
[descriptor->progressObject showProgress:progress]
if (bytesLeft == 0) return MAD_FLOW_STOP;
fprintf(stderr, "Bytes read=%d, left=%d\n", descriptor->bytesRead, bytesLeft);
if (bytesLeft > descriptor->byteChunk) bytesLeft = descriptor->byteChunk; mad_stream_buffer(stream, [inputData bytes] + (descriptor->bytesRead), bytesLeft); descriptor->bytesRead += bytesLeft;
return MAD_FLOW_CONTINUE; }
On Apr 30, 2004, at 5:20 AM, Hamish Allan wrote:
I've modelled my code on minimad.c and it works fine, but as I'm decoding each file all at once, I want to provide a progress meter. In minimad.c the whole file is mmapped, so the read function only gets called once. I figured I would change my read function to make available a small fraction of the data, update the progress bar, then make the next block available, etc.
Unfortunately this doesn't work, I get "lost synchronisation" , "reserved sample frequency value", "bad main_data_begin pointer", "forbidden bitrate value" and "Huffman data overrun" errors each time I return a new block of data. As far as I can tell, my code is doing the right thing (I've included it below). In madllc.c, there is provision for when a frame is not wholly included by a buffer, but I would expect in the case of the high-level functions that this would be detected by mad_decoder_run and the input function would be polled for more data automatically.
Am I missing something obvious? Also, is there a better way to implement a progress bar?
Each time the input callback is called, some unconsumed portion of the bitstream (a partial frame, beginning at stream->next_frame) may remain in the stream buffer. It's important not to discard this unconsumed data, but instead arrange for it to be found at the beginning of the next stream buffer passed to mad_stream_buffer(). This is true for both the low- and high-level APIs.
FWIW, it might be simpler to attach the progress indication to the output or filter callbacks. In the case of the filter callback, you have access to the stream structure so you can see exactly which bytes the decoder is working on, namely the bytes between stream->this_frame and stream->next_frame.