int output_synth_data(mpgedit_madbuf_t *ctx) { int i; int rsts; for(i=0;i<ctx->Synth.pcm.length;i++) { signed short Sample; /* Left channel */ Sample=MadFixedToSshort(ctx->Synth.pcm.samples[0][i]); *(ctx->OutputPtr++) = Sample & 0xff; *(ctx->OutputPtr++) = Sample >> 8; /* Right channel. If the decoded stream is monophonic then * the right output channel is the same as the left one. */ if(MAD_NCHANNELS(&ctx->Frame.header)==2) { Sample=MadFixedToSshort(ctx->Synth.pcm.samples[1][i]); *(ctx->OutputPtr++) = Sample & 0xff; *(ctx->OutputPtr++) = Sample >> 8; } /* Flush the output buffer if it is full. */ if (ctx->OutputPtr >= ctx->OutputBufferEnd) { rsts = fwrite(ctx->OutputBuffer, 1, OUTPUT_BUFFER_SIZE, ctx->outfp); if (rsts != OUTPUT_BUFFER_SIZE) { fprintf(stderr,"%s: PCM write error (%s).\n", "main" ,strerror(errno)); return 1; } ctx->OutputPtr = ctx->OutputBuffer; } }
void mp3_mad_decode (mp3_info_t *info) { // copy synthesized samples into readbuffer int idx = info->mad_synth.pcm.length-info->buffer.decode_remaining; // stereo if (MAD_NCHANNELS(&info->mad_frame.header) == 2 && info->info.fmt.channels == 2) { while (info->buffer.decode_remaining > 0 && info->buffer.readsize > 0) { *((int16_t*)info->buffer.out) = MadFixedToSshort (info->mad_synth.pcm.samples[0][idx]); info->buffer.readsize -= 2; info->buffer.out += 2; *((int16_t*)info->buffer.out) = MadFixedToSshort (info->mad_synth.pcm.samples[1][idx]); info->buffer.readsize -= 2; info->buffer.out += 2; info->buffer.decode_remaining--; idx++; } } // mono else if (MAD_NCHANNELS(&info->mad_frame.header) == 1 && info->info.fmt.channels == 1){ while (info->buffer.decode_remaining > 0 && info->buffer.readsize > 0) { *((int16_t*)info->buffer.out) = MadFixedToSshort (info->mad_synth.pcm.samples[0][idx]); info->buffer.readsize -= 2; info->buffer.out += 2; info->buffer.decode_remaining--; idx++; } } // workaround for bad mp3s that have both mono and stereo frames else if (MAD_NCHANNELS(&info->mad_frame.header) == 1 && info->info.fmt.channels == 2) { while (info->buffer.decode_remaining > 0 && info->buffer.readsize > 0) { int16_t sample = MadFixedToSshort (info->mad_synth.pcm.samples[0][idx]); *((int16_t*)info->buffer.out) = sample; info->buffer.readsize -= 2; info->buffer.out += 2; *((int16_t*)info->buffer.out) = sample; info->buffer.readsize -= 2; info->buffer.out += 2; info->buffer.decode_remaining--; idx++; } } else if (MAD_NCHANNELS(&info->mad_frame.header) == 2 && info->info.fmt.channels == 1) { while (info->buffer.decode_remaining > 0 && info->buffer.readsize > 0) { int16_t sample = MadFixedToSshort (info->mad_synth.pcm.samples[0][idx]); *((int16_t*)info->buffer.out) = sample; info->buffer.readsize -= 2; info->buffer.out += 2; info->buffer.decode_remaining--; idx++; } } }
int32 MADDecoder::Decode(uint8* buffer, int32 max_length) { int32 bytes_decoded = 0; if (stereo) max_length = max_length - 3; else max_length = max_length - 1; while (bytes_decoded < max_length) { if (sample < Synth.pcm.length) { int16 sample_data; sample_data = MadFixedToSshort(Synth.pcm.samples[0][sample]); #ifdef ALEPHONE_LITTLE_ENDIAN buffer[bytes_decoded++] = sample_data & 0xff; buffer[bytes_decoded++] = sample_data >> 8; #else buffer[bytes_decoded++] = sample_data >> 8; buffer[bytes_decoded++] = sample_data & 0xff; #endif if (stereo) { sample_data = MadFixedToSshort(Synth.pcm.samples[1][sample]); #ifdef ALEPHONE_LITTLE_ENDIAN buffer[bytes_decoded++] = sample_data & 0xff; buffer[bytes_decoded++] = sample_data >> 8; #else buffer[bytes_decoded++] = sample_data >> 8; buffer[bytes_decoded++] = sample_data & 0xff; #endif } sample++; } else if (!DecodeFrame())
/** * MP3音乐播放回调函数, * 负责将解码数据填充声音缓存区 * * @note 声音缓存区的格式为双声道,16位低字序 * * @param buf 声音缓冲区指针 * @param reqn 缓冲区帧大小 * @param pdata 用户数据,无用 */ static int mp3_audiocallback(void *buf, unsigned int reqn, void *pdata) { int avail_frame; int snd_buf_frame_size = (int) reqn; int ret; double incr; signed short *audio_buf = buf; unsigned i; uint16_t *output; UNUSED(pdata); if (g_status != ST_PLAYING) { if (handle_seek() == -1) { __end(); return -1; } xAudioClearSndBuf(buf, snd_buf_frame_size); xrKernelDelayThread(100000); return 0; } while (snd_buf_frame_size > 0) { avail_frame = g_buff_frame_size - g_buff_frame_start; if (avail_frame >= snd_buf_frame_size) { send_to_sndbuf(audio_buf, &g_buff[g_buff_frame_start * 2], snd_buf_frame_size, 2); g_buff_frame_start += snd_buf_frame_size; audio_buf += snd_buf_frame_size * 2; snd_buf_frame_size = 0; } else { send_to_sndbuf(audio_buf, &g_buff[g_buff_frame_start * 2], avail_frame, 2); snd_buf_frame_size -= avail_frame; audio_buf += avail_frame * 2; if (stream.buffer == NULL || stream.error == MAD_ERROR_BUFLEN) { size_t read_size, remaining = 0; uint8_t *read_start; int bufsize; if (stream.next_frame != NULL) { remaining = stream.bufend - stream.next_frame; memmove(g_input_buff, stream.next_frame, remaining); read_start = g_input_buff + remaining; read_size = BUFF_SIZE - remaining; } else { read_size = BUFF_SIZE; read_start = g_input_buff; remaining = 0; } if (mp3_data.use_buffer) bufsize = buffered_reader_read(mp3_data.r, read_start, read_size); else bufsize = xrIoRead(mp3_data.fd, read_start, read_size); if (bufsize <= 0) { __end(); return -1; } if (bufsize < read_size) { uint8_t *guard = read_start + read_size; memset(guard, 0, MAD_BUFFER_GUARD); read_size += MAD_BUFFER_GUARD; } mad_stream_buffer(&stream, g_input_buff, read_size + remaining); stream.error = 0; } ret = mad_frame_decode(&frame, &stream); if (ret == -1) { if (MAD_RECOVERABLE(stream.error) || stream.error == MAD_ERROR_BUFLEN) { if (stream.error == MAD_ERROR_LOSTSYNC) { long tagsize = id3_tag_query(stream.this_frame, stream.bufend - stream.this_frame); if (tagsize > 0) { mad_stream_skip(&stream, tagsize); } if (mad_header_decode(&frame.header, &stream) == -1) { if (stream.error != MAD_ERROR_BUFLEN) { if (!MAD_RECOVERABLE(stream.error)) { __end(); return -1; } } } else { stream.error = MAD_ERROR_NONE; } } g_buff_frame_size = 0; g_buff_frame_start = 0; continue; } else { __end(); return -1; } } output = &g_buff[0]; if (stream.error != MAD_ERROR_NONE) { continue; } mad_synth_frame(&synth, &frame); for (i = 0; i < synth.pcm.length; i++) { signed short sample; if (MAD_NCHANNELS(&frame.header) == 2) { /* Left channel */ sample = MadFixedToSshort(synth.pcm.samples[0][i]); *(output++) = sample; sample = MadFixedToSshort(synth.pcm.samples[1][i]); *(output++) = sample; } else { sample = MadFixedToSshort(synth.pcm.samples[0][i]); *(output++) = sample; *(output++) = sample; } } g_buff_frame_size = synth.pcm.length; g_buff_frame_start = 0; incr = frame.header.duration.seconds; incr += mad_timer_fraction(frame.header.duration, MAD_UNITS_MILLISECONDS) / 1000.0; g_play_time += incr; add_bitrate(&g_inst_br, frame.header.bitrate, incr); } } return 0; }
bool madaudiofile::getNextAudioFrame() { #ifdef HAVE_MAD_H #ifdef MADAUDIO_PRINT_DEBUG printf("Now in getNextAudioFrame()\n"); #endif u_int8_t *OutputPtr = OutputBuffer; u_int8_t *GuardPtr = NULL; while(OutputPtr < OutputBufferEnd) { /* The input bucket must be filled if it becomes empty or if * it's the first execution of the loop. */ if(Stream->buffer==NULL || Stream->error==MAD_ERROR_BUFLEN || frame_count == 0) { size_t ReadSize,Remaining; unsigned char *ReadStart; /* {2} libmad may not consume all bytes of the input * buffer. If the last frame in the buffer is not wholly * contained by it, then that frame's start is pointed by * the next_frame member of the Stream structure. This * common situation occurs when mad_frame_decode() fails, * sets the stream error code to MAD_ERROR_BUFLEN, and * sets the next_frame pointer to a non NULL value. (See * also the comment marked {4} bellow.) * * When this occurs, the remaining unused bytes must be * put back at the beginning of the buffer and taken in * account before refilling the buffer. This means that * the input buffer must be large enough to hold a whole * frame at the highest observable bit-rate (currently 448 * kb/s). XXX=XXX Is 2016 bytes the size of the largest * frame? (448000*(1152/32000))/8 */ if(Stream->next_frame!=NULL) { Remaining=Stream->bufend-Stream->next_frame; memmove(InputBuffer,Stream->next_frame,Remaining); ReadStart=InputBuffer+Remaining; ReadSize=INPUT_BUFFER_SIZE-Remaining; } else ReadSize=INPUT_BUFFER_SIZE, ReadStart=InputBuffer, Remaining=0; /* Fill-in the buffer. If an error occurs print a message * and leave the decoding loop. If the end of stream is * reached we also leave the loop but the return status is * left untouched. */ ReadSize=readData(ReadStart,1,ReadSize,file); if(ReadSize<=0) { break; // probably end of file reached and nothing was read } /* {3} When decoding the last frame of a file, it must be * followed by MAD_BUFFER_GUARD zero bytes if one wants to * decode that last frame. When the end of file is * detected we append that quantity of bytes at the end of * the available data. Note that the buffer can't overflow * as the guard size was allocated but not used the the * buffer management code. (See also the comment marked * {1}.) * * In a message to the mad-dev mailing list on May 29th, * 2001, Rob Leslie explains the guard zone as follows: * * "The reason for MAD_BUFFER_GUARD has to do with the * way decoding is performed. In Layer III, Huffman * decoding may inadvertently read a few bytes beyond * the end of the buffer in the case of certain invalid * input. This is not detected until after the fact. To * prevent this from causing problems, and also to * ensure the next frame's main_data_begin pointer is * always accessible, MAD requires MAD_BUFFER_GUARD * (currently 8) bytes to be present in the buffer past * the end of the current frame in order to decode the * frame." */ if(reachedEOF) { GuardPtr=ReadStart+ReadSize; memset(GuardPtr,0,MAD_BUFFER_GUARD); ReadSize+=MAD_BUFFER_GUARD; } /* Pipe the new buffer content to libmad's stream decoder * facility. */ mad_stream_buffer(Stream,InputBuffer,ReadSize+Remaining); Stream->error=(mad_error)0; } /* Decode the next MPEG frame. The streams is read from the * buffer, its constituents are break down and stored the the * Frame structure, ready for examination/alteration or PCM * synthesis. Decoding options are carried in the Frame * structure from the Stream structure. * * Error handling: mad_frame_decode() returns a non zero value * when an error occurs. The error condition can be checked in * the error member of the Stream structure. A mad error is * recoverable or fatal, the error status is checked with the * MAD_RECOVERABLE macro. * * {4} When a fatal error is encountered all decoding * activities shall be stopped, except when a MAD_ERROR_BUFLEN * is signaled. This condition means that the * mad_frame_decode() function needs more input to complete * its work. One shall refill the buffer and repeat the * mad_frame_decode() call. Some bytes may be left unused at * the end of the buffer if those bytes forms an incomplete * frame. Before refilling, the remaining bytes must be moved * to the beginning of the buffer and used for input for the * next mad_frame_decode() invocation. (See the comments * marked {2} earlier for more details.) * * Recoverable errors are caused by malformed bit-streams, in * this case one can call again mad_frame_decode() in order to * skip the faulty part and re-sync to the next frame. */ if(mad_frame_decode(Frame,Stream)) { if(MAD_RECOVERABLE(Stream->error)) { /* Do not print a message if the error is a loss of * synchronization and this loss is due to the end of * stream guard bytes. (See the comments marked {3} * supra for more informations about guard bytes.) */ if(Stream->error!=MAD_ERROR_LOSTSYNC || Stream->this_frame!=GuardPtr) { } continue; } else if(Stream->error==MAD_ERROR_BUFLEN) continue; // end of buffer reached --> read more from the file else { fprintf(stderr, "madaudiofile: unrecoverable frame level error (%i).\n", Stream->error); break; } } if(frame_count == 0) { samplerate = Frame->header.samplerate; #ifdef MADAUDIO_PRINT_DEBUG printf("Initially setting samplerate to %i\n",samplerate); #endif } #ifdef MADAUDIO_PRINT_DEBUG if(Frame->header.samplerate != samplerate) printf("Obs: samplerate changed to %i!\n",Frame->header.samplerate); #endif /* Accounting. The computed frame duration is in the frame * header structure. It is expressed as a fixed point number * whole data type is mad_timer_t. It is different from the * samples fixed point format and unlike it, it can't directly * be added or subtracted. The timer module provides several * functions to operate on such numbers. Be careful there, as * some functions of libmad's timer module receive some of * their mad_timer_t arguments by value! */ frame_count++; mad_timer_add(Timer,Frame->header.duration); /* Once decoded the frame is synthesized to PCM samples. No errors * are reported by mad_synth_frame(); */ mad_synth_frame(Synth,Frame); /* Synthesized samples must be converted from libmad's fixed * point number to the consumer format. Here we use unsigned * 16 bit big endian integers on two channels. Integer samples * are temporarily stored in a buffer that is flushed when * full. */ int unsigned sr = 0; for(int i=0;i<Synth->pcm.length;i++) { signed short Sample; u_int8_t left[2]; u_int8_t right[2]; /* Left channel */ Sample=MadFixedToSshort(Synth->pcm.samples[0][i]); left[0]=Sample>>8; left[1]=Sample&0xff; /* Right channel. If the decoded stream is monophonic then * the right output channel is the same as the left one. */ if(MAD_NCHANNELS(&Frame->header)==2) Sample=MadFixedToSshort(Synth->pcm.samples[1][i]); right[0]=Sample>>8; right[1]=Sample&0xff; while(sr < samplerate) { /* Left channel */ *(OutputPtr++)=left[1]; *(OutputPtr++)=left[0]; /* Right channel. If the decoded stream is monophonic then * the right output channel is the same as the left one. */ *(OutputPtr++)=right[1]; *(OutputPtr++)=right[0]; sr += Synth->pcm.samplerate; } sr -= samplerate; } if (OutputPtr>=OutputBufferEnd+OUTPUT_BUFFER_SAFETY) { char cstr[200]; sprintf(cstr,"getNextAudioFrame() writing outside of OutputBuffer:" " %p >= %p VERY BAD!!!\n", OutputPtr, OutputBufferEnd+OUTPUT_BUFFER_SAFETY); throw(string(cstr)); } } // while(OutputPtr < OutputBufferEnd) outputLength = OutputPtr-OutputBuffer; outputPosition = 0; if (outputLength == 0) reachedEOF = true; // If we have breaked out of the loop, but it wasn't because of EOF, // return false. if (OutputPtr < OutputBufferEnd && !reachedEOF) return false; return true; #else cerr << "libmad not available" << endl; return false; #endif // HAVE_MAD_H }
static int MP3Callback_22k(void *_buf2, unsigned int numSamples, void *pdata) { int i; short *_buf = (short *)_buf2; unsigned long samplesOut = 0; numSamples /= 2; // Playing , so mix up a buffer if (samplesInOutput > 0) { if (samplesInOutput > numSamples) { write22k_buf((short *) _buf, (short *) OutputBuffer, numSamples * 2); samplesOut = numSamples; samplesInOutput -= numSamples; } else { write22k_buf((short *) _buf, (short *) OutputBuffer, samplesInOutput * 2); samplesOut = samplesInOutput; samplesInOutput = 0; } } while (samplesOut < numSamples) { if (Stream.buffer == NULL) { Stream.error = 0; mad_stream_buffer(&Stream, mp3_data, size); } if (Stream.error == MAD_ERROR_BUFLEN) { Stream.error = 0; if (isRepeatMode) { MP3_Restart(); mad_stream_buffer(&Stream, mp3_data, size); samplesInOutput = 0; } else { MP3_Stop(); return 0; } } if (mad_frame_decode(&Frame, &Stream)) { if (MAD_RECOVERABLE(Stream.error)) { return 0; } else if (Stream.error == MAD_ERROR_BUFLEN) { if (! isRepeatMode) { MP3_Stop(); return 0; } } else { MP3_Stop(); } } FrameCount++; mad_timer_add(&Timer, Frame.header.duration); mad_synth_frame(&Synth, &Frame); for (i = 0; i < Synth.pcm.length; i++) { signed short Sample; if (samplesOut < numSamples) { /* Left channel */ Sample = MadFixedToSshort(Synth.pcm.samples[0][i]); _buf[((samplesOut * 2) * 2) ] = Sample; _buf[((samplesOut * 2) * 2) + 1] = Sample; /* Right channel. If the decoded stream is monophonic then * the right output channel is the same as the left one. */ if (MAD_NCHANNELS(&Frame.header) == 2) { Sample = MadFixedToSshort(Synth.pcm.samples[1][i]); } _buf[(((samplesOut * 2) + 1) * 2) ] = Sample; _buf[(((samplesOut * 2) + 1) * 2) + 1] = Sample; samplesOut++; } else { Sample = MadFixedToSshort(Synth.pcm.samples[0][i]); OutputBuffer[samplesInOutput * 2] = Sample; if (MAD_NCHANNELS(&Frame.header) == 2) { Sample = MadFixedToSshort(Synth.pcm.samples[1][i]); } OutputBuffer[samplesInOutput * 2 + 1] = Sample; samplesInOutput++; } } } return isPlaying; }
bool Mp3AudioFileReader::run(AudioProcessor& processor) { if (file_ == nullptr) { return false; } enum { STATUS_OK, STATUS_INIT_ERROR, STATUS_READ_ERROR, STATUS_PROCESS_ERROR } status = STATUS_OK; unsigned char input_buffer[INPUT_BUFFER_SIZE + MAD_BUFFER_GUARD]; unsigned char* guard_ptr = nullptr; unsigned long frame_count = 0; short output_buffer[OUTPUT_BUFFER_SIZE]; short* output_ptr = output_buffer; const short* const output_buffer_end = output_buffer + OUTPUT_BUFFER_SIZE; int channels = 0; // Decoding options can here be set in the options field of the stream // structure. // {1} When decoding from a file we need to know when the end of the file is // reached at the same time as the last bytes are read (see also the comment // marked {3} below). Neither the standard C fread() function nor the POSIX // read() system call provides this feature. We thus need to perform our // reads through an interface having this feature, this is implemented here // by the bstdfile.c module. BStdFile bstd_file(file_); // Initialize the structures used by libmad. MadStream stream; MadFrame frame; MadSynth synth; mad_timer_t timer; mad_timer_reset(&timer); // This is the decoding loop. for (;;) { // The input bucket must be filled if it becomes empty or if it's the // first execution of the loop. if (stream.buffer == nullptr || stream.error == MAD_ERROR_BUFLEN) { size_t read_size; size_t remaining; unsigned char* read_start; // {2} libmad may not consume all bytes of the input buffer. If the // last frame in the buffer is not wholly contained by it, then that // frame's start is pointed by the next_frame member of the stream // structure. This common situation occurs when mad_frame_decode() // fails, sets the stream error code to MAD_ERROR_BUFLEN, and sets // the next_frame pointer to a non-NULL value. (See also the comment // marked {4} below.) // // When this occurs, the remaining unused bytes must be put back at // the beginning of the buffer and taken in account before refilling // the buffer. This means that the input buffer must be large enough // to hold a whole frame at the highest observable bit-rate // (currently 448 kb/s). XXX=XXX Is 2016 bytes the size of the // largest frame? (448000*(1152/32000))/8 if (stream.next_frame != nullptr) { remaining = stream.bufend - stream.next_frame; memmove(input_buffer, stream.next_frame, remaining); read_start = input_buffer + remaining; read_size = INPUT_BUFFER_SIZE - remaining; } else { read_size = INPUT_BUFFER_SIZE; read_start = input_buffer; remaining = 0; } // Fill-in the buffer. If an error occurs print a message and leave // the decoding loop. If the end of stream is reached we also leave // the loop but the return status is left untouched. read_size = bstd_file.read(read_start, 1, read_size); if (read_size <= 0) { if (ferror(file_)) { error_stream << "\nRead error on bit-stream: " << strerror(errno) << '\n'; status = STATUS_READ_ERROR; } break; } // {3} When decoding the last frame of a file, it must be followed // by MAD_BUFFER_GUARD zero bytes if one wants to decode that last // frame. When the end of file is detected we append that quantity // of bytes at the end of the available data. Note that the buffer // can't overflow as the guard size was allocated but not used the // the buffer management code. (See also the comment marked {1}.) // // In a message to the mad-dev mailing list on May 29th, 2001, Rob // Leslie explains the guard zone as follows: // // "The reason for MAD_BUFFER_GUARD has to do with the way // decoding is performed. In Layer III, Huffman decoding may // inadvertently read a few bytes beyond the end of the buffer in // the case of certain invalid input. This is not detected until // after the fact. To prevent this from causing problems, and // also to ensure the next frame's main_data_begin pointer is // always accessible, MAD requires MAD_BUFFER_GUARD (currently 8) // bytes to be present in the buffer past the end of the current // frame in order to decode the frame." if (bstd_file.eof()) { guard_ptr = read_start + read_size; memset(guard_ptr, 0, MAD_BUFFER_GUARD); read_size += MAD_BUFFER_GUARD; } // Pipe the new buffer content to libmad's stream decoder facility. mad_stream_buffer(&stream, input_buffer, read_size + remaining); stream.error = MAD_ERROR_NONE; } // Decode the next MPEG frame. The streams is read from the buffer, its // constituents are break down and stored the the frame structure, ready // for examination/alteration or PCM synthesis. Decoding options are // carried in the frame structure from the stream structure. // // Error handling: mad_frame_decode() returns a non zero value when an // error occurs. The error condition can be checked in the error member // of the stream structure. A mad error is recoverable or fatal, the // error status is checked with the MAD_RECOVERABLE macro. // // {4} When a fatal error is encountered all decoding activities shall // be stopped, except when a MAD_ERROR_BUFLEN is signaled. This // condition means that the mad_frame_decode() function needs more input // to complete its work. One shall refill the buffer and repeat the // mad_frame_decode() call. Some bytes may be left unused at the end of // the buffer if those bytes forms an incomplete frame. Before // refilling, the remaining bytes must be moved to the beginning of the // buffer and used for input for the next mad_frame_decode() invocation. // (See the comments marked {2} earlier for more details.) // // Recoverable errors are caused by malformed bit-streams, in this case // one can call again mad_frame_decode() in order to skip the faulty // part and re-sync to the next frame. if (mad_frame_decode(&frame, &stream)) { if (MAD_RECOVERABLE(stream.error)) { // Do not print a message if the error is a loss of // synchronization and this loss is due to the end of stream // guard bytes. (See the comment marked {3} above for more // information about guard bytes.) if (stream.error != MAD_ERROR_LOSTSYNC || stream.this_frame != guard_ptr) { // For any MP3 file we typically see two errors in the // first frame processed: // - lost synchronization // - reserved header layer value // This seems to be OK, so don't print these if (frame_count != 0) { error_stream << "\nRecoverable frame level error: " << mad_stream_errorstr(&stream) << '\n'; } } continue; } else { if (stream.error == MAD_ERROR_BUFLEN) { continue; } else { error_stream << "\nUnrecoverable frame level error: " << mad_stream_errorstr(&stream) << '\n'; status = STATUS_READ_ERROR; break; } } } // Display the characteristics of the stream's first frame. The first // frame is representative of the entire stream. if (frame_count == 0) { const int sample_rate = frame.header.samplerate; channels = MAD_NCHANNELS(&frame.header); dumpInfo(output_stream, frame.header); if (!processor.init(sample_rate, channels, OUTPUT_BUFFER_SIZE)) { status = STATUS_PROCESS_ERROR; break; } showProgress(0, file_size_); } // Accounting. The computed frame duration is in the frame header // structure. It is expressed as a fixed point number whole data type is // mad_timer_t. It is different from the samples fixed point format and // unlike it, it can't directly be added or subtracted. The timer module // provides several functions to operate on such numbers. Be careful // there, as some functions of libmad's timer module receive some of // their mad_timer_t arguments by value! frame_count++; mad_timer_add(&timer, frame.header.duration); // Once decoded the frame is synthesized to PCM samples. No errors are // reported by mad_synth_frame(); mad_synth_frame(&synth, &frame); // Synthesized samples must be converted from libmad's fixed point // number to the consumer format. Here we use signed 16 bit integers on // two channels. Integer samples are temporarily stored in a buffer that // is flushed when full. for (int i = 0; i < synth.pcm.length; i++) { // Left channel short sample = MadFixedToSshort(synth.pcm.samples[0][i]); *output_ptr++ = sample; // Right channel. If the decoded stream is monophonic then the right // output channel is the same as the left one. if (MAD_NCHANNELS(&frame.header) == 2) { sample = MadFixedToSshort(synth.pcm.samples[1][i]); *output_ptr++ = sample; } // Flush the output buffer if it is full if (output_ptr == output_buffer_end) { long pos = ftell(file_); showProgress(pos, file_size_); bool success = processor.process( output_buffer, OUTPUT_BUFFER_SIZE / channels ); if (!success) { status = STATUS_PROCESS_ERROR; break; } output_ptr = output_buffer; } } } // If the output buffer is not empty and no error occurred during the last // write, then flush it. if (output_ptr != output_buffer && status != STATUS_PROCESS_ERROR) { int buffer_size = static_cast<int>(output_ptr - output_buffer); bool success = processor.process(output_buffer, buffer_size / channels); if (!success) { status = STATUS_PROCESS_ERROR; } } // Accounting report if no error occurred. if (status == STATUS_OK) { // Report 100% done. showProgress(file_size_, file_size_); char buffer[80]; // The duration timer is converted to a human readable string with the // versatile, but still constrained mad_timer_string() function, in a // fashion not unlike strftime(). The main difference is that the timer // is broken into several values according some of its arguments. The // units and fracunits arguments specify the intended conversion to be // executed. // // The conversion unit (MAD_UNIT_MINUTES in our example) also specify // the order and kind of conversion specifications that can be used in // the format string. // // It is best to examine libmad's timer.c source-code for details of the // available units, fraction of units, their meanings, the format // arguments, etc. mad_timer_string(timer, buffer, "%lu:%02lu.%03u", MAD_UNITS_MINUTES, MAD_UNITS_MILLISECONDS, 0); output_stream << "\nFrames decoded: " << frame_count << " (" << buffer << ")\n"; } processor.done(); close(); return status == STATUS_OK; }
/**************************************************************************** * Main decoding loop. This is where mad is used. * ****************************************************************************/ #define INPUT_BUFFER_SIZE (5*8192) #define OUTPUT_BUFFER_SIZE 8192 /* Must be an integer multiple of 4. */ static int MpegAudioDecoder(FILE *InputFp, FILE *OutputFp) { struct mad_stream Stream; struct mad_frame Frame; struct mad_synth Synth; mad_timer_t Timer; unsigned char InputBuffer[INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD], OutputBuffer[OUTPUT_BUFFER_SIZE], *OutputPtr=OutputBuffer, *GuardPtr=NULL; const unsigned char *OutputBufferEnd=OutputBuffer+OUTPUT_BUFFER_SIZE; int Status=0, i; unsigned long FrameCount=0; bstdfile_t *BstdFile; /* First the structures used by libmad must be initialized. */ mad_stream_init(&Stream); mad_frame_init(&Frame); mad_synth_init(&Synth); mad_timer_reset(&Timer); /* Decoding options can here be set in the options field of the * Stream structure. */ /* {1} When decoding from a file we need to know when the end of * the file is reached at the same time as the last bytes are read * (see also the comment marked {3} bellow). Neither the standard * C fread() function nor the POSIX read() system call provides * this feature. We thus need to perform our reads through an * interface having this feature, this is implemented here by the * bstdfile.c module. */ BstdFile=NewBstdFile(InputFp); if(BstdFile==NULL) { fprintf(stderr,"%s: can't create a new bstdfile_t (%s).\n", ProgName,strerror(errno)); return(1); } /* This is the decoding loop. */ do { /* The input bucket must be filled if it becomes empty or if * it's the first execution of the loop. */ if(Stream.buffer==NULL || Stream.error==MAD_ERROR_BUFLEN) { size_t ReadSize, Remaining; unsigned char *ReadStart; /* {2} libmad may not consume all bytes of the input * buffer. If the last frame in the buffer is not wholly * contained by it, then that frame's start is pointed by * the next_frame member of the Stream structure. This * common situation occurs when mad_frame_decode() fails, * sets the stream error code to MAD_ERROR_BUFLEN, and * sets the next_frame pointer to a non NULL value. (See * also the comment marked {4} bellow.) * * When this occurs, the remaining unused bytes must be * put back at the beginning of the buffer and taken in * account before refilling the buffer. This means that * the input buffer must be large enough to hold a whole * frame at the highest observable bit-rate (currently 448 * kb/s). XXX=XXX Is 2016 bytes the size of the largest * frame? (448000*(1152/32000))/8 */ if(Stream.next_frame!=NULL) { Remaining=Stream.bufend-Stream.next_frame; memmove(InputBuffer,Stream.next_frame,Remaining); ReadStart=InputBuffer+Remaining; ReadSize=INPUT_BUFFER_SIZE-Remaining; } else ReadSize=INPUT_BUFFER_SIZE, ReadStart=InputBuffer, Remaining=0; /* Fill-in the buffer. If an error occurs print a message * and leave the decoding loop. If the end of stream is * reached we also leave the loop but the return status is * left untouched. */ ReadSize=BstdRead(ReadStart,1,ReadSize,BstdFile); if(ReadSize<=0) { if(ferror(InputFp)) { fprintf(stderr,"%s: read error on bit-stream (%s)\n", ProgName,strerror(errno)); Status=1; } if(feof(InputFp)) fprintf(stderr,"%s: end of input stream\n",ProgName); break; } /* {3} When decoding the last frame of a file, it must be * followed by MAD_BUFFER_GUARD zero bytes if one wants to * decode that last frame. When the end of file is * detected we append that quantity of bytes at the end of * the available data. Note that the buffer can't overflow * as the guard size was allocated but not used the the * buffer management code. (See also the comment marked * {1}.) * * In a message to the mad-dev mailing list on May 29th, * 2001, Rob Leslie explains the guard zone as follows: * * "The reason for MAD_BUFFER_GUARD has to do with the * way decoding is performed. In Layer III, Huffman * decoding may inadvertently read a few bytes beyond * the end of the buffer in the case of certain invalid * input. This is not detected until after the fact. To * prevent this from causing problems, and also to * ensure the next frame's main_data_begin pointer is * always accessible, MAD requires MAD_BUFFER_GUARD * (currently 8) bytes to be present in the buffer past * the end of the current frame in order to decode the * frame." */ if(BstdFileEofP(BstdFile)) { GuardPtr=ReadStart+ReadSize; memset(GuardPtr,0,MAD_BUFFER_GUARD); ReadSize+=MAD_BUFFER_GUARD; } /* Pipe the new buffer content to libmad's stream decoder * facility. */ mad_stream_buffer(&Stream,InputBuffer,ReadSize+Remaining); Stream.error=0; } /* Decode the next MPEG frame. The streams is read from the * buffer, its constituents are break down and stored the the * Frame structure, ready for examination/alteration or PCM * synthesis. Decoding options are carried in the Frame * structure from the Stream structure. * * Error handling: mad_frame_decode() returns a non zero value * when an error occurs. The error condition can be checked in * the error member of the Stream structure. A mad error is * recoverable or fatal, the error status is checked with the * MAD_RECOVERABLE macro. * * {4} When a fatal error is encountered all decoding * activities shall be stopped, except when a MAD_ERROR_BUFLEN * is signaled. This condition means that the * mad_frame_decode() function needs more input to complete * its work. One shall refill the buffer and repeat the * mad_frame_decode() call. Some bytes may be left unused at * the end of the buffer if those bytes forms an incomplete * frame. Before refilling, the remaining bytes must be moved * to the beginning of the buffer and used for input for the * next mad_frame_decode() invocation. (See the comments * marked {2} earlier for more details.) * * Recoverable errors are caused by malformed bit-streams, in * this case one can call again mad_frame_decode() in order to * skip the faulty part and re-sync to the next frame. */ if(mad_frame_decode(&Frame,&Stream)) { if(MAD_RECOVERABLE(Stream.error)) { /* Do not print a message if the error is a loss of * synchronization and this loss is due to the end of * stream guard bytes. (See the comments marked {3} * supra for more informations about guard bytes.) */ if(Stream.error!=MAD_ERROR_LOSTSYNC || Stream.this_frame!=GuardPtr) { fprintf(stderr,"%s: recoverable frame level error (%s)\n", ProgName,MadErrorString(&Stream)); fflush(stderr); } continue; } else if(Stream.error==MAD_ERROR_BUFLEN) continue; else { fprintf(stderr,"%s: unrecoverable frame level error (%s).\n", ProgName,MadErrorString(&Stream)); Status=1; break; } } /* The characteristics of the stream's first frame is printed * on stderr. The first frame is representative of the entire * stream. */ if(FrameCount==0) if(PrintFrameInfo(stderr,&Frame.header)) { Status=1; break; } /* Accounting. The computed frame duration is in the frame * header structure. It is expressed as a fixed point number * whole data type is mad_timer_t. It is different from the * samples fixed point format and unlike it, it can't directly * be added or subtracted. The timer module provides several * functions to operate on such numbers. Be careful there, as * some functions of libmad's timer module receive some of * their mad_timer_t arguments by value! */ FrameCount++; mad_timer_add(&Timer,Frame.header.duration); /* Between the frame decoding and samples synthesis we can * perform some operations on the audio data. We do this only * if some processing was required. Detailed explanations are * given in the ApplyFilter() function. */ if(DoFilter) ApplyFilter(&Frame); /* Once decoded the frame is synthesized to PCM samples. No errors * are reported by mad_synth_frame(); */ mad_synth_frame(&Synth,&Frame); /* Synthesized samples must be converted from libmad's fixed * point number to the consumer format. Here we use unsigned * 16 bit big endian integers on two channels. Integer samples * are temporarily stored in a buffer that is flushed when * full. */ for(i=0;i<Synth.pcm.length;i++) { signed short Sample; /* Left channel */ Sample=MadFixedToSshort(Synth.pcm.samples[0][i]); *(OutputPtr++)=Sample>>8; *(OutputPtr++)=Sample&0xff; /* Right channel. If the decoded stream is monophonic then * the right output channel is the same as the left one. */ if(MAD_NCHANNELS(&Frame.header)==2) Sample=MadFixedToSshort(Synth.pcm.samples[1][i]); *(OutputPtr++)=Sample>>8; *(OutputPtr++)=Sample&0xff; /* Flush the output buffer if it is full. */ if(OutputPtr==OutputBufferEnd) { if(fwrite(OutputBuffer,1,OUTPUT_BUFFER_SIZE,OutputFp)!=OUTPUT_BUFFER_SIZE) { fprintf(stderr,"%s: PCM write error (%s).\n", ProgName,strerror(errno)); Status=2; break; } OutputPtr=OutputBuffer; } } }while(1); /* The input file was completely read; the memory allocated by our * reading module must be reclaimed. */ BstdFileDestroy(BstdFile); /* Mad is no longer used, the structures that were initialized must * now be cleared. */ mad_synth_finish(&Synth); mad_frame_finish(&Frame); mad_stream_finish(&Stream); /* If the output buffer is not empty and no error occurred during * the last write, then flush it. */ if(OutputPtr!=OutputBuffer && Status!=2) { size_t BufferSize=OutputPtr-OutputBuffer; if(fwrite(OutputBuffer,1,BufferSize,OutputFp)!=BufferSize) { fprintf(stderr,"%s: PCM write error (%s).\n", ProgName,strerror(errno)); Status=2; } } /* Accounting report if no error occurred. */ if(!Status) { char Buffer[80]; /* The duration timer is converted to a human readable string * with the versatile, but still constrained mad_timer_string() * function, in a fashion not unlike strftime(). The main * difference is that the timer is broken into several * values according some of it's arguments. The units and * fracunits arguments specify the intended conversion to be * executed. * * The conversion unit (MAD_UNIT_MINUTES in our example) also * specify the order and kind of conversion specifications * that can be used in the format string. * * It is best to examine libmad's timer.c source-code for details * of the available units, fraction of units, their meanings, * the format arguments, etc. */ mad_timer_string(Timer,Buffer,"%lu:%02lu.%03u", MAD_UNITS_MINUTES,MAD_UNITS_MILLISECONDS,0); fprintf(stderr,"%s: %lu frames decoded (%s).\n", ProgName,FrameCount,Buffer); } /* That's the end of the world (in the H. G. Wells way). */ return(Status); }