// // Read up samples from madSynth_ // If needed, read some more MP3 data, decode them and synth them // Place in audioBuffer_. // Return number of samples read. // size_t MadDecoder::decode(size_t numPendingTotal, AudioBuffer* buffer) { size_t numProcessedTotal = 0; int numChannels = getNumChannels(); mad_fixed_t sample; do { size_t numPendingFrame = (madSynth_.pcm.length - currentFrame_) * numChannels; numPendingFrame = std::min(numPendingTotal, numPendingFrame); size_t numProcessedFrame = 0; while (numProcessedFrame < numPendingFrame) { for (int channel = 0; channel < numChannels; channel++) { sample = madSynth_.pcm.samples[channel][currentFrame_]; if (sample < -MAD_F_ONE) sample = -MAD_F_ONE; else if (sample >= MAD_F_ONE) sample = MAD_F_ONE - 1; float fSample = (float)(sample / (float)(1L << MAD_F_FRACBITS)); float* pos = buffer->getHead() + numProcessedTotal; *pos = fSample; numProcessedFrame++; numProcessedTotal++; } currentFrame_++; } numPendingTotal -= numProcessedFrame; if (numPendingTotal == 0) break; if (madStream_.error == MAD_ERROR_BUFLEN) { // check whether input buffer needs a refill if (readMpgFile() == false) // eof break; } if (mad_frame_decode(&madFrame_, &madStream_)) { if (MAD_RECOVERABLE(madStream_.error)) { consumeId3Tag(); continue; } else { if (madStream_.error == MAD_ERROR_BUFLEN) continue; else THROW(std::exception, "unrecoverable frame level error (%s).", mad_stream_errorstr(&madStream_)); } } mad_timer_add(&madTimer_, madFrame_.header.duration); mad_synth_frame(&madSynth_, &madFrame_); currentFrame_ = 0; numMpegFrames_++; } while (true); return numProcessedTotal; }
static int mp3_decode_frame (mp3_s *mp3) { if (mp3->stream.buffer == NULL || mp3->stream.error == MAD_ERROR_BUFLEN) { if (mp3_fill_input (mp3) < 0) { return DECODE_BREAK; } } if (mad_frame_decode (&mp3->frame, &mp3->stream)) { if (MAD_RECOVERABLE (mp3->stream.error)) { return DECODE_CONT; } else { if (mp3->stream.error == MAD_ERROR_BUFLEN) { return DECODE_CONT; } else { printf ("Unrecoverable frame error: \'%s\'\n", mad_stream_errorstr (&mp3->stream)); mp3->status = 1; return DECODE_BREAK; } } } mp3->frame_count++; return DECODE_OK; }
void decode() { // While we need to fill the buffer... while ( (mad_frame_decode(&frame, &stream) == -1) && ((stream.error == MAD_ERROR_BUFLEN) || (stream.error == MAD_ERROR_BUFPTR)) ) { // Fill up the remainder of the file buffer. int tmp; tmp = fillFileBuffer(); if (tmp==2) { endofstream = 1; //MusicPlayerNextSong(); /*! * * Put here the function that does something when the file has ended. * */ } // Give new buffer to the stream. mad_stream_buffer(&stream, fileBuffer, sizeof(fileBuffer)); } // Add to the timer the stream duration mad_timer_add(&timer, frame.header.duration); // Synth the frame. mad_synth_frame(&synth, &frame); }
static int read_frame(sh_audio_t *sh){ mad_decoder_t *this = sh->context; int len; while((len=demux_read_data(sh->ds,&sh->a_in_buffer[sh->a_in_buffer_len], sh->a_in_buffer_size-sh->a_in_buffer_len))>0){ sh->a_in_buffer_len+=len; while(1){ int ret; mad_stream_buffer (&this->stream, sh->a_in_buffer, sh->a_in_buffer_len); ret=mad_frame_decode (&this->frame, &this->stream); if (this->stream.next_frame) { int num_bytes = (char*)sh->a_in_buffer+sh->a_in_buffer_len - (char*)this->stream.next_frame; memmove(sh->a_in_buffer, this->stream.next_frame, num_bytes); mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"libmad: %d bytes processed\n",sh->a_in_buffer_len-num_bytes); sh->a_in_buffer_len = num_bytes; } if (ret == 0) return 1; // OK!!! // error! try to resync! if(this->stream.error==MAD_ERROR_BUFLEN) break; } } mp_msg(MSGT_DECAUDIO,MSGL_INFO,"Cannot sync MAD frame\n"); return 0; }
size_t MadDecoder::start(FILE* handle) { handle_ = handle; decodeBuffer_.resize(bufferSize_, false); ASSERT(decodeBuffer_.size() == bufferSize_); unsigned char* buffer = decodeBuffer_.getHead(); int64 durationMsec = getDurationMs(buffer, bufferSize_); mad_stream_init(&madStream_); mad_frame_init(&madFrame_); mad_synth_init(&madSynth_); mad_timer_reset(&madTimer_); // Decode at least one valid frame to find out the input format. // The decoded frame will be saved off so that it can be processed later. // size_t bytesRead = fread(buffer, (size_t)1, bufferSize_, handle_); if (bytesRead != bufferSize_ && ferror(handle_)) THROW(std::exception, "%s", strerror(errno)); mad_stream_buffer(&madStream_, buffer, bytesRead); // Find a valid frame before starting up. // This make sure that we have a valid MP3 // and also skips past ID3v2 tags at the beginning of the audio file. // madStream_.error = MAD_ERROR_NONE; while (mad_frame_decode(&madFrame_, &madStream_)) { // check whether input buffer needs a refill if (madStream_.error == MAD_ERROR_BUFLEN) { if (readMpgFile() == false) break; // eof else continue; } consumeId3Tag(); // consume any ID3 tags // FIXME: We should probably detect when we've read // a bunch of non-ID3 data and still haven't found a // frame. In that case we can abort early without // scanning the whole file. // madStream_.error = MAD_ERROR_NONE; } if (madStream_.error) { THROW(std::exception, "No valid MP3 frame found"); } mad_timer_add(&madTimer_, madFrame_.header.duration); mad_synth_frame(&madSynth_, &madFrame_); //unsigned int precision_ = 16; currentFrame_ = 0; numMpegFrames_ = 0; initialized_ = true; return (size_t)(durationMsec * .001 * getSampleRate() + .5); // number of sample frames }
/***************************************************************************** * DoWork: decode an MPEG audio frame. *****************************************************************************/ static void DoWork( filter_t * p_filter, block_t * p_in_buf, block_t * p_out_buf ) { filter_sys_t *p_sys = p_filter->p_sys; p_out_buf->i_nb_samples = p_in_buf->i_nb_samples; p_out_buf->i_buffer = p_in_buf->i_nb_samples * sizeof(vlc_fixed_t) * aout_FormatNbChannels( &p_filter->fmt_out.audio ); /* Do the actual decoding now. */ mad_stream_buffer( &p_sys->mad_stream, p_in_buf->p_buffer, p_in_buf->i_buffer ); if ( mad_frame_decode( &p_sys->mad_frame, &p_sys->mad_stream ) == -1 ) { msg_Dbg( p_filter, "libmad error: %s", mad_stream_errorstr( &p_sys->mad_stream ) ); p_sys->i_reject_count = 3; } else if( p_in_buf->i_flags & BLOCK_FLAG_DISCONTINUITY ) { p_sys->i_reject_count = 3; } if( p_sys->i_reject_count > 0 ) { memset( p_out_buf->p_buffer, 0, p_out_buf->i_buffer ); p_sys->i_reject_count--; return; } mad_synth_frame( &p_sys->mad_synth, &p_sys->mad_frame ); struct mad_pcm * p_pcm = &p_sys->mad_synth.pcm; unsigned int i_samples = p_pcm->length; mad_fixed_t const * p_left = p_pcm->samples[0]; mad_fixed_t const * p_right = p_pcm->samples[1]; mad_fixed_t * p_samples = (mad_fixed_t *)p_out_buf->p_buffer; assert( i_samples == p_out_buf->i_nb_samples ); /* Interleave and keep buffers in mad_fixed_t format */ if ( p_pcm->channels == 2 ) { while ( i_samples-- ) { *p_samples++ = *p_left++; *p_samples++ = *p_right++; } } else { assert( p_pcm->channels == 1 ); memcpy( p_samples, p_left, i_samples * sizeof(mad_fixed_t) ); } }
/* Returns 1 if a recoverable error occured, 0 else. */ int mad_js_decode_frame(madfile_t *mf) { int dec; dec = mad_frame_decode(&mf->frame, &mf->stream); if (dec) { if (MAD_RECOVERABLE(mf->stream.error) || mf->stream.error == MAD_ERROR_BUFLEN) { return 1; } else { _mad_js_raise(mad_stream_errorstr(&mf->stream)); } } mad_synth_frame(&mf->synth, &mf->frame); return 0; }
static enum mp3_action decodeNextFrame(struct mp3_data *data) { if ((data->stream).buffer == NULL || (data->stream).error == MAD_ERROR_BUFLEN) { if (!mp3_fill_buffer(data)) return DECODE_BREAK; } if (mad_frame_decode(&data->frame, &data->stream)) { #ifdef HAVE_ID3TAG if ((data->stream).error == MAD_ERROR_LOSTSYNC) { signed long tagsize = id3_tag_query((data->stream). this_frame, (data->stream). bufend - (data->stream). this_frame); if (tagsize > 0) { mad_stream_skip(&(data->stream), tagsize); return DECODE_CONT; } } #endif if (MAD_RECOVERABLE((data->stream).error)) { return DECODE_SKIP; } else { if ((data->stream).error == MAD_ERROR_BUFLEN) return DECODE_CONT; else { g_warning("unrecoverable frame level error " "(%s).\n", mad_stream_errorstr(&data->stream)); return DECODE_BREAK; } } } return DECODE_OK; }
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 gint xmms_mad_read (xmms_xform_t *xform, gpointer buf, gint len, xmms_error_t *err) { xmms_mad_data_t *data; xmms_samples16_t *out = (xmms_samples16_t *)buf; gint ret; gint j; gint read = 0; data = xmms_xform_private_data_get (xform); j = 0; while (read < len) { /* use already synthetized frame first */ if (data->synthpos < data->synth.pcm.length) { out[j++] = scale_linear (data->synth.pcm.samples[0][data->synthpos]); if (data->channels == 2) { out[j++] = scale_linear (data->synth.pcm.samples[1][data->synthpos]); read += 2 * xmms_sample_size_get (XMMS_SAMPLE_FORMAT_S16); } else { read += xmms_sample_size_get (XMMS_SAMPLE_FORMAT_S16); } data->synthpos++; continue; } /* then try to decode another frame */ if (mad_frame_decode (&data->frame, &data->stream) != -1) { /* mad_synthpop_frame - go Depeche! */ mad_synth_frame (&data->synth, &data->frame); if (data->frames_to_skip) { data->frames_to_skip--; data->synthpos = 0x7fffffff; } else if (data->samples_to_skip) { if (data->samples_to_skip > data->synth.pcm.length) { data->synthpos = 0x7fffffff; data->samples_to_skip -= data->synth.pcm.length; } else { data->synthpos = data->samples_to_skip; data->samples_to_skip = 0; } } else { if (data->samples_to_play == 0) { return read; } else if (data->samples_to_play > 0) { if (data->synth.pcm.length > data->samples_to_play) { data->synth.pcm.length = data->samples_to_play; } data->samples_to_play -= data->synth.pcm.length; } data->synthpos = 0; } continue; } /* if there is no frame to decode stream more data */ if (data->stream.next_frame) { guchar *buffer = data->buffer; const guchar *nf = data->stream.next_frame; memmove (data->buffer, data->stream.next_frame, data->buffer_length = (&buffer[data->buffer_length] - nf)); } ret = xmms_xform_read (xform, (gchar *)data->buffer + data->buffer_length, 4096 - data->buffer_length, err); if (ret <= 0) { return ret; } data->buffer_length += ret; mad_stream_buffer (&data->stream, data->buffer, data->buffer_length); } return read; }
static void mp_render_ex (void *dest, unsigned nsamp) { short *sout = (short *) dest; int localerrors = 0; if (!mp_playing || mp_paused) { memset (dest, 0, nsamp * 4); return; } while (1) { // write any leftover data from last MP3 frame while (mp_leftoversamps > 0 && nsamp > 0) { short s = mp_fixtoshort (Synth.pcm.samples[0][mp_leftoversamppos]); *sout++ = s; if (Synth.pcm.channels == 2) s = mp_fixtoshort (Synth.pcm.samples[1][mp_leftoversamppos]); // if mono, just duplicate the first channel again *sout++ = s; mp_leftoversamps -= 1; mp_leftoversamppos += 1; nsamp -= 1; } if (nsamp == 0) return; // done // decode next valid MP3 frame while (mad_frame_decode (&Frame, &Stream) != 0) { if (MAD_RECOVERABLE (Stream.error)) { // unspecified problem with one frame. // try the next frame, but bail if we get a bunch of crap in a row; // likely indicates a larger problem (and if we don't bail, we could // spend arbitrarily long amounts of time looking for the next good // packet) localerrors++; if (localerrors == 10) { lprintf (LO_WARN, "mad_frame_decode: Lots of errors. Most recent %s\n", mad_stream_errorstr (&Stream)); mp_playing = 0; memset (sout, 0, nsamp * 4); return; } } else if (Stream.error == MAD_ERROR_BUFLEN) { // EOF // FIXME: in order to not drop the last frame, there must be at least MAD_BUFFER_GUARD // of extra bytes (with value 0) at the end of the file. current implementation // drops last frame if (mp_looping) { // rewind, then go again mad_stream_buffer (&Stream, mp_data, mp_len); continue; } else { // stop mp_playing = 0; memset (sout, 0, nsamp * 4); return; } } else { // oh well. lprintf (LO_WARN, "mad_frame_decode: Unrecoverable error %s\n", mad_stream_errorstr (&Stream)); mp_playing = 0; memset (sout, 0, nsamp * 4); return; } } // got a good frame, so synth it and dispatch it. mad_synth_frame (&Synth, &Frame); mp_leftoversamps = Synth.pcm.length; mp_leftoversamppos = 0; } // NOT REACHED }
// MP3 decode player void MP3Player(void) { FRESULT res; uint8_t *ReadStart; uint8_t *GuardPtr; volatile uint8_t u8PCMBufferTargetIdx = 0; volatile uint32_t pcmbuf_idx, i; volatile unsigned int Mp3FileOffset=0; uint16_t sampleL, sampleR; pcmbuf_idx = 0; memset((void *)&audioInfo, 0, sizeof(audioInfo)); /* Parse MP3 header */ MP3_ParseHeaderInfo(MP3_FILE); /* First the structures used by libmad must be initialized. */ mad_stream_init(&Stream); mad_frame_init(&Frame); mad_synth_init(&Synth); /* Open MP3 file */ res = f_open(&mp3FileObject, MP3_FILE, FA_OPEN_EXISTING | FA_READ); if (res != FR_OK) { printf("Open file error \r\n"); return; } /* Open I2S1 interface and set to slave mode, stereo channel, I2S format */ I2S_Open(I2S1, I2S_MODE_SLAVE, 16000, I2S_DATABIT_16, I2S_STEREO, I2S_FORMAT_I2S, I2S_I2S); /* Initialize WAU8822 codec */ WAU8822_Setup(); /* Configure wau8822 for specific sampling rate */ WAU8822_ConfigSampleRate(audioInfo.mp3SampleRate); /* Set MCLK and enable MCLK */ I2S_EnableMCLK(I2S1, 12000000); while(1) { if(Stream.buffer==NULL || Stream.error==MAD_ERROR_BUFLEN) { if(Stream.next_frame != NULL) { /* Get the remaining frame */ Remaining = Stream.bufend - Stream.next_frame; memmove(MadInputBuffer, Stream.next_frame, Remaining); ReadStart = MadInputBuffer + Remaining; ReadSize = FILE_IO_BUFFER_SIZE - Remaining; } else { ReadSize = FILE_IO_BUFFER_SIZE, ReadStart = MadInputBuffer, Remaining = 0; } /* read the file from SDCard */ res = f_read(&mp3FileObject, ReadStart, ReadSize, &ReturnSize); if((res != FR_OK) || f_eof(&mp3FileObject)) { printf("Stop !(%x)\n\r", res); goto stop; } /* if the file is over */ if (ReadSize > ReturnSize) { GuardPtr=ReadStart+ReadSize; memset(GuardPtr,0,MAD_BUFFER_GUARD); ReadSize+=MAD_BUFFER_GUARD; } Mp3FileOffset = Mp3FileOffset + ReturnSize; /* Pipe the new buffer content to libmad's stream decoder * facility. */ mad_stream_buffer(&Stream,MadInputBuffer,ReadSize+Remaining); Stream.error=(enum mad_error)0; } /* decode a frame from the mp3 stream data */ if(mad_frame_decode(&Frame,&Stream)) { if(MAD_RECOVERABLE(Stream.error)) { /*if(Stream.error!=MAD_ERROR_LOSTSYNC || Stream.this_frame!=GuardPtr) { }*/ continue; } else { /* the current frame is not full, need to read the remaining part */ if(Stream.error==MAD_ERROR_BUFLEN) { continue; } else { printf("Something error!!\n"); /* play the next file */ audioInfo.mp3FileEndFlag = 1; goto stop; } } } /* Once decoded the frame is synthesized to PCM samples. No errors * are reported by mad_synth_frame(); */ mad_synth_frame(&Synth,&Frame); // // decode finished, try to copy pcm data to audio buffer // if(audioInfo.mp3Playing) { //if next buffer is still full (playing), wait until it's empty if(aPCMBuffer_Full[u8PCMBufferTargetIdx] == 1) while(aPCMBuffer_Full[u8PCMBufferTargetIdx]); } else { if((aPCMBuffer_Full[0] == 1) && (aPCMBuffer_Full[1] == 1 )) { //all buffers are full, wait StartPlay(); } } for(i=0; i<(int)Synth.pcm.length; i++) { /* Get the left/right samples */ sampleL = Synth.pcm.samples[0][i]; sampleR = Synth.pcm.samples[1][i]; /* Fill PCM data to I2S(PDMA) buffer */ aPCMBuffer[u8PCMBufferTargetIdx][pcmbuf_idx++] = sampleR | (sampleL << 16); /* Need change buffer ? */ if(pcmbuf_idx == PCM_BUFFER_SIZE) { aPCMBuffer_Full[u8PCMBufferTargetIdx] = 1; //set full flag u8PCMBufferTargetIdx ^= 1; pcmbuf_idx = 0; // printf("change to ==>%d ..\n", u8PCMBufferTargetIdx); /* if next buffer is still full (playing), wait until it's empty */ if((aPCMBuffer_Full[u8PCMBufferTargetIdx] == 1) && (audioInfo.mp3Playing)) while(aPCMBuffer_Full[u8PCMBufferTargetIdx]); } } } stop: printf("Exit MP3\r\n"); mad_synth_finish(&Synth); mad_frame_finish(&Frame); mad_stream_finish(&Stream); f_close(&mp3FileObject); StopPlay(); }
/* * NAME: scan_header() * DESCRIPTION: read the initial frame(s) to get stream statistics */ static int scan_header(CPs_InStream* pInStream, struct mad_header *header, struct xing *xing) { struct mad_stream stream; struct mad_frame frame; unsigned char buffer[8192]; unsigned int buflen = 0; int count = 0, result = 0; mad_stream_init(&stream); mad_frame_init(&frame); if (xing) xing->flags = 0; while (1) { if (buflen < sizeof(buffer)) { // DWORD bytes; unsigned int bytes; if (pInStream->Read(pInStream, buffer + buflen, sizeof(buffer) - buflen, &bytes) == FALSE || bytes == 0) { result = -1; break; } buflen += bytes; } mad_stream_buffer(&stream, buffer, buflen); while (1) { if (mad_frame_decode(&frame, &stream) == -1) { if (!MAD_RECOVERABLE(stream.error)) break; continue; } if (count++ || (xing && parse_xing(xing, stream.anc_ptr, stream.anc_bitlen) == 0)) break; } if (count || stream.error != MAD_ERROR_BUFLEN) break; memmove(buffer, stream.next_frame, buflen = &buffer[buflen] - stream.next_frame); } if (count) { if (header) *header = frame.header; } else result = -1; mad_frame_finish(&frame); mad_stream_finish(&stream); return result; }
static OMX_ERRORTYPE decode_buffer (const void * ap_obj) { mp3d_prc_t * p_obj = (mp3d_prc_t *) ap_obj; unsigned char * p_guardzone = NULL; int status = 0; assert (p_obj->p_outhdr_); /* Check if there is any remaining PCM data from a previous run of the * decoding loop that needs to be synthesised */ if ((0 != p_obj->next_synth_sample_ && p_obj->next_synth_sample_ < p_obj->synth_.pcm.length) && (p_obj->p_outhdr_->nFilledLen < p_obj->p_outhdr_->nAllocLen)) { p_obj->next_synth_sample_ = synthesize_samples (p_obj, p_obj->next_synth_sample_); } while (p_obj->p_outhdr_) { /* The input bucket must be filled if it becomes empty or if * it's the first execution of the loop. */ if ((NULL == p_obj->stream_.buffer || MAD_ERROR_BUFLEN == p_obj->stream_.error) && p_obj->p_inhdr_ != NULL) { size_t read_size = 0; unsigned char * p_read_start = NULL; p_obj->remaining_ = 0; if (p_obj->stream_.next_frame != NULL) { p_obj->remaining_ = p_obj->stream_.bufend - p_obj->stream_.next_frame; memmove (p_obj->in_buff_, p_obj->stream_.next_frame, p_obj->remaining_); p_read_start = p_obj->in_buff_ + p_obj->remaining_; read_size = INPUT_BUFFER_SIZE - p_obj->remaining_; } else { read_size = INPUT_BUFFER_SIZE; p_read_start = p_obj->in_buff_; p_obj->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 = read_from_omx_buffer (p_obj, p_read_start, read_size, p_obj->p_inhdr_); if (read_size == 0) { if ((p_obj->p_inhdr_->nFlags & OMX_BUFFERFLAG_EOS) != 0) { TIZ_TRACE (handleOf (p_obj), "end of input stream"); status = 2; } else { TIZ_TRACE (handleOf (p_obj), "read_size <= 0"); status = 1; } break; } /* TODO */ /* if(BstdFileEofP (BstdFile)) */ /* { */ /* p_guardzone = p_read_start + read_size; */ /* memset (p_guardzone, 0, MAD_BUFFER_GUARD); */ /* read_size += MAD_BUFFER_GUARD; */ /* } */ /* Pipe the new buffer content to libmad's stream decoder * facility. */ mad_stream_buffer (&p_obj->stream_, p_obj->in_buff_, read_size + p_obj->remaining_); p_obj->stream_.error = 0; } if (mad_frame_decode (&p_obj->frame_, &p_obj->stream_) == -1) { if (MAD_RECOVERABLE (p_obj->stream_.error)) { if (p_obj->stream_.error != MAD_ERROR_LOSTSYNC || p_obj->stream_.this_frame != p_guardzone) { TIZ_TRACE (handleOf (p_obj), "recoverable frame level error (%s)", mad_stream_errorstr (&p_obj->stream_)); } continue; } else { if (p_obj->stream_.error == MAD_ERROR_BUFLEN) { if (!p_obj->p_inhdr_) { TIZ_TRACE (handleOf (p_obj), "p_obj->stream_.error==MAD_ERROR_BUFLEN " "p_obj->p_inhdr_=[NULL]"); break; } else { TIZ_TRACE (handleOf (p_obj), "p_obj->stream_.error==MAD_ERROR_BUFLEN " "p_obj->p_inhdr_=[%p] nFilledLen [%d]", p_obj->p_inhdr_, p_obj->p_inhdr_->nFilledLen); continue; } } else { TIZ_TRACE (handleOf (p_obj), "unrecoverable frame level error (%s).", mad_stream_errorstr (&p_obj->stream_)); status = 2; break; } } } /* The characteristics of the stream's first frame is printed The first * frame is representative of the entire stream. */ if (0 == p_obj->frame_count_) { store_stream_metadata (p_obj, &(p_obj->frame_.header)); } p_obj->frame_count_++; mad_timer_add (&p_obj->timer_, p_obj->frame_.header.duration); /* Once decoded the frame is synthesized to PCM samples. No errors * are reported by mad_synth_frame(); */ mad_synth_frame (&p_obj->synth_, &p_obj->frame_); p_obj->next_synth_sample_ = synthesize_samples (p_obj, p_obj->next_synth_sample_); } (void) status; /* TODO */ /* if (p_obj->p_outhdr_ != NULL */ /* && p_obj->p_outhdr_->nFilledLen != 0 */ /* && status == 2) */ /* { */ /* const tiz_srv_t *p_parent = ap_obj; */ /* void *p_krn = tiz_get_krn (p_parent->p_hdl_); */ /* p_obj->eos_ = true; */ /* p_obj->p_outhdr_->nFlags |= OMX_BUFFERFLAG_EOS; */ /* TIZ_LOG (TIZ_PRIORITY_TRACE, handleOf (p_obj), */ /* "Releasing output buffer [%p] ..." */ /* "nFilledLen = [%d] OMX_BUFFERFLAG_EOS", */ /* p_obj->p_outhdr_, p_obj->p_outhdr_->nFilledLen); */ /* tiz_krn_release_buffer (tiz_get_krn (handleOf (ap_obj)), 1, * p_obj->p_outhdr_); */ /* /\* p_obj->p_outhdr_ = NULL; *\/ */ /* } */ return OMX_ErrorNone; }
void CodecMpeg1::process(const QByteArray &data,bool is_last) { #ifdef HAVE_LIBMAD float pcm[32768*4]; int frame_offset=0; int err_count=0; mpeg1_mpeg.append(data); mad_stream_buffer(&mpeg1_mad_stream,(const unsigned char *)mpeg1_mpeg.data(), mpeg1_mpeg.length()); do { while(mad_frame_decode(&mpeg1_mad_frame,&mpeg1_mad_stream)==0) { mad_synth_frame(&mpeg1_mad_synth,&mpeg1_mad_frame); for(int i=0;i<mpeg1_mad_synth.pcm.length;i++) { for(int j=0;j<mpeg1_mad_synth.pcm.channels;j++) { pcm[frame_offset+i*mpeg1_mad_synth.pcm.channels+j]= (float)mad_f_todouble(mpeg1_mad_synth.pcm.samples[j][i]); } } frame_offset+=(mpeg1_mad_synth.pcm.length*mpeg1_mad_synth.pcm.channels); } if(MAD_RECOVERABLE(mpeg1_mad_stream.error)!=0) { if(err_count++>10) { Reset(); break; } } } while(mpeg1_mad_stream.error!=MAD_ERROR_BUFLEN); if(mpeg1_mad_stream.error==MAD_ERROR_BUFLEN) { if(frame_offset>0) { mpeg1_mad_header=mpeg1_mad_frame.header; if(!isFramed()) { int channels=2; if(mpeg1_mad_frame.header.mode==MAD_MODE_SINGLE_CHANNEL) { channels=1; } setFramed(channels,mpeg1_mad_frame.header.samplerate, mpeg1_mad_frame.header.bitrate/1000); } else { writePcm(pcm,frame_offset/channels(),is_last); } } mpeg1_mpeg= mpeg1_mpeg.right(mpeg1_mad_stream.bufend-mpeg1_mad_stream.next_frame); } if(is_last) { frame_offset=0; mpeg1_mpeg.append(0,MAD_BUFFER_GUARD); mad_stream_buffer(&mpeg1_mad_stream,(const unsigned char *)mpeg1_mpeg.data(), mpeg1_mpeg.length()); do { while(mad_frame_decode(&mpeg1_mad_frame,&mpeg1_mad_stream)==0) { mad_synth_frame(&mpeg1_mad_synth,&mpeg1_mad_frame); for(int i=0;i<mpeg1_mad_synth.pcm.length;i++) { for(int j=0;j<mpeg1_mad_synth.pcm.channels;j++) { pcm[frame_offset+i*mpeg1_mad_synth.pcm.channels+j]= (float)mad_f_todouble(mpeg1_mad_synth.pcm.samples[j][i]); } } frame_offset+=(mpeg1_mad_synth.pcm.length*mpeg1_mad_synth.pcm.channels); } if(MAD_RECOVERABLE(mpeg1_mad_stream.error)!=0) { if(err_count++>10) { Reset(); break; } } } while(mpeg1_mad_stream.error!=MAD_ERROR_BUFLEN); writePcm(pcm,frame_offset/channels(),is_last); } #endif // HAVE_LIBMAD }
/* Read up to len samples from p->Synth * If needed, read some more MP3 data, decode them and synth them * Place in buf[]. * Return number of samples read. */ static int mp3_decode(snd_stream_t *stream, byte *buf, int len) { mp3_priv_t *p = (mp3_priv_t *) stream->priv; int donow, i, done = 0; mad_fixed_t sample; int chan, x; do { x = (p->Synth.pcm.length - p->cursamp) * stream->info.channels; donow = min(len, x); i = 0; while (i < donow) { for (chan = 0; chan < stream->info.channels; chan++) { sample = p->Synth.pcm.samples[chan][p->cursamp]; /* convert from fixed to short, * write in host-endian format. */ if (sample <= -MAD_F_ONE) sample = -0x7FFF; else if (sample >= MAD_F_ONE) sample = 0x7FFF; else sample >>= (MAD_F_FRACBITS + 1 - 16); if (host_bigendian) { *buf++ = (sample >> 8) & 0xFF; *buf++ = sample & 0xFF; } else /* assumed LITTLE_ENDIAN. */ { *buf++ = sample & 0xFF; *buf++ = (sample >> 8) & 0xFF; } i++; } p->cursamp++; } len -= donow; done += donow; if (len == 0) break; /* check whether input buffer needs a refill */ if (p->Stream.error == MAD_ERROR_BUFLEN) { if (mp3_inputdata(stream) == -1) { /* check feof() ?? */ Con_DPrintf("mp3 EOF\n"); break; } } if (mad_frame_decode(&p->Frame, &p->Stream)) { if (MAD_RECOVERABLE(p->Stream.error)) { mp3_inputtag(stream); continue; } else { if (p->Stream.error == MAD_ERROR_BUFLEN) continue; else { Con_Printf("MP3: unrecoverable frame level error (%s)\n", mad_stream_errorstr(&p->Stream)); break; } } } p->FrameCount++; mad_timer_add(&p->Timer, p->Frame.header.duration); mad_synth_frame(&p->Synth, &p->Frame); p->cursamp = 0; } while (1);
int Mp3Decoder::Read(u8 * buffer, int buffer_size, int pos UNUSED) { if(!file_fd) return -1; if(Format == VOICE_STEREO_16BIT) buffer_size &= ~0x0003; else buffer_size &= ~0x0001; u8 * write_pos = buffer; u8 * write_end = buffer+buffer_size; while(1) { while(SynthPos < Synth.pcm.length) { if(write_pos >= write_end) return write_pos-buffer; *((s16 *) write_pos) = FixedToShort(Synth.pcm.samples[0][SynthPos]); write_pos += 2; if(MAD_NCHANNELS(&Frame.header) == 2) { *((s16 *) write_pos) = FixedToShort(Synth.pcm.samples[1][SynthPos]); write_pos += 2; } SynthPos++; } if(Stream.buffer == NULL || Stream.error == MAD_ERROR_BUFLEN) { u8 * ReadStart = ReadBuffer; int ReadSize = SoundBlockSize*SoundBlocks; int Remaining = 0; if(Stream.next_frame != NULL) { Remaining = Stream.bufend - Stream.next_frame; memmove(ReadBuffer, Stream.next_frame, Remaining); ReadStart += Remaining; ReadSize -= Remaining; } ReadSize = file_fd->read(ReadStart, ReadSize); if(ReadSize <= 0) { GuardPtr = ReadStart; memset(GuardPtr, 0, MAD_BUFFER_GUARD); ReadSize = MAD_BUFFER_GUARD; } CurPos += ReadSize; mad_stream_buffer(&Stream, ReadBuffer, Remaining+ReadSize); } if(mad_frame_decode(&Frame,&Stream)) { if(MAD_RECOVERABLE(Stream.error)) { if(Stream.error != MAD_ERROR_LOSTSYNC || !GuardPtr) continue; } else { if(Stream.error != MAD_ERROR_BUFLEN) return -1; else if(Stream.error == MAD_ERROR_BUFLEN && GuardPtr) return -1; } } mad_timer_add(&Timer,Frame.header.duration); mad_synth_frame(&Synth,&Frame); SynthPos = 0; } return 0; }
int mp3_mad_stream_frame (mp3_info_t *info) { int eof = 0; while (!eof && (info->mad_stream.buffer == NULL || info->buffer.decode_remaining <= 0)) { // read more MPEG data if needed if(info->mad_stream.buffer==NULL || info->mad_stream.error==MAD_ERROR_BUFLEN) { // copy part of last frame to beginning if (info->mad_stream.next_frame && info->mad_stream.bufend <= info->mad_stream.next_frame) { eof = 1; break; } if (info->mad_stream.next_frame != NULL) { info->buffer.remaining = info->mad_stream.bufend - info->mad_stream.next_frame; memmove (info->buffer.input, info->mad_stream.next_frame, info->buffer.remaining); } int size = READBUFFER - info->buffer.remaining; int bytesread = 0; uint8_t *bytes = info->buffer.input + info->buffer.remaining; bytesread = deadbeef->fread (bytes, 1, size, info->buffer.file); if (!bytesread) { // add guard eof = 1; memset (bytes, 0, 8); bytesread = 8; } if (bytesread < size) { // end of file size -= bytesread; bytes += bytesread; } bytesread += info->buffer.remaining; mad_stream_buffer(&info->mad_stream,info->buffer.input,bytesread); if (info->mad_stream.buffer==NULL) { // check sync bits if (bytes[0] != 0xff || (bytes[1]&(3<<5)) != (3<<5)) { trace ("mp3: read didn't start at frame boundary!\ncmp3_scan_stream is broken\n"); } else { trace ("mp3: streambuffer=NULL\n"); } } } info->mad_stream.error=0; // decode next frame if(mad_frame_decode(&info->mad_frame, &info->mad_stream)) { if(MAD_RECOVERABLE(info->mad_stream.error)) { if(info->mad_stream.error!=MAD_ERROR_LOSTSYNC) { // printf ("mp3: recoverable frame level error (%s)\n", MadErrorString(&info->stream)); } if (info->buffer.lead_in_frames > 0) { info->buffer.lead_in_frames--; } continue; } else { if(info->mad_stream.error==MAD_ERROR_BUFLEN) { // printf ("mp3: recoverable frame level error (%s)\n", MadErrorString(&info->stream)); continue; } else { // printf ("mp3: unrecoverable frame level error (%s).\n", MadErrorString(&info->stream)); return -1; // fatal error } } } mad_synth_frame(&info->mad_synth,&info->mad_frame); if (info->buffer.lead_in_frames > 0) { info->buffer.lead_in_frames--; info->buffer.decode_remaining = 0; continue; } info->info.fmt.samplerate = info->mad_frame.header.samplerate; // synthesize single frame info->buffer.decode_remaining = info->mad_synth.pcm.length; deadbeef->streamer_set_bitrate (info->mad_frame.header.bitrate/1000); break; } return eof; }
SINT SoundSourceMp3::readSampleFrames( SINT numberOfFrames, CSAMPLE* sampleBuffer, SINT sampleBufferSize, bool readStereoSamples) { DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(getSampleBufferSize(numberOfFrames, readStereoSamples) <= sampleBufferSize); const SINT numberOfFramesTotal = math_min( numberOfFrames, getMaxFrameIndex() - m_curFrameIndex); CSAMPLE* pSampleBuffer = sampleBuffer; SINT numberOfFramesRemaining = numberOfFramesTotal; while (0 < numberOfFramesRemaining) { if (0 >= m_madSynthCount) { // When all decoded output data has been consumed... DEBUG_ASSERT(0 == m_madSynthCount); // ...decode the next MP3 frame DEBUG_ASSERT(m_madStream.buffer); DEBUG_ASSERT(m_madStream.this_frame); // WARNING: Correctly evaluating and handling the result // of mad_frame_decode() has proven to be extremely tricky. // Don't change anything at the following lines of code // unless you know what you are doing!!! unsigned char const* pMadThisFrame = m_madStream.this_frame; if (mad_frame_decode(&m_madFrame, &m_madStream)) { // Something went wrong when decoding the frame... if (MAD_ERROR_BUFLEN == m_madStream.error) { // Abort break; } if (isUnrecoverableError(m_madStream)) { qWarning() << "Unrecoverable MP3 frame decoding error:" << mad_stream_errorstr(&m_madStream); // Abort decoding break; } if (isRecoverableError(m_madStream)) { if (pMadThisFrame != m_madStream.this_frame) { // Ignore all recoverable errors (and especially // "lost synchronization" warnings) while skipping // over prefetched frames after seeking. if (pSampleBuffer) { qWarning() << "Recoverable MP3 frame decoding error:" << mad_stream_errorstr(&m_madStream); } else { // Decoded samples will simply be discarded qDebug() << "Recoverable MP3 frame decoding error while skipping:" << mad_stream_errorstr(&m_madStream); } } // Continue decoding } } if (pMadThisFrame == m_madStream.this_frame) { qDebug() << "Retry decoding MP3 frame @" << m_curFrameIndex; // Retry decoding continue; } DEBUG_ASSERT(isStreamValid(m_madStream)); #ifndef QT_NO_DEBUG_OUTPUT const SINT madFrameChannelCount = MAD_NCHANNELS(&m_madFrame.header); if (madFrameChannelCount != getChannelCount()) { qDebug() << "MP3 frame header with mismatching number of channels" << madFrameChannelCount << "<>" << getChannelCount(); } #endif // Once decoded the frame is synthesized to PCM samples mad_synth_frame(&m_madSynth, &m_madFrame); #ifndef QT_NO_DEBUG_OUTPUT const SINT madSynthSampleRate = m_madSynth.pcm.samplerate; if (madSynthSampleRate != getSamplingRate()) { qDebug() << "Reading MP3 data with different sampling rate" << madSynthSampleRate << "<>" << getSamplingRate(); } #endif m_madSynthCount = m_madSynth.pcm.length; DEBUG_ASSERT(0 < m_madSynthCount); } const SINT synthReadCount = math_min( m_madSynthCount, numberOfFramesRemaining); if (pSampleBuffer) { DEBUG_ASSERT(m_madSynthCount <= m_madSynth.pcm.length); const SINT madSynthOffset = m_madSynth.pcm.length - m_madSynthCount; DEBUG_ASSERT(madSynthOffset < m_madSynth.pcm.length); const SINT madSynthChannelCount = m_madSynth.pcm.channels; DEBUG_ASSERT(0 < madSynthChannelCount); DEBUG_ASSERT(madSynthChannelCount <= getChannelCount()); #ifndef QT_NO_DEBUG_OUTPUT if (madSynthChannelCount != getChannelCount()) { qDebug() << "Reading MP3 data with different number of channels" << madSynthChannelCount << "<>" << getChannelCount(); } #endif if (kChannelCountMono == madSynthChannelCount) { // MP3 frame contains a mono signal if (readStereoSamples || (kChannelCountStereo == getChannelCount())) { // The reader explicitly requested a stereo signal // or the AudioSource itself provides a stereo signal. // Mono -> Stereo: Copy 1st channel twice for (SINT i = 0; i < synthReadCount; ++i) { const CSAMPLE sampleValue = madScaleSampleValue( m_madSynth.pcm.samples[0][madSynthOffset + i]); *pSampleBuffer++ = sampleValue; *pSampleBuffer++ = sampleValue; } } else { // Mono -> Mono: Copy 1st channel for (SINT i = 0; i < synthReadCount; ++i) { const CSAMPLE sampleValue = madScaleSampleValue( m_madSynth.pcm.samples[0][madSynthOffset + i]); *pSampleBuffer++ = sampleValue; } } } else { // MP3 frame contains a stereo signal DEBUG_ASSERT(kChannelCountStereo == madSynthChannelCount); // If the MP3 frame contains a stereo signal then the whole // AudioSource must also provide 2 channels, because the // maximum channel count of all MP3 frames is used. DEBUG_ASSERT(kChannelCountStereo == getChannelCount()); // Stereo -> Stereo: Copy 1st + 2nd channel for (SINT i = 0; i < synthReadCount; ++i) { *pSampleBuffer++ = madScaleSampleValue( m_madSynth.pcm.samples[0][madSynthOffset + i]); *pSampleBuffer++ = madScaleSampleValue( m_madSynth.pcm.samples[1][madSynthOffset + i]); } } } // consume decoded output data m_madSynthCount -= synthReadCount; m_curFrameIndex += synthReadCount; numberOfFramesRemaining -= synthReadCount; } DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(numberOfFramesTotal >= numberOfFramesRemaining); return numberOfFramesTotal - numberOfFramesRemaining; }
static void mad_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { mad_decoder_t *this = (mad_decoder_t *) this_gen; int bytes_in_buffer_at_pts; lprintf ("decode data, size: %d, decoder_flags: %d\n", buf->size, buf->decoder_flags); if (buf->size>(INPUT_BUF_SIZE-this->bytes_in_buffer)) { xprintf (this->xstream->xine, XINE_VERBOSITY_DEBUG, "libmad: ALERT input buffer too small (%d bytes, %d avail)!\n", buf->size, INPUT_BUF_SIZE-this->bytes_in_buffer); buf->size = INPUT_BUF_SIZE-this->bytes_in_buffer; } if ((buf->decoder_flags & BUF_FLAG_HEADER) == 0) { /* reset decoder on leaving preview mode */ if ((buf->decoder_flags & BUF_FLAG_PREVIEW) == 0) { if (this->preview_mode) { mad_reset (this_gen); } } else { this->preview_mode = 1; } bytes_in_buffer_at_pts = this->bytes_in_buffer; xine_fast_memcpy (&this->buffer[this->bytes_in_buffer], buf->content, buf->size); this->bytes_in_buffer += buf->size; /* printf ("libmad: decode data - doing it\n"); */ mad_stream_buffer (&this->stream, this->buffer, this->bytes_in_buffer); if (this->bytes_in_buffer < MAD_MIN_SIZE && buf->pts == 0) return; if (!this->needs_more_data) { this->pts = buf->pts; if (buf->decoder_flags & BUF_FLAG_AUDIO_PADDING) { this->start_padding = buf->decoder_info[1]; this->end_padding = buf->decoder_info[2]; } else { this->start_padding = 0; this->end_padding = 0; } } while (1) { if (mad_frame_decode (&this->frame, &this->stream) != 0) { if (this->stream.next_frame) { int num_bytes = this->buffer + this->bytes_in_buffer - this->stream.next_frame; /* printf("libmad: MAD_ERROR_BUFLEN\n"); */ memmove(this->buffer, this->stream.next_frame, num_bytes); this->bytes_in_buffer = num_bytes; } switch (this->stream.error) { case MAD_ERROR_BUFLEN: /* libmad wants more data */ this->needs_more_data = 1; return; default: lprintf ("error 0x%04X, mad_stream_buffer %d bytes\n", this->stream.error, this->bytes_in_buffer); mad_stream_buffer (&this->stream, this->buffer, this->bytes_in_buffer); } } else { int mode = (this->frame.header.mode == MAD_MODE_SINGLE_CHANNEL) ? AO_CAP_MODE_MONO : AO_CAP_MODE_STEREO; if (!this->output_open || (this->output_sampling_rate != this->frame.header.samplerate) || (this->output_mode != mode)) { lprintf ("audio sample rate %d mode %08x\n", this->frame.header.samplerate, mode); /* the mpeg audio demuxer can set audio bitrate */ if (! _x_stream_info_get(this->xstream, XINE_STREAM_INFO_AUDIO_BITRATE)) { _x_stream_info_set(this->xstream, XINE_STREAM_INFO_AUDIO_BITRATE, this->frame.header.bitrate); } /* the mpeg audio demuxer can set this meta info */ if (! _x_meta_info_get(this->xstream, XINE_META_INFO_AUDIOCODEC)) { switch (this->frame.header.layer) { case MAD_LAYER_I: _x_meta_info_set_utf8(this->xstream, XINE_META_INFO_AUDIOCODEC, "MPEG audio layer 1 (lib: MAD)"); break; case MAD_LAYER_II: _x_meta_info_set_utf8(this->xstream, XINE_META_INFO_AUDIOCODEC, "MPEG audio layer 2 (lib: MAD)"); break; case MAD_LAYER_III: _x_meta_info_set_utf8(this->xstream, XINE_META_INFO_AUDIOCODEC, "MPEG audio layer 3 (lib: MAD)"); break; default: _x_meta_info_set_utf8(this->xstream, XINE_META_INFO_AUDIOCODEC, "MPEG audio (lib: MAD)"); } } if (this->output_open) { this->xstream->audio_out->close (this->xstream->audio_out, this->xstream); this->output_open = 0; } if (!this->output_open) { this->output_open = (this->xstream->audio_out->open) (this->xstream->audio_out, this->xstream, 16, this->frame.header.samplerate, mode) ; } if (!this->output_open) { return; } this->output_sampling_rate = this->frame.header.samplerate; this->output_mode = mode; } mad_synth_frame (&this->synth, &this->frame); if ( (buf->decoder_flags & BUF_FLAG_PREVIEW) == 0 ) { unsigned int nchannels, nsamples; mad_fixed_t const *left_ch, *right_ch; struct mad_pcm *pcm = &this->synth.pcm; audio_buffer_t *audio_buffer; uint16_t *output; int bitrate; int pts_offset; audio_buffer = this->xstream->audio_out->get_buffer (this->xstream->audio_out); output = audio_buffer->mem; nchannels = pcm->channels; nsamples = pcm->length; left_ch = pcm->samples[0]; right_ch = pcm->samples[1]; /* padding */ if (this->start_padding || this->end_padding) { /* check padding validity */ if (nsamples < (this->start_padding + this->end_padding)) { lprintf("invalid padding data"); this->start_padding = 0; this->end_padding = 0; } lprintf("nsamples=%d, start_padding=%d, end_padding=%d\n", nsamples, this->start_padding, this->end_padding); nsamples -= this->start_padding + this->end_padding; left_ch += this->start_padding; right_ch += this->start_padding; } audio_buffer->num_frames = nsamples; audio_buffer->vpts = this->pts; while (nsamples--) { /* output sample(s) in 16-bit signed little-endian PCM */ *output++ = scale(*left_ch++); if (nchannels == 2) *output++ = scale(*right_ch++); } audio_buffer->num_frames = pcm->length; /* pts computing */ if (this->frame.header.bitrate > 0) { bitrate = this->frame.header.bitrate; } else { bitrate = _x_stream_info_get(this->xstream, XINE_STREAM_INFO_AUDIO_BITRATE); lprintf("offset %d bps\n", bitrate); } audio_buffer->vpts = buf->pts; if (audio_buffer->vpts && (bitrate > 0)) { pts_offset = (bytes_in_buffer_at_pts * 8 * 90) / (bitrate / 1000); lprintf("pts: %"PRId64", offset: %d pts, %d bytes\n", buf->pts, pts_offset, bytes_in_buffer_at_pts); if (audio_buffer->vpts < pts_offset) pts_offset = audio_buffer->vpts; audio_buffer->vpts -= pts_offset; } this->xstream->audio_out->put_buffer (this->xstream->audio_out, audio_buffer, this->xstream); this->pts = buf->pts; buf->pts = 0; if (buf->decoder_flags & BUF_FLAG_AUDIO_PADDING) { this->start_padding = buf->decoder_info[1]; this->end_padding = buf->decoder_info[2]; buf->decoder_info[1] = 0; buf->decoder_info[2] = 0; } else { this->start_padding = 0; this->end_padding = 0; } } lprintf ("decode worked\n"); } } } }
/* Reads the next frame from the file. Returns true on success or false on failure. */ static int read_next_frame(mad_data *mp3_mad) { if (mp3_mad->stream.buffer == NULL || mp3_mad->stream.error == MAD_ERROR_BUFLEN) { size_t read_size; size_t remaining; unsigned char *read_start; /* There might be some bytes in the buffer left over from last time. If so, move them down and read more bytes following them. */ if (mp3_mad->stream.next_frame != NULL) { remaining = mp3_mad->stream.bufend - mp3_mad->stream.next_frame; memmove(mp3_mad->input_buffer, mp3_mad->stream.next_frame, remaining); read_start = mp3_mad->input_buffer + remaining; read_size = MAD_INPUT_BUFFER_SIZE - remaining; } else { read_size = MAD_INPUT_BUFFER_SIZE; read_start = mp3_mad->input_buffer; remaining = 0; } /* Now read additional bytes from the input file. */ read_size = SDL_RWread(mp3_mad->src, read_start, 1, read_size); if (read_size <= 0) { if ((mp3_mad->status & (MS_input_eof | MS_input_error)) == 0) { if (read_size == 0) { mp3_mad->status |= MS_input_eof; } else { mp3_mad->status |= MS_input_error; } /* At the end of the file, we must stuff MAD_BUFFER_GUARD number of 0 bytes. */ SDL_memset(read_start + read_size, 0, MAD_BUFFER_GUARD); read_size += MAD_BUFFER_GUARD; } } /* Now feed those bytes into the libmad stream. */ mad_stream_buffer(&mp3_mad->stream, mp3_mad->input_buffer, read_size + remaining); mp3_mad->stream.error = MAD_ERROR_NONE; } /* Now ask libmad to extract a frame from the data we just put in its buffer. */ if (mad_frame_decode(&mp3_mad->frame, &mp3_mad->stream)) { if (MAD_RECOVERABLE(mp3_mad->stream.error)) { return 0; } else if (mp3_mad->stream.error == MAD_ERROR_BUFLEN) { return 0; } else { mp3_mad->status |= MS_decode_error; return 0; } } mp3_mad->frames_read++; mad_timer_add(&mp3_mad->next_frame_start, mp3_mad->frame.header.duration); return 1; }
/***************************************************************************** * DoWork: decode an MPEG audio frame. *****************************************************************************/ static void DoWork( filter_t * p_filter, aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf ) { filter_sys_t *p_sys = p_filter->p_sys; p_out_buf->i_nb_samples = p_in_buf->i_nb_samples; p_out_buf->i_buffer = p_in_buf->i_nb_samples * sizeof(vlc_fixed_t) * aout_FormatNbChannels( &p_filter->fmt_out.audio ); /* Do the actual decoding now. */ mad_stream_buffer( &p_sys->mad_stream, p_in_buf->p_buffer, p_in_buf->i_buffer ); if ( mad_frame_decode( &p_sys->mad_frame, &p_sys->mad_stream ) == -1 ) { msg_Dbg( p_filter, "libmad error: %s", mad_stream_errorstr( &p_sys->mad_stream ) ); p_sys->i_reject_count = 3; } else if( p_in_buf->i_flags & BLOCK_FLAG_DISCONTINUITY ) { p_sys->i_reject_count = 3; } if( p_sys->i_reject_count > 0 ) { if( p_filter->fmt_out.audio.i_format == VLC_CODEC_FL32 ) { int i; int i_size = p_out_buf->i_buffer / sizeof(float); float * a = (float *)p_out_buf->p_buffer; for ( i = 0 ; i < i_size ; i++ ) *a++ = 0.0; } else { memset( p_out_buf->p_buffer, 0, p_out_buf->i_buffer ); } p_sys->i_reject_count--; return; } mad_synth_frame( &p_sys->mad_synth, &p_sys->mad_frame ); struct mad_pcm * p_pcm = &p_sys->mad_synth.pcm; unsigned int i_samples = p_pcm->length; mad_fixed_t const * p_left = p_pcm->samples[0]; mad_fixed_t const * p_right = p_pcm->samples[1]; assert( i_samples == p_out_buf->i_nb_samples ); if ( p_filter->fmt_out.audio.i_format == VLC_CODEC_FI32 ) { /* Interleave and keep buffers in mad_fixed_t format */ mad_fixed_t * p_samples = (mad_fixed_t *)p_out_buf->p_buffer; if ( p_pcm->channels == 2 ) { while ( i_samples-- ) { *p_samples++ = *p_left++; *p_samples++ = *p_right++; } } else { assert( p_pcm->channels == 1 ); vlc_memcpy( p_samples, p_left, i_samples * sizeof(mad_fixed_t) ); } } else { /* float32 */ float * p_samples = (float *)p_out_buf->p_buffer; const float f_temp = (float)FIXED32_ONE; if ( p_pcm->channels == 2 ) { while ( i_samples-- ) { *p_samples++ = (float)*p_left++ / f_temp; *p_samples++ = (float)*p_right++ / f_temp; } } else { assert( p_pcm->channels == 1 ); while ( i_samples-- ) { *p_samples++ = (float)*p_left++ / f_temp; } } } }
void XMp3Decomp::Decompress(XS16* dstWord, XS32 nSamples) { long bytesCleared; XS32 nBytes = nSamples * snd->BytesPerBlock(); XS8 *dstByte = (XS8 *) dstWord; // XBOOL seeking = (!dstWord) ? (true) : false; bytesCleared = GetBufferedData(dstByte, nBytes); if (!isInitMad()) { if (dstByte) { memset(dstByte, 0x00, nBytes); } goto exit_gracefully; } else { nBytes -= bytesCleared; // dst byte can be zero during seeking if (dstByte) dstByte += bytesCleared; } if (m_firstBuf) // first enter { // read head. and give data bool b = fillBufferMad(); assert(b); m_firstBuf = false; } // check first if there is any buffered data if (bytesCleared == nBytes) goto exit_gracefully; mad_error madError; while(nBytes > 0) { int success = mad_frame_decode(&Frame, &Stream); madError = Stream.error; if (success == 0) { // do success things. mad_synth_frame(&Synth,&Frame); struct mad_pcm *pcm = &(Synth.pcm); int nchannels = pcm->channels; // int nsamples = pcm->length; assert(Synth.pcm.length * nchannels * 2 <= kBufSize); assert(Synth.pcm.length > 0); XU8* p = pcmBuf; for (int i = 0; i < Synth.pcm.length; i++) { signed int Sample = scale(Synth.pcm.samples[0][i]); *p++ = Sample & 0xff; *p++ = (Sample >> 8) & 0xff; if (nchannels == 2) { Sample = scale(Synth.pcm.samples[0][i]); *p++ = Sample & 0xff; *p++ = (Sample >> 8) & 0xff; } } bufLength = Synth.pcm.length * nchannels * 2; bytesCleared = GetBufferedData(dstByte, nBytes); nBytes -= bytesCleared; if (dstByte) { dstByte += bytesCleared; } }
static int run_sync(struct mad_decoder *decoder) { enum mad_flow (*error_func)(void *, struct mad_stream *, struct mad_frame *); void *error_data; int bad_last_frame = 0; struct mad_stream *stream; struct mad_frame *frame; struct mad_synth *synth; int result = 0; if (decoder->input_func == 0) return 0; if (decoder->error_func) { error_func = decoder->error_func; error_data = decoder->cb_data; } else { error_func = error_default; error_data = &bad_last_frame; } stream = &decoder->sync->stream; frame = &decoder->sync->frame; synth = &decoder->sync->synth; mad_stream_init(stream); mad_frame_init(frame); mad_synth_init(synth); mad_stream_options(stream, decoder->options); do { switch (decoder->input_func(decoder->cb_data, stream)) { case MAD_FLOW_STOP: goto done; case MAD_FLOW_BREAK: goto fail; case MAD_FLOW_IGNORE: continue; case MAD_FLOW_CONTINUE: break; } while (1) { if (decoder->header_func) { if (mad_header_decode(&frame->header, stream) == -1) { if (!MAD_RECOVERABLE(stream->error)) break; switch (error_func(error_data, stream, frame)) { case MAD_FLOW_STOP: goto done; case MAD_FLOW_BREAK: goto fail; case MAD_FLOW_IGNORE: case MAD_FLOW_CONTINUE: default: continue; } } switch (decoder->header_func(decoder->cb_data, &frame->header)) { case MAD_FLOW_STOP: goto done; case MAD_FLOW_BREAK: goto fail; case MAD_FLOW_IGNORE: continue; case MAD_FLOW_CONTINUE: break; } } if (mad_frame_decode(frame, stream) == -1) { if (!MAD_RECOVERABLE(stream->error)) break; switch (error_func(error_data, stream, frame)) { case MAD_FLOW_STOP: goto done; case MAD_FLOW_BREAK: goto fail; case MAD_FLOW_IGNORE: break; case MAD_FLOW_CONTINUE: default: continue; } } else bad_last_frame = 0; if (decoder->filter_func) { switch (decoder->filter_func(decoder->cb_data, stream, frame)) { case MAD_FLOW_STOP: goto done; case MAD_FLOW_BREAK: goto fail; case MAD_FLOW_IGNORE: continue; case MAD_FLOW_CONTINUE: break; } } mad_synth_frame(synth, frame); if (decoder->output_func) { switch (decoder->output_func(decoder->cb_data, &frame->header, &synth->pcm)) { case MAD_FLOW_STOP: goto done; case MAD_FLOW_BREAK: goto fail; case MAD_FLOW_IGNORE: case MAD_FLOW_CONTINUE: break; } } } } while (stream->error == MAD_ERROR_BUFLEN); fail: result = -1; done: mad_synth_finish(synth); mad_frame_finish(frame); mad_stream_finish(stream); return result; }
static gboolean xmms_mad_init (xmms_xform_t *xform) { struct mad_frame frame; struct mad_stream stream; xmms_error_t err; guchar buf[40960]; xmms_mad_data_t *data; int len; const gchar *metakey; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_mad_data_t, 1); mad_stream_init (&data->stream); mad_frame_init (&data->frame); mad_synth_init (&data->synth); xmms_xform_private_data_set (xform, data); data->buffer_length = 0; data->synthpos = 0x7fffffff; mad_stream_init (&stream); mad_frame_init (&frame); len = xmms_xform_peek (xform, buf, 40960, &err); mad_stream_buffer (&stream, buf, len); while (mad_frame_decode (&frame, &stream) == -1) { if (!MAD_RECOVERABLE (stream.error)) { XMMS_DBG ("couldn't decode %02x %02x %02x %02x",buf[0],buf[1],buf[2],buf[3]); mad_frame_finish (&frame); mad_stream_finish (&stream); return FALSE; } } data->channels = frame.header.mode == MAD_MODE_SINGLE_CHANNEL ? 1 : 2; data->samplerate = frame.header.samplerate; if (frame.header.flags & MAD_FLAG_PROTECTION) { XMMS_DBG ("Frame has protection enabled"); if (stream.anc_ptr.byte > stream.buffer + 2) { stream.anc_ptr.byte = stream.anc_ptr.byte - 2; } } data->samples_to_play = -1; data->xing = xmms_xing_parse (stream.anc_ptr); if (data->xing) { xmms_xing_lame_t *lame; XMMS_DBG ("File with Xing header!"); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_IS_VBR; xmms_xform_metadata_set_int (xform, metakey, 1); if (xmms_xing_has_flag (data->xing, XMMS_XING_FRAMES)) { guint duration; mad_timer_t timer; timer = frame.header.duration; mad_timer_multiply (&timer, xmms_xing_get_frames (data->xing)); duration = mad_timer_count (timer, MAD_UNITS_MILLISECONDS); XMMS_DBG ("XING duration %d", duration); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION; xmms_xform_metadata_set_int (xform, metakey, duration); if (xmms_xing_has_flag (data->xing, XMMS_XING_BYTES) && duration) { guint tmp; tmp = xmms_xing_get_bytes (data->xing) * ((guint64)8000) / duration; XMMS_DBG ("XING bitrate %d", tmp); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_BITRATE; xmms_xform_metadata_set_int (xform, metakey, tmp); } } lame = xmms_xing_get_lame (data->xing); if (lame) { /* FIXME: add a check for ignore_lame_headers from the medialib */ data->frames_to_skip = 1; data->samples_to_skip = lame->start_delay; data->samples_to_play = ((guint64) xmms_xing_get_frames (data->xing) * 1152ULL) - lame->start_delay - lame->end_padding; XMMS_DBG ("Samples to skip in the beginning: %d, total: %" G_GINT64_FORMAT, data->samples_to_skip, data->samples_to_play); /* metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_GAIN_ALBUM; xmms_xform_metadata_set_int (xform, metakey, lame->audiophile_gain); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_PEAK_TRACK; xmms_xform_metadata_set_int (xform, metakey, lame->peak_amplitude); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_GAIN_TRACK; xmms_xform_metadata_set_int (xform, metakey, lame->radio_gain); */ } } else { gint filesize; metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_BITRATE; xmms_xform_metadata_set_int (xform, metakey, frame.header.bitrate); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION; if (!xmms_xform_metadata_get_int (xform, metakey, &filesize)) { metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_SIZE; if (xmms_xform_metadata_get_int (xform, metakey, &filesize)) { gint32 val; val = (gint32) (filesize * (gdouble) 8000.0 / frame.header.bitrate); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION; xmms_xform_metadata_set_int (xform, metakey, val); } } } /* seeking needs bitrate */ data->bitrate = frame.header.bitrate; if (xmms_id3v1_get_tags (xform) < 0) { mad_stream_finish (&data->stream); mad_frame_finish (&data->frame); mad_synth_finish (&data->synth); if (data->xing) { xmms_xing_free (data->xing); } return FALSE; } xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, XMMS_SAMPLE_FORMAT_S16, XMMS_STREAM_TYPE_FMT_CHANNELS, data->channels, XMMS_STREAM_TYPE_FMT_SAMPLERATE, data->samplerate, XMMS_STREAM_TYPE_END); mad_frame_finish (&frame); mad_stream_finish (&stream); return TRUE; }
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; }
void LibMadWrapper::render(pcm_t *const bufferToFill, const uint32_t Channels, frame_t framesToRender) { framesToRender = min(framesToRender, this->getFrames() - this->framesAlreadyRendered); int32_t *pcm = static_cast<int32_t *>(bufferToFill); // the outer loop, used for decoding and synthesizing MPEG frames while (framesToRender > 0 && !this->stopFillBuffer) { // write back tempbuffer, i.e. frames weve buffered from previous calls to libmad (necessary due to inelegant API of libmad, i.e. cant tell how many frames to render during one call) { const size_t itemsToCpy = min<size_t>(this->tempBuf.size(), framesToRender * Channels); memcpy(pcm, this->tempBuf.data(), itemsToCpy * sizeof(int32_t)); this->tempBuf.erase(this->tempBuf.begin(), this->tempBuf.begin() + itemsToCpy); const size_t framesCpyd = itemsToCpy / Channels; framesToRender -= framesCpyd; this->framesAlreadyRendered += framesCpyd; // again: adjust position pcm += itemsToCpy; } int framesToDoNow = (framesToRender / gConfig.FramesToRender) > 0 ? gConfig.FramesToRender : framesToRender % gConfig.FramesToRender; if (framesToDoNow == 0) { continue; } int ret = mad_frame_decode(&this->frame.Value, this->stream); if (ret != 0) { if (this->stream->error == MAD_ERROR_LOSTSYNC) { long tagsize = id3_tag_query(this->stream->this_frame, this->stream->bufend - this->stream->this_frame); if (tagsize > 0) { mad_stream_skip(this->stream, tagsize); continue; } } string errstr = mad_stream_errorstr(this->stream); if (MAD_RECOVERABLE(this->stream->error)) { errstr += " (recoverable)"; CLOG(LogLevel_t::Info, errstr); continue; } else { errstr += " (not recoverable)"; CLOG(LogLevel_t::Warning, errstr); break; } } mad_synth_frame(&this->synth.Value, &this->frame.Value); /* save PCM samples from synth.pcm */ /* &synth.pcm->samplerate contains the sampling frequency */ unsigned short nsamples = this->synth->pcm.length; mad_fixed_t const *left_ch = this->synth->pcm.samples[0]; mad_fixed_t const *right_ch = this->synth->pcm.samples[1]; unsigned int item = 0; /* audio normalization */ const float absoluteGain = (numeric_limits<int32_t>::max()) / (numeric_limits<int32_t>::max() * this->gainCorrection); for (; !this->stopFillBuffer && framesToDoNow > 0 && // frames left during this loop framesToRender > 0 && // frames left during this call nsamples > 0; // frames left from libmad framesToRender--, nsamples--, framesToDoNow--) { int32_t sample; /* output sample(s) in 24-bit signed little-endian PCM */ sample = LibMadWrapper::toInt24Sample(*left_ch++); sample = gConfig.useAudioNormalization ? floor(sample * absoluteGain) : sample; pcm[item++] = sample; if (Channels == 2) // our buffer is for 2 channels { if (this->synth.Value.pcm.channels == 2) // ...but did mad also decoded for 2 channels? { sample = LibMadWrapper::toInt24Sample(*right_ch++); sample = gConfig.useAudioNormalization ? floor(sample * absoluteGain) : sample; pcm[item++] = sample; } else { // what? only one channel in a stereo file? well then: pseudo stereo pcm[item++] = sample; CLOG(LogLevel_t::Warning, "decoded only one channel, though this is a stereo file!"); } } this->framesAlreadyRendered++; } pcm += item /* % this->count*/; // "bufferToFill" (i.e. "pcm") seems to be full, drain the rest pcm samples from libmad and temporarily save them while (!this->stopFillBuffer && nsamples > 0) { int32_t sample; /* output sample(s) in 24-bit signed little-endian PCM */ sample = LibMadWrapper::toInt24Sample(*left_ch++); this->tempBuf.push_back(gConfig.useAudioNormalization ? floor(sample * absoluteGain) : sample); if (Channels == 2) { sample = LibMadWrapper::toInt24Sample(*right_ch++); this->tempBuf.push_back(gConfig.useAudioNormalization ? floor(sample * absoluteGain) : sample); } /* DONT do this: this->framesAlreadyRendered++; since we use framesAlreadyRendered as offset for "bufferToFill"*/ nsamples--; } if (item > this->count) { CLOG(LogLevel_t::Error, "THIS SHOULD NEVER HAPPEN: read " << item << " items but only expected " << this->count << "\n"); break; } } }
/* mp3 playback callback */ static WaitressCbReturn_t BarPlayerMp3Cb (void *ptr, size_t size, void *stream) { const char *data = ptr; struct audioPlayer *player = stream; size_t i; QUIT_PAUSE_CHECK; if (!BarPlayerBufferFill (player, data, size)) { return WAITRESS_CB_RET_ERR; } /* some "prebuffering" */ if (player->mode < PLAYER_RECV_DATA && player->bufferFilled < BAR_PLAYER_BUFSIZE / 2) { return WAITRESS_CB_RET_OK; } mad_stream_buffer (&player->mp3Stream, player->buffer, player->bufferFilled); player->mp3Stream.error = 0; do { /* channels * max samples, found in mad.h */ signed short int madDecoded[2*1152], *madPtr = madDecoded; if (mad_frame_decode (&player->mp3Frame, &player->mp3Stream) != 0) { if (player->mp3Stream.error != MAD_ERROR_BUFLEN) { BarUiMsg (player->settings, MSG_ERR, "mp3 decoding error: %s\n", mad_stream_errorstr (&player->mp3Stream)); return WAITRESS_CB_RET_ERR; } else { /* rebuffering required => exit loop */ break; } } mad_synth_frame (&player->mp3Synth, &player->mp3Frame); for (i = 0; i < player->mp3Synth.pcm.length; i++) { /* left channel */ *(madPtr++) = applyReplayGain (BarPlayerMadToShort ( player->mp3Synth.pcm.samples[0][i]), player->scale); /* right channel */ *(madPtr++) = applyReplayGain (BarPlayerMadToShort ( player->mp3Synth.pcm.samples[1][i]), player->scale); } if (player->mode < PLAYER_AUDIO_INITIALIZED) { ao_sample_format format; int audioOutDriver; player->channels = player->mp3Synth.pcm.channels; player->samplerate = player->mp3Synth.pcm.samplerate; audioOutDriver = ao_default_driver_id(); memset (&format, 0, sizeof (format)); format.bits = 16; format.channels = player->channels; format.rate = player->samplerate; format.byte_format = AO_FMT_NATIVE; if ((player->audioOutDevice = ao_open_live (audioOutDriver, &format, NULL)) == NULL) { player->aoError = 1; BarUiMsg (player->settings, MSG_ERR, "Cannot open audio device\n"); return WAITRESS_CB_RET_ERR; } /* calc song length using the framerate of the first decoded frame */ player->songDuration = (unsigned long long int) player->waith.request.contentLength / ((unsigned long long int) player->mp3Frame.header.bitrate / (unsigned long long int) BAR_PLAYER_MS_TO_S_FACTOR / 8LL); /* must be > PLAYER_SAMPLESIZE_INITIALIZED, otherwise time won't * be visible to user (ugly, but mp3 decoding != aac decoding) */ player->mode = PLAYER_RECV_DATA; } /* samples * length * channels */ ao_play (player->audioOutDevice, (char *) madDecoded, player->mp3Synth.pcm.length * 2 * 2); /* avoid division by 0 */ if (player->mode == PLAYER_RECV_DATA) { /* same calculation as in aac player; don't need to divide by * channels, length is number of samples for _one_ channel */ player->songPlayed += (unsigned long long int) player->mp3Synth.pcm.length * (unsigned long long int) BAR_PLAYER_MS_TO_S_FACTOR / (unsigned long long int) player->samplerate; } QUIT_PAUSE_CHECK; } while (player->mp3Stream.error != MAD_ERROR_BUFLEN); player->bufferRead += player->mp3Stream.next_frame - player->buffer; BarPlayerBufferMove (player); return WAITRESS_CB_RET_OK; }
/** * 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; }
static gavl_source_status_t decode_frame_mad(bgav_stream_t * s) { mad_priv_t * priv; int i, j; gavl_source_status_t st; int got_frame; int flush = 0; priv = s->decoder_priv; if(priv->eof) return GAVL_SOURCE_EOF; while(1) { st = get_data(s); switch(st) { case GAVL_SOURCE_AGAIN: return st; break; case GAVL_SOURCE_EOF: flush = 1; break; case GAVL_SOURCE_OK: break; } got_frame = 1; mad_stream_buffer(&priv->stream, priv->buf.buffer, priv->buf.size + flush * MAD_BUFFER_GUARD); if(priv->do_init) { get_format(s); priv->do_init = 0; } if(mad_frame_decode(&priv->frame, &priv->stream) == -1) { got_frame = 0; if(priv->stream.error != MAD_ERROR_BUFLEN) { /* This is often a spurious error, which ALWAYS occurs for ripped radio stations */ if(priv->stream.error != MAD_ERROR_BADDATAPTR) bgav_log(s->opt, BGAV_LOG_ERROR, LOG_DOMAIN, "Decode failed %s\n", mad_stream_errorstr(&priv->stream)); break; } } else break; if(!got_frame && flush) return GAVL_SOURCE_EOF; } if(got_frame) { // fprintf(stderr, "Decodes %ld bytes\n", priv->stream.next_frame - priv->stream.buffer); mad_synth_frame(&priv->synth, &priv->frame); for(i = 0; i < s->data.audio.format.num_channels; i++) { for(j = 0; j < s->data.audio.format.samples_per_frame; j++) { if (priv->synth.pcm.samples[i][j] >= MAD_F_ONE) priv->synth.pcm.samples[i][j] = MAD_F_ONE - 1; else if (priv->synth.pcm.samples[i][j] < -MAD_F_ONE) priv->synth.pcm.samples[i][j] = -MAD_F_ONE; priv->audio_frame->channels.f[i][j] = (float)(priv->synth.pcm.samples[i][j]) / (float)MAD_F_ONE; } } priv->audio_frame->valid_samples = s->data.audio.format.samples_per_frame; } else gavl_audio_frame_mute(priv->audio_frame, &s->data.audio.format); if(flush && priv->last_duration && (priv->last_duration < priv->audio_frame->valid_samples)) priv->audio_frame->valid_samples = priv->last_duration; gavl_audio_frame_copy_ptrs(&s->data.audio.format, s->data.audio.frame, priv->audio_frame); #if 0 fprintf(stderr, "Done decode %ld %ld\n", priv->stream.this_frame - priv->stream.buffer, priv->stream.next_frame - priv->stream.this_frame); #endif s->flags |= STREAM_HAVE_FRAME; bgav_bytebuffer_remove(&priv->buf, priv->stream.next_frame - priv->stream.buffer); if(flush) priv->eof = 1; return GAVL_SOURCE_OK; }