int MP3Decoder::mp3_decode(unsigned char const *inData, unsigned long inDataLength, unsigned char *outData, unsigned long *outDataLength) { int result = -1; unsigned long curOutDataIndex = 0; // 当前已输出数据的index unsigned long curInDataRemaining = inDataLength;// 当前输入数据剩余数据量 if (_isClearPreDeocodeBuffer) { Stream.next_frame = NULL; _isClearPreDeocodeBuffer = false; } /* 开始解码 */ do { /* 如果缓冲区空了或不足一帧数据, 就向缓冲区填充数据 */ if (Stream.buffer == NULL || Stream.error == MAD_ERROR_BUFLEN) { size_t BufferSize; /* 缓冲区大小 */ size_t Remaining; /* 帧剩余数据 */ unsigned char *BufferStart; /* 头指针 */ if (Stream.next_frame != NULL) // 还有上一帧的缓存 { /* 把剩余没解码完的数据补充到这次的缓冲区中 */ Remaining = Stream.bufend - Stream.next_frame; memmove(Mp3_InputBuffer, Stream.next_frame, Remaining); BufferStart = Mp3_InputBuffer + Remaining; BufferSize = INPUT_BUFFER_SIZE - Remaining; } else // 没有上一帧的缓存 { /* 设置了缓冲区地址, 但还没有填充数据 */ BufferSize = INPUT_BUFFER_SIZE; BufferStart = Mp3_InputBuffer; Remaining = 0; } /* 从输入数据中读取数据并填充缓冲区 */ if (curInDataRemaining == 0) { BufferSize = 0; // 没有数据可读取 } else { if (curInDataRemaining >= BufferSize) // 剩余的数据量满足准备读取的数据量 { memcpy(BufferStart, inData + (inDataLength - curInDataRemaining), BufferSize); curInDataRemaining -= BufferSize; } else // 剩余的数据量不足,全部取 出来 { memcpy(BufferStart, inData + (inDataLength - curInDataRemaining), curInDataRemaining); BufferSize = curInDataRemaining; curInDataRemaining = 0; } } if (BufferSize <= 0) // 未读取到数据,直接返回 { /*printf("文件读取失败\n"); exit(-1);*/ result = 0; break; } mad_stream_buffer(&Stream, Mp3_InputBuffer, BufferSize + Remaining); Stream.error = MAD_ERROR_NONE; } if (mad_frame_decode(&Frame, &Stream)) { // 解码出错 if (MAD_RECOVERABLE(Stream.error)) { // 可恢复的错误,继续执行 continue; } else { if (Stream.error == MAD_ERROR_BUFLEN) { continue; /* buffer解码光了, 需要继续填充 */ } else if (Stream.error == MAD_ERROR_LOSTSYNC) { // 丢失同步,这里可以不处理,因此该错误属于可恢复的错误 int tagsize = 0; //tagsize = id3_tag_query(Stream.this_frame, Stream.bufend - Stream.this_frame); if (tagsize > 0) { mad_stream_skip(&Stream, tagsize); } continue; } else { // 严重错误,无法继续解码 result = -1; break; } } } /* 设置每帧的播放时间 */ //mad_timer_add(&Timer, Frame.header.duration); /* 解码成音频数据 */ mad_synth_frame(&Synth, &Frame); struct mad_pcm *pcm = &Synth.pcm; unsigned int nchannels, nsamples; mad_fixed_t const *left_ch, *right_ch; /* pcm->samplerate contains the sampling frequency */ nchannels = pcm->channels; nsamples = pcm->length; left_ch = pcm->samples[0]; right_ch = pcm->samples[1]; int curDataLen = pcm->length * pcm->channels * sizeof(short); short *buf = (short *) malloc(curDataLen); // 将解码后的数据进行填充 int i = 0; while (nsamples--) { signed int sample; // output sample(s) in 16-bit signed little-endian PCM sample = scale(*left_ch++); buf[i++] = sample & 0xFFFF; if (nchannels == 2) { sample = scale(*right_ch++); buf[i++] = sample & 0xFFFF; } } memcpy(outData + curOutDataIndex, buf, curDataLen); curOutDataIndex += curDataLen; *outDataLength = curOutDataIndex; free(buf); } while (1); return result; }
bool K3bMadDecoder::seekInternal( const K3b::Msf& pos ) { // // we need to reset the complete mad stuff // if( !initDecoderInternal() ) return false; // // search a position // This is all hacking, I don't really know what I am doing here... ;) // double mp3FrameSecs = static_cast<double>(d->firstHeader.duration.seconds) + static_cast<double>(d->firstHeader.duration.fraction) / static_cast<double>(MAD_TIMER_RESOLUTION); double posSecs = static_cast<double>(pos.totalFrames()) / 75.0; // seekPosition to seek after frame i unsigned int frame = static_cast<unsigned int>( posSecs / mp3FrameSecs ); // Rob said: 29 frames is the theoretically max frame reservoir limit (whatever that means...) // it seems that mad needs at most 29 frames to get ready unsigned int frameReservoirProtect = ( frame > 29 ? 29 : frame ); frame -= frameReservoirProtect; // seek in the input file behind the already decoded data d->handle->inputSeek( d->seekPositions[frame] ); qDebug() << "(K3bMadDecoder) Seeking to frame " << frame << " with " << frameReservoirProtect << " reservoir frames." << endl; // decode some frames ignoring MAD_ERROR_BADDATAPTR errors unsigned int i = 1; while( i <= frameReservoirProtect ) { d->handle->fillStreamBuffer(); if( mad_frame_decode( d->handle->madFrame, d->handle->madStream ) ) { if( MAD_RECOVERABLE( d->handle->madStream->error ) ) { if( d->handle->madStream->error == MAD_ERROR_BUFLEN ) continue; else if( d->handle->madStream->error != MAD_ERROR_BADDATAPTR ) { qDebug() << "(K3bMadDecoder) Seeking: recoverable mad error (" << mad_stream_errorstr(d->handle->madStream) << ")" << endl; continue; } else { qDebug() << "(K3bMadDecoder) Seeking: ignoring (" << mad_stream_errorstr(d->handle->madStream) << ")" << endl; } } else return false; } if( i == frameReservoirProtect ) // synth only the last frame (Rob said so ;) mad_synth_frame( d->handle->madSynth, d->handle->madFrame ); ++i; } return true; }
int Mp3Decoder::Read(u8 * buffer, int buffer_size, int) { 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; } }
/***************************************************************************** * 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 ) { 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; } } } }
/* 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; }
static void MP3Update(void) { int flip; UINT8 *GuardPtr; INT16 *OutputPtr, *OutputEnd; struct mad_stream Stream; struct mad_frame Frame; struct mad_synth Synth; mad_timer_t Timer; mad_stream_init(&Stream); mad_frame_init(&Frame); mad_synth_init(&Synth); mad_timer_reset(&Timer); OutputPtr = (INT16 *)mp3_out[0]; OutputEnd = (INT16 *)(mp3_out[0] + MP3_BUFFER_SIZE); GuardPtr = NULL; mp3_filepos = 0; mp3_frame = 0; flip = 0; cdda_command_ack = 1; while (mp3_active && mp3_status != MP3_STOP) { if (Stream.buffer == NULL || Stream.error == MAD_ERROR_BUFLEN) { UINT32 ReadSize, Remaining; UINT8 *ReadStart; if (Stream.next_frame != NULL) { Remaining = Stream.bufend - Stream.next_frame; ReadStart = mp3_in + Remaining; ReadSize = (2 * MP3_BUFFER_SIZE) - Remaining; memmove(mp3_in, Stream.next_frame, Remaining); } else { ReadSize = 2 * MP3_BUFFER_SIZE; ReadStart = mp3_in; Remaining = 0; } if (MP3SleepCheck()) break; ReadSize = sceIoRead(mp3_fd, ReadStart, ReadSize); mp3_filepos += ReadSize; if (mp3_filepos == mp3_fsize) { if (cdda_autoloop) { mp3_filepos = 0; sceIoLseek(mp3_fd, 0, PSP_SEEK_SET); } else { cdda_playing = CDDA_STOP; mp3_status = MP3_STOP; } } if (mp3_filepos == mp3_fsize) { GuardPtr = ReadStart + ReadSize; memset(GuardPtr, 0, MAD_BUFFER_GUARD); ReadSize += MAD_BUFFER_GUARD; } mad_stream_buffer(&Stream, mp3_in, ReadSize + Remaining); Stream.error = 0; } if (mad_frame_decode(&Frame, &Stream)) { if (MAD_RECOVERABLE(Stream.error)) { // if (Stream.error != MAD_ERROR_LOSTSYNC || Stream.this_frame != GuardPtr) continue; } else if (Stream.error == MAD_ERROR_BUFLEN) { continue; } else { ui_popup(TEXT(MP3_DECODE_ERROR)); mp3_status = MP3_STOP; break; } } mp3_frame++; mad_timer_add(&Timer, Frame.header.duration); mad_synth_frame(&Synth, &Frame); if (mp3_status == MP3_PLAY) { int i; for (i = 0; i < Synth.pcm.length; i++) { if (MAD_NCHANNELS(&Frame.header) == 2) { *OutputPtr++ = MP3Limit(Synth.pcm.samples[0][i]); *OutputPtr++ = MP3Limit(Synth.pcm.samples[1][i]); } else { INT16 data = MP3Limit(Synth.pcm.samples[0][i]); *OutputPtr++ = data; *OutputPtr++ = data; } if (OutputPtr == OutputEnd) { sceAudioOutputPannedBlocking(mp3_handle, mp3_volume, mp3_volume, mp3_out[flip]); flip ^= 1; OutputPtr = (INT16 *)mp3_out[flip]; OutputEnd = (INT16 *)(mp3_out[flip] + MP3_BUFFER_SIZE); } } } else if (mp3_status == MP3_SEEK) { if (mp3_frame >= mp3_start_frame) { mp3_start_frame = 0; mp3_status = MP3_SLEEP; sceKernelSleepThread(); } } } mad_synth_finish(&Synth); mad_frame_finish(&Frame); mad_stream_finish(&Stream); if (mp3_fd >= 0) { sceIoClose(mp3_fd); mp3_fd = -1; } }
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; }
unsigned int mpgDecoder::decode( float *** data, int count ) { #ifdef HAVE_MAD if(data) *data=returnBuffer; while( mad_outputBuffer[0].canWrite(1152) ) // well letts refill the Input buffer.......... { if( madStream->buffer == NULL || madStream->error == MAD_ERROR_BUFLEN) // well letts refill the Input buffer.......... { size_t readSize, remaining; unsigned char* readStart; unsigned char* guardPtr; if( madFile->atEnd() ) return(0); if(madStream->next_frame) // move remaining bytes to start wich has not been decoded yet... { remaining = mad_inputBuffer + 163840 - madStream->next_frame; memmove( mad_inputBuffer, madStream->next_frame, remaining ); readStart = mad_inputBuffer + remaining; readSize = 163840 - remaining; } else { readSize = 163840; readStart = mad_inputBuffer; remaining = 0; } // get some more Byte from File... unsigned int readCnt = 0; while( !madFile->atEnd() && readCnt < readSize) { readStart[readCnt] = madFile->read(1).at(0); readCnt++; } //bei EOF ein paar GUARD 0Bytes anhaengen die MAD benötigt.. if( madFile->atEnd() ) { guardPtr = readStart + readCnt; memset( guardPtr, 0, MAD_BUFFER_GUARD); readCnt += MAD_BUFFER_GUARD; } mad_stream_buffer( madStream, mad_inputBuffer, readCnt+remaining); madStream->error = MAD_ERROR_NONE; } // well lets decode the buffer and get some Music out of it :-) mad_frame_decode( madFrame, madStream ); frameCounter++; // first MPeg Frame isnt Played cause it contains noisy Metadata if we Play it :D // frame is also not played if we could not decode the whole MPeg frame in case of end of input buffer if(madStream->error==MAD_ERROR_BUFLEN || frameCounter ==1) continue; mad_timer_add( currentPositionTimer, madFrame->header.duration ); mad_synth_frame( madSynth, madFrame ); // decoding done.. convert sampletype... for( unsigned int j=0; j<channels; j++ ) for(unsigned int i=0; i<madSynth->pcm.length; i++ ) { float temp = scale( madSynth->pcm.samples[j][i]); mad_outputBuffer[j].write( &temp, 1 ); } } //nice little workarround so the buffer never gets so much back it wants to.... int dataAvailable = mad_outputBuffer[0].canRead(count*.95)?count*.95:mad_outputBuffer[0].getAvailable()-8; // ensure the return buffer is clean... memset(returnBuffer[0], 0, 8192*sizeof(float)); memset(returnBuffer[1], 0, 8192*sizeof(float)); for( unsigned int j=0; j<channels; j++ ) mad_outputBuffer[j].read( returnBuffer[j], dataAvailable ); return dataAvailable; #endif }
int MAD_WRAPPER_playAudio( void *userdata, Uint8 *stream, int len ) { MAD_WRAPPER *mad = (MAD_WRAPPER*)userdata; if ( !mad->is_playing ) return -1; // pause size_t ReadSize = 1, Remaining; unsigned char *ReadStart; do{ if( mad->Stream.buffer==NULL || mad->Stream.error==MAD_ERROR_BUFLEN ){ if ( mad->Stream.next_frame != NULL ){ Remaining = mad->Stream.bufend - mad->Stream.next_frame; memmove( mad->input_buf, mad->Stream.next_frame, Remaining); ReadStart = mad->input_buf + Remaining; ReadSize = INPUT_BUFFER_SIZE - Remaining; } else{ ReadSize = INPUT_BUFFER_SIZE; ReadStart = mad->input_buf; Remaining = 0; } ReadSize = SDL_RWread( mad->src, ReadStart, 1, ReadSize ); if ( ReadSize <= 0 ) break; // end of stream mad_stream_buffer( &mad->Stream, mad->input_buf, ReadSize + Remaining ); mad->Stream.error = MAD_ERROR_NONE; } if ( mad_frame_decode( &mad->Frame,&mad->Stream ) ){ if ( MAD_RECOVERABLE( mad->Stream.error ) || mad->Stream.error == MAD_ERROR_BUFLEN ){ continue; } else{ fprintf( stderr, "unrecoverable frame level error (%s).\n", mad_stream_errorstr(&mad->Stream) ); return 0; // error } } #if defined(PDA) && !defined(PSP) && !defined(IPHONE) if ( mad->Frame.header.samplerate == 44100 ) mad->Frame.options |= MAD_OPTION_HALFSAMPLERATE; #endif mad_synth_frame( &mad->Synth, &mad->Frame ); char *ptr = (char*)mad->output_buf + mad->output_buf_index; for ( int i=0 ; i<mad->Synth.pcm.length ; i++ ){ unsigned short Sample; /* Left channel */ Sample=MadFixedToUshort( mad->Synth.pcm.samples[0][i] ); #if SDL_BYTEORDER == SDL_LIL_ENDIAN *(ptr++) = Sample & 0xff; *(ptr++) = Sample >> 8; #else *(ptr++) = Sample >> 8; *(ptr++) = Sample & 0xff; #endif /* Right channel, if exist. */ if ( MAD_NCHANNELS(&mad->Frame.header)==2 ) Sample=MadFixedToUshort( mad->Synth.pcm.samples[1][i] ); #if SDL_BYTEORDER == SDL_LIL_ENDIAN *(ptr++) = Sample & 0xff; *(ptr++) = Sample >> 8; #else *(ptr++) = Sample >> 8; *(ptr++) = Sample&0xff; #endif } mad->output_buf_index += mad->Synth.pcm.length * 4; } while( mad->output_buf_index < len ); if ( ReadSize <= 0 ) return 0; // end of stream if ( mad->output_buf_index > len ){ SDL_MixAudio( stream, mad->output_buf, len, mad->volume ); memmove( mad->output_buf, mad->output_buf + len, mad->output_buf_index - len ); mad->output_buf_index -= len; } else{ SDL_MixAudio( stream, mad->output_buf, mad->output_buf_index, mad->volume ); len = mad->output_buf_index; mad->output_buf_index = 0; } return len; }
/***************************************************************************** * 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(float) * 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_Err( p_filter, "libmad error: %s", mad_stream_errorstr( &p_sys->mad_stream ) ); if( !MAD_RECOVERABLE( p_sys->mad_stream.error ) ) 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 ) { reject: 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]; float *p_samples = (float *)p_out_buf->p_buffer; if (p_pcm->channels > p_filter->fmt_out.audio.i_channels) { msg_Err( p_filter, "wrong channels count (corrupt stream?): %u > %u", p_pcm->channels, p_filter->fmt_out.audio.i_channels); p_sys->i_reject_count = 3; goto reject; } if( i_samples != p_out_buf->i_nb_samples ) { msg_Err( p_filter, "unexpected samples count (corrupt stream?): " "%u / %u", i_samples, p_out_buf->i_nb_samples ); p_sys->i_reject_count = 3; goto reject; } /* Interleave and keep buffers in mad_fixed_t format */ if ( p_pcm->channels == 2 ) { while ( i_samples-- ) { //assert( *p_left < MAD_F_ONE ); //assert( *p_left >= -MAD_F_ONE ); //assert( *p_right < MAD_F_ONE ); //assert( *p_right >= -MAD_F_ONE ); *p_samples++ = (float)*p_left++ / (float)MAD_F_ONE; *p_samples++ = (float)*p_right++ / (float)MAD_F_ONE; } } else { assert( p_pcm->channels == 1 ); while ( i_samples-- ) { //assert( *p_left < MAD_F_ONE ); //assert( *p_left >= -MAD_F_ONE ); *p_samples++ = (float)*p_left++ / (float)MAD_F_ONE; } } }
void MADTranscode::processData( const QByteArray &buffer, bool finish ) { static audio_dither left_dither, right_dither; int err = 0; m_encodedBuffer.append( buffer ); while ( err == 0 && ( m_encodedBuffer.count() >= MP3_BUFFER || finish ) ) { mad_stream_buffer( &stream, (const unsigned char*)m_encodedBuffer.data(), m_encodedBuffer.count() ); err = mad_frame_decode( &frame, &stream ); if ( stream.next_frame != 0 ) { size_t r = stream.next_frame - stream.buffer; m_encodedBuffer.remove( 0, r ); } if ( err ) { // if ( stream.error != MAD_ERROR_LOSTSYNC ) // qDebug() << "libmad error:" << mad_stream_errorstr( &stream ); if ( !MAD_RECOVERABLE( stream.error ) ) return; err = 0; } else { mad_timer_add( &timer, frame.header.duration ); mad_synth_frame( &synth, &frame ); if ( !m_mpegInitialised ) { long sampleRate = synth.pcm.samplerate; int channels = synth.pcm.channels; qDebug() << "madTranscode( Samplerate:" << sampleRate << "- Channels:" << channels << ")"; m_mpegInitialised = true; emit streamInitialized( sampleRate, channels > 0 ? channels : 2 ); } for ( int i = 0; i < synth.pcm.length; i++ ) { union PCMDATA { short i; unsigned char b[2]; } pcmData; pcmData.i = dither( synth.pcm.samples[0][i], &left_dither ); m_decodedBuffer.append( pcmData.b[0] ); m_decodedBuffer.append( pcmData.b[1] ); if ( synth.pcm.channels == 2 ) { pcmData.i = dither( synth.pcm.samples[1][i], &right_dither ); m_decodedBuffer.append( pcmData.b[0] ); m_decodedBuffer.append( pcmData.b[1] ); } } if ( timer.seconds != last_timer.seconds ) emit timeChanged( timer.seconds ); last_timer = timer; } } }
/**************************************************************************** * 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); }
/* scale */ return output >> scalebits; } #define INPUT_BUFFER_SIZE (5*8192) #define OUTPUT_BUFFER_SIZE 8192 /* Must be an integer multiple of 4. */ void real_mpeg_play(char* fname) { unsigned char InputBuffer[INPUT_BUFFER_SIZE], OutputBuffer[OUTPUT_BUFFER_SIZE], *OutputPtr=OutputBuffer; const unsigned char *OutputBufferEnd=OutputBuffer+OUTPUT_BUFFER_SIZE; int Status=0, i, fd; unsigned long FrameCount=0; sound_t sound; struct mp3entry mp3; static struct dither d0, d1; int key=0; mp3info(&mp3, fname, false); /* FIXME: honor the v1first setting */ init_sound(&sound); /* Configure sound device for this file - always select Stereo because some sound cards don't support mono */ config_sound(&sound,mp3.frequency,2); if ((fd=open(fname,O_RDONLY)) < 0) { fprintf(stderr,"could not open %s\n",fname); return; } /* 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); do { if (Stream.buffer==NULL || Stream.error==MAD_ERROR_BUFLEN) { size_t ReadSize,Remaining; unsigned char *ReadStart; 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; } if ((int)(ReadSize=read(fd,ReadStart,ReadSize)) < 0) { fprintf(stderr,"end of input stream\n"); break; } mad_stream_buffer(&Stream,InputBuffer,ReadSize+Remaining); Stream.error=0; } if(mad_frame_decode(&Frame,&Stream)) { if(MAD_RECOVERABLE(Stream.error)) { fprintf(stderr,"recoverable frame level error\n"); fflush(stderr); continue; } else { if(Stream.error==MAD_ERROR_BUFLEN) { continue; } else { fprintf(stderr,"unrecoverable frame level error\n"); Status=1; break; } } } FrameCount++; mad_timer_add(&Timer,Frame.header.duration); mad_synth_frame(&Synth,&Frame); for(i=0;i<Synth.pcm.length;i++) { unsigned short Sample; /* Left channel */ Sample=scale(Synth.pcm.samples[0][i],&d0); *(OutputPtr++)=Sample&0xff; *(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(&Frame.header)==2) { Sample=scale(Synth.pcm.samples[1][i],&d1); } *(OutputPtr++)=Sample&0xff; *(OutputPtr++)=Sample>>8; /* Flush the buffer if it is full. */ if (OutputPtr==OutputBufferEnd) { if (output_sound(&sound, OutputBuffer, OUTPUT_BUFFER_SIZE)!=OUTPUT_BUFFER_SIZE) { fprintf(stderr,"PCM write error.\n"); Status=2; break; } OutputPtr=OutputBuffer; } } if ((key=button_get(0))==BUTTON_STOP) { break; } }while(1); /* 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 occured during * the last write, then flush it. */ if(OutputPtr!=OutputBuffer && Status!=2) { size_t BufferSize=OutputPtr-OutputBuffer; if (output_sound(&sound, OutputPtr, BufferSize)!=(int)BufferSize) { fprintf(stderr,"PCM write error\n"); Status=2; } } /* Accounting report if no error occured. */ if(!Status) { char Buffer[80]; mad_timer_string(Timer,Buffer,"%lu:%02lu.%03u", MAD_UNITS_MINUTES,MAD_UNITS_MILLISECONDS,0); fprintf(stderr,"%lu frames decoded (%s).\n",FrameCount,Buffer); } close_sound(&sound); /* That's the end of the world (in the H. G. Wells way). */ return; }
static int mp3_startread(snd_stream_t *stream) { mp3_priv_t *p = (mp3_priv_t *) stream->priv; size_t ReadSize; mad_stream_init(&p->Stream); mad_frame_init(&p->Frame); mad_synth_init(&p->Synth); mad_timer_reset(&p->Timer); /* 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. */ ReadSize = FS_fread(p->mp3_buffer, 1, MP3_BUFFER_SIZE, &stream->fh); if (!ReadSize || FS_ferror(&stream->fh)) return -1; mad_stream_buffer(&p->Stream, p->mp3_buffer, ReadSize); /* Find a valid frame before starting up. This makes sure * that we have a valid MP3 and also skips past ID3v2 tags * at the beginning of the audio file. */ p->Stream.error = MAD_ERROR_NONE; while (mad_frame_decode(&p->Frame,&p->Stream)) { /* check whether input buffer needs a refill */ if (p->Stream.error == MAD_ERROR_BUFLEN) { if (mp3_inputdata(stream) == -1) return -1;/* EOF with no valid data */ continue; } /* Consume any ID3 tags */ mp3_inputtag(stream); /* 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. */ p->Stream.error = MAD_ERROR_NONE; } if (p->Stream.error) { Con_Printf("MP3: No valid MP3 frame found\n"); return -1; } switch(p->Frame.header.mode) { case MAD_MODE_SINGLE_CHANNEL: case MAD_MODE_DUAL_CHANNEL: case MAD_MODE_JOINT_STEREO: case MAD_MODE_STEREO: stream->info.channels = MAD_NCHANNELS(&p->Frame.header); break; default: Con_Printf("MP3: Cannot determine number of channels\n"); return -1; } p->FrameCount = 1; mad_timer_add(&p->Timer,p->Frame.header.duration); mad_synth_frame(&p->Synth,&p->Frame); stream->info.rate = p->Synth.pcm.samplerate; stream->info.bits = MP3_MAD_SAMPLEBITS; stream->info.width = MP3_MAD_SAMPLEWIDTH; p->cursamp = 0; return 0; }
static int mad_frame_seek(input_object *obj, int frame) { struct mad_local_data *data; struct mad_header header; int skip; ssize_t byte_offset; if (!obj) return 0; data = (struct mad_local_data *)obj->local_data; if (!data || !data->seekable) return 0; //alsaplayer_error("frame_seek(..., %d)", frame); mad_header_init(&header); data->bytes_avail = 0; if (frame <= data->highest_frame) { skip = 0; if (frame > 4) { skip = 3; } byte_offset = data->frames[frame-skip]; /* Prepare the buffer for a read */ fill_buffer(data, byte_offset); mad_stream_buffer(&data->stream, data->mad_map, data->bytes_avail); skip++; while (skip != 0) { skip--; mad_frame_decode(&data->frame, &data->stream); if (skip == 0) mad_synth_frame (&data->synth, &data->frame); } data->bytes_avail = data->stream.bufend - data->stream.next_frame; data->current_frame = frame; data->seeking = 0; return data->current_frame; } data->seeking = 1; fill_buffer(data, data->frames[data->highest_frame]); mad_stream_buffer(&data->stream, data->mad_map, data->bytes_avail); while (data->highest_frame < frame) { if (data->bytes_avail < 3072) { fill_buffer(data, data->map_offset + MAD_BUFSIZE - data->bytes_avail); mad_stream_buffer(&data->stream, data->mad_map, data->bytes_avail); } if (mad_header_decode(&header, &data->stream) == -1) { if (!MAD_RECOVERABLE(data->stream.error)) { fill_buffer(data, 0); mad_stream_buffer(&data->stream, data->mad_map, data->bytes_avail); data->seeking = 0; return 0; } } data->frames[++data->highest_frame] = data->map_offset + data->stream.this_frame - data->mad_map; data->bytes_avail = data->stream.bufend - data->stream.next_frame; } data->current_frame = data->highest_frame; if (data->current_frame > 4) { skip = 3; fill_buffer(data, data->frames[data->current_frame-skip]); mad_stream_buffer(&data->stream, data->mad_map, data->bytes_avail); skip++; while (skip != 0) { skip--; mad_frame_decode(&data->frame, &data->stream); if (skip == 0) mad_synth_frame (&data->synth, &data->frame); data->bytes_avail = data->stream.bufend - data->stream.next_frame; } } data->seeking = 0; return data->current_frame; return 0; }
/* 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 = q_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);
static int mad_play_frame(input_object *obj, char *buf) { struct mad_local_data *data; struct mad_pcm *pcm; mad_fixed_t const *left_ch; mad_fixed_t const *right_ch; int16_t *output; int nsamples; int nchannels; if (!obj) return 0; data = (struct mad_local_data *)obj->local_data; if (!data) return 0; if (data->bytes_avail < 3072) { /* alsaplayer_error("Filling buffer = %d,%d", data->bytes_avail, data->map_offset + MAD_BUFSIZE - data->bytes_avail); */ fill_buffer(data, -1); /* data->map_offset + MAD_BUFSIZE - data->bytes_avail); */ mad_stream_buffer(&data->stream, data->mad_map, data->bytes_avail); } else { /* alsaplayer_error("bytes_avail = %d", data->bytes_avail); */ } if (mad_frame_decode(&data->frame, &data->stream) == -1) { if (!MAD_RECOVERABLE(data->stream.error)) { /* alsaplayer_error("MAD error: %s (%d). fatal", error_str(data->stream.error, data->str), data->bytes_avail); */ mad_frame_mute(&data->frame); return 0; } else { if (reader_eof(data->mad_fd)) { return 0; } //alsaplayer_error("MAD error: %s (not fatal)", error_str(data->stream.error, data->str)); memset(buf, 0, obj->frame_size); return 1; } } data->current_frame++; if (data->seekable && data->current_frame < (obj->nr_frames + FRAME_RESERVE)) { data->frames[data->current_frame] = data->map_offset + data->stream.this_frame - data->mad_map; if (data->current_frame > 3 && (data->frames[data->current_frame] - data->frames[data->current_frame-3]) < 6) { return 0; } if (data->highest_frame < data->current_frame) data->highest_frame = data->current_frame; } mad_synth_frame (&data->synth, &data->frame); { pcm = &data->synth.pcm; output = (int16_t *)buf; nsamples = pcm->length; nchannels = pcm->channels; if (nchannels != obj->nr_channels) { alsaplayer_error("ERROR: bad data stream! (channels: %d != %d, frame %d)", nchannels, obj->nr_channels, data->current_frame); mad_frame_mute(&data->frame); memset(buf, 0, obj->frame_size); return 1; } obj->nr_channels = nchannels; if (data->samplerate != data->frame.header.samplerate) { alsaplayer_error("ERROR: bad data stream! (samplerate: %d != %d, frame %d)", data->samplerate, data->frame.header.samplerate, data->current_frame); mad_frame_mute(&data->frame); memset(buf, 0, obj->frame_size); return 1; } data->samplerate = data->frame.header.samplerate; left_ch = pcm->samples[0]; right_ch = pcm->samples[1]; while (nsamples--) { *output++ = my_scale(*(left_ch++)); if (nchannels == 1) { *output++ = my_scale(*(left_ch-1)); } else { /* nchannels == 2 */ *output++ = my_scale(*(right_ch++)); } } } data->bytes_avail = data->stream.bufend - data->stream.next_frame; return 1; }
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 }
static int mad_open(input_object *obj, const char *path) { struct mad_local_data *data; char *p; int mode; if (!obj) return 0; obj->local_data = malloc(sizeof(struct mad_local_data)); if (!obj->local_data) { puts("failed to allocate local data"); return 0; } data = (struct mad_local_data *)obj->local_data; memset(data, 0, sizeof(struct mad_local_data)); if ((data->mad_fd = reader_open(path, &reader_status, obj)) == NULL) { fprintf(stderr, "mad_open(obj, %s) failed\n", path); free(obj->local_data); obj->local_data = NULL; return 0; } obj->flags = 0; if (strncasecmp(path, "http://", 7) == 0) { obj->flags |= P_STREAMBASED; strcpy(data->sinfo.status, "Prebuffering"); } else { obj->flags |= P_FILEBASED; } if (!reader_seekable(data->mad_fd)) { data->seekable = 0; } else { obj->flags |= P_SEEK; obj->flags |= P_PERFECTSEEK; data->seekable = 1; } obj->flags |= P_REENTRANT; mad_init_decoder(data); memset(&data->xing, 0, sizeof(struct xing)); xing_init (&data->xing); data->mad_init = 1; fill_buffer(data, -1); //alsaplayer_error("initial bytes_avail = %d", data->bytes_avail); if (obj->flags & P_PERFECTSEEK) { data->offset = find_initial_frame(data->mad_map, data->bytes_avail < STREAM_BUFFER_SIZE ? data->bytes_avail : STREAM_BUFFER_SIZE); } else { data->offset = 0; } data->highest_frame = 0; if (data->offset < 0) { //fprintf(stderr, "mad_open() couldn't find valid MPEG header\n"); data->offset = 0; } //alsaplayer_error("data->offset = %d", data->offset); if (data->offset > data->bytes_avail) { data->seekable = 1; //alsaplayer_error("Need to refill buffer (data->offset = %d)", data->offset); fill_buffer(data, 0); mad_stream_buffer(&data->stream, data->mad_map, data->bytes_avail); } else { mad_stream_buffer(&data->stream, data->mad_map + data->offset, data->bytes_avail - data->offset); data->bytes_avail -= data->offset; } first_frame: if ((mad_header_decode(&data->frame.header, &data->stream) == -1)) { switch (data->stream.error) { case MAD_ERROR_BUFLEN: return 0; case MAD_ERROR_LOSTSYNC: case MAD_ERROR_BADEMPHASIS: case MAD_ERROR_BADBITRATE: case MAD_ERROR_BADLAYER: case MAD_ERROR_BADSAMPLERATE: //alsaplayer_error("Error %x (frame %d)", data->stream.error, data->current_frame); data->bytes_avail-=(data->stream.next_frame - data->stream.this_frame); goto first_frame; break; case MAD_ERROR_BADBITALLOC: return 0; case MAD_ERROR_BADCRC: alsaplayer_error("MAD_ERROR_BADCRC: %s", error_str(data->stream.error, data->str)); case MAD_ERROR_BADBIGVALUES: case MAD_ERROR_BADDATAPTR: break; default: alsaplayer_error("ERROR: %s", error_str(data->stream.error, data->str)); alsaplayer_error("No valid frame found at start (pos: %d, error: 0x%x --> %x %x %x %x) (%s)", data->offset, data->stream.error, data->stream.this_frame[0], data->stream.this_frame[1], data->stream.this_frame[2], data->stream.this_frame[3],path); return 0; } } mad_frame_decode(&data->frame, &data->stream); /* alsaplayer_error("xing parsing...%x %x %x %x (%x %d)", data->stream.this_frame[0], data->stream.this_frame[1], data->stream.this_frame[2], data->stream.this_frame[3], data->stream.anc_ptr, data->stream.anc_bitlen); */ if (xing_parse(&data->xing, data->stream.anc_ptr, data->stream.anc_bitlen) == 0) { // We use the xing data later on } mode = (data->frame.header.mode == MAD_MODE_SINGLE_CHANNEL) ? 1 : 2; data->samplerate = data->frame.header.samplerate; data->bitrate = data->frame.header.bitrate; mad_synth_frame (&data->synth, &data->frame); { struct mad_pcm *pcm = &data->synth.pcm; obj->nr_channels = pcm->channels; //alsaplayer_error("nr_channels = %d", obj->nr_channels); } //alsaplayer_error("Initial: %d, %d, %d", data->samplerate, data->bitrate, obj->nr_channels); /* Calculate some values */ data->bytes_avail = data->stream.bufend - data->stream.next_frame; { int64_t time; int64_t samples; int64_t frames; long oldpos = reader_tell(data->mad_fd); reader_seek(data->mad_fd, 0, SEEK_END); data->filesize = reader_tell(data->mad_fd); data->filesize -= data->offset; reader_seek(data->mad_fd, oldpos, SEEK_SET); if (data->bitrate) time = (data->filesize * 8) / (data->bitrate); else time = 0; samples = 32 * MAD_NSBSAMPLES(&data->frame.header); obj->frame_size = (int) samples << 2; /* Assume 16-bit stereo */ frames = data->samplerate * (time+1) / samples; if (data->xing.flags & XING_FRAMES) { obj->nr_frames = data->xing.frames; } else { obj->nr_frames = (int) frames; } obj->nr_tracks = 1; } /* Determine if nr_frames makes sense */ if (!(obj->flags & P_SEEK) && (obj->flags & P_STREAMBASED)) { obj->nr_frames = -1; } /* Allocate frame index */ if (!data->seekable || obj->nr_frames > 1000000 || (data->frames = (ssize_t *)malloc((obj->nr_frames + FRAME_RESERVE) * sizeof(ssize_t))) == NULL) { data->seekable = 0; // Given really } else { data->seekable = 1; data->frames[0] = 0; } data->mad_init = 1; p = strrchr(path, '/'); if (p) { strcpy(data->filename, ++p); } else { strcpy(data->filename, path); } strcpy(data->path, path); data->parse_id3 = prefs_get_bool(ap_prefs, "mad", "parse_id3", 1); return 1; }
bool CMpegAudioDecoder::DecodeFrame(const BYTE *pData, DWORD *pDataSize, DecodeFrameInfo *pInfo) { if (!m_bInitialized) { return false; } if (m_MadStream.buffer == nullptr || m_MadStream.error == MAD_ERROR_BUFLEN) { size_t ReadSize, Remain; if (m_MadStream.next_frame != nullptr) { Remain = m_MadStream.bufend - m_MadStream.next_frame; ::MoveMemory(m_InputBuffer, m_MadStream.next_frame, Remain); ReadSize = INPUT_BUFFER_SIZE - Remain; } else { ReadSize = INPUT_BUFFER_SIZE; Remain = 0; } if (ReadSize > *pDataSize) ReadSize = *pDataSize; *pDataSize = (DWORD)ReadSize; ::CopyMemory(&m_InputBuffer[Remain], pData, ReadSize); mad_stream_buffer(&m_MadStream, m_InputBuffer, (unsigned long)(ReadSize + Remain)); m_MadStream.error = MAD_ERROR_NONE; } else { *pDataSize = 0; } if (mad_frame_decode(&m_MadFrame, &m_MadStream)) { pInfo->Samples = 0; if (m_MadStream.error == MAD_ERROR_BUFLEN) return true; if (MAD_RECOVERABLE(m_MadStream.error)) return true; #ifdef _DEBUG ::OutputDebugStringA("libmad error : "); ::OutputDebugStringA(mad_stream_errorstr(&m_MadStream)); ::OutputDebugStringA("\n"); #endif ResetDecoder(); return false; } mad_synth_frame(&m_MadSynth, &m_MadFrame); const BYTE Channels = MAD_NCHANNELS(&m_MadFrame.header); short *p = m_PcmBuffer; if (Channels == 1) { for (int i = 0; i < m_MadSynth.pcm.length; i++) { *p++ = FixedToInt16(m_MadSynth.pcm.samples[0][i]); } } else { for (int i = 0; i < m_MadSynth.pcm.length; i++) { *p++ = FixedToInt16(m_MadSynth.pcm.samples[0][i]); *p++ = FixedToInt16(m_MadSynth.pcm.samples[1][i]); } } m_AudioInfo.Frequency = m_MadSynth.pcm.samplerate; m_AudioInfo.Channels = Channels; m_AudioInfo.OrigChannels = Channels; m_AudioInfo.bDualMono = false; pInfo->pData = (const BYTE*)m_PcmBuffer; pInfo->Samples = m_MadSynth.pcm.length; pInfo->Info = m_AudioInfo; pInfo->bDiscontinuity = m_bDecodeError; return true; }
int Mp3Decoder::decode_frame(sh_audio_t *sh,unsigned char *outdata,int *outlen){ mad_decoder_t *mad_dec = (mad_decoder_t *) sh->context; int len; unsigned char *inbuf = buffer; int inbuff_len = a_in_buffer_len; *outlen = 0; uint16_t *output = (uint16_t *)outdata; int nChannels = 0; while(1){ int ret; // EL("sh->a_in_buffer: %p, inbuff_len: %d",inbuf,inbuff_len); mad_dec->stream.error = MAD_ERROR_NONE; mad_stream_buffer (&mad_dec->stream, (unsigned char *)inbuf, inbuff_len); // EL(""); ret=mad_frame_decode (&mad_dec->frame, &mad_dec->stream); if (sh->samplerate == 0)//hpwang 2011-08-03 add for samplerate is zero while mpeg2 audio sh->samplerate = mad_dec->frame.header.samplerate; nChannels = mad_dec->frame.header.mode ? 2 : 1; if (nChannels != sh->channels) sh->channels = mad_dec->synth.pcm.channels; // ALOGE("RET: %d, stream error: %d",ret,mad_dec->stream.error); // EL("ret: %d, next_frame: %p",ret,mad_dec->stream.next_frame); //ALOGE("sh->channels = %d,sh->samplerate = %d",sh->channels,sh->samplerate); inbuff_len -= (mad_dec->stream.next_frame - inbuf); inbuf = (unsigned char *)mad_dec->stream.next_frame; if(inbuff_len <= 0) { a_in_buffer_len = 0; return 0; } a_in_buffer_len = inbuff_len; if(a_in_buffer_len == 0) return (inbuf - buffer); if (ret == 0){ mad_synth_frame (&mad_dec->synth, &mad_dec->frame); { unsigned int nchannels, nsamples; mad_fixed_t const *left_ch, *right_ch; struct mad_pcm *pcm = &mad_dec->synth.pcm; nchannels = pcm->channels; nsamples = pcm->length; left_ch = pcm->samples[0]; right_ch = pcm->samples[1]; *outlen += nchannels*nsamples; while (nsamples--) { /* output sample(s) in 16-bit signed little-endian PCM */ *output++ = scale(*left_ch++); if (nchannels == 2) *output++ = scale(*right_ch++); } } }else if(!MAD_RECOVERABLE(mad_dec->stream.error)) { if(mad_dec->stream.error == MAD_ERROR_BUFLEN) { memcpy(buffer, inbuf, a_in_buffer_len); return (inbuf - buffer); } else { //memcpy(buffer, inbuf, a_in_buffer_len); return 0; } } } mp_msg(MSGT_DECAUDIO,MSGL_INFO,"Cannot sync MAD frame\n"); return 0; }
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; } #ifndef USE_ASYNC stream = &decoder->sync.stream; frame = &decoder->sync.frame; synth = &decoder->sync.synth; memset(&decoder->sync, 0, sizeof(decoder->sync)); #endif 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 defined(USE_ASYNC) if (decoder->mode == MAD_DECODER_MODE_ASYNC) { switch (check_message(decoder)) { case MAD_FLOW_IGNORE: case MAD_FLOW_CONTINUE: break; case MAD_FLOW_BREAK: goto fail; case MAD_FLOW_STOP: goto done; } } # endif 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; }
madx_sig madx_read ( unsigned char *in_buffer, unsigned char *out_buffer, madx_house *mxhouse, madx_stat *mxstat) { // "Random" seed for generating dither. Used // by scale_audio() in preparing the samples // for 16 bit output. mad_fixed_t rnscale = 0xa8b9ff7e; unsigned char *guard_ptr = NULL; unsigned char *readstart; // Clear mxstat->msg sprintf(mxstat->msg,""); mxstat->buffstart = 0; // Input file has been read completely if ( mxstat->is_eof && !mxstat->readsize ) { sprintf(mxstat->msg,"End of input stream"); return(EOF_REACHED); } // Executes on initial loop if ( (mxstat->readsize == 0) && (mxstat->remaining == 0) && mxhouse->stream.buffer == NULL ) { mxstat->readsize = MADX_INPUT_BUFFER_SIZE; mxstat->remaining = 0; return(MORE_INPUT); } readstart = in_buffer; // Stream buffer if ( mxhouse->stream.buffer == NULL || mxhouse->stream.error == MAD_ERROR_BUFLEN ) { // BUFFER_GUARD // "mxstat->is_eof" must be set to // non-zero IMMEDIATELY (see "test.cpp") // once it is detected, so the following // may execute, padding the buffer. if( mxstat->is_eof ) { guard_ptr = in_buffer + mxstat->readsize; memset( guard_ptr, 0, MAD_BUFFER_GUARD ); mxstat->readsize += MAD_BUFFER_GUARD; } // Pipe the new buffer content to libmad's // stream decoder facility. mad_stream_buffer( &mxhouse->stream, in_buffer, mxstat->readsize + mxstat->remaining ); mxhouse->stream.error = (mad_error)0; } // [Madlld comment]: // Decode the next MPEG frame. The streams is read from the // buffer, its constituents are broken down and stored in the // mxhouse->frame structure, ready for examination/alteration // or PCM synthesis. Decoding options are carried in the Frame // structure from the mxhouse->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 mxhouse->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(&mxhouse->frame, &mxhouse->stream) ) { if( MAD_RECOVERABLE(mxhouse->stream.error) ) { // Do not print a message if the error is // a loss of synchronization or this loss // is due to the end of stream guard bytes. if( mxhouse->stream.error != MAD_ERROR_LOSTSYNC || mxhouse->stream.this_frame != guard_ptr || // Suppress error if caused by ID3 tag. (mxhouse->stream.this_frame[0] != 'I' && // ID3v2 mxhouse->stream.this_frame[1] != 'D' && mxhouse->stream.this_frame[2] != '3') || (mxhouse->stream.this_frame[0] != 'T' && // ID3v1 mxhouse->stream.this_frame[1] != 'A' && mxhouse->stream.this_frame[2] != 'G') ) { sprintf(mxstat->msg,"Recoverable frame level error (%s)", MadErrorString(&mxhouse->stream)); } return(CALL_AGAIN); } else // Non-recoverable error { // MAD_ERROR_BUFLEN means that more input // is needed (it's not recoverable without // interaction from the calling code). The // bytes already in the buffer must be // preserved. "mxstat->buffstart" is used // to point to the end of the preserved // bytes in "in_buffer", then MORE_INPUT // is requested. "mxstat->buffstart" is set // to 0 every time "madx_read()" is // called. The calling code checks this // variable to determine if a full buffer // read or a partial read is necessary. // (Not "0" signifies a partial read.) if( mxhouse->stream.error == MAD_ERROR_BUFLEN ) { sprintf(mxstat->msg, "Need more input (%s)", MadErrorString(&mxhouse->stream)); mxstat->remaining = mxhouse->stream.bufend - mxhouse->stream.next_frame; memmove(in_buffer, mxhouse->stream.next_frame, mxstat->remaining); mxstat->readsize = MADX_INPUT_BUFFER_SIZE - mxstat->remaining; // How far "forward" in_buffer to begin: mxstat->buffstart = in_buffer + mxstat->remaining; return(MORE_INPUT); } else // Error returned { sprintf(mxstat->msg,"Unrecoverable frame level error (%s).", MadErrorString(&mxhouse->stream)); return(ERROR_OCCURED); } } } // [Madlld comment]: // 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! mxhouse->frame_cnt++; mad_timer_add( &mxhouse->timer, mxhouse->frame.header.duration ); // Once decoded the frame is synthesized to // PCM samples. No errors are reported by // mad_synth_frame(); mad_synth_frame( &mxhouse->synth, &mxhouse->frame ); // [Madlld comment]: // 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. // // Note: Code to computer "big-endian" has been preserved // below. It is simply commented out. This source produces // 16-bit "little-endian" PCM samples. for( int i=0; i < mxhouse->synth.pcm.length; i++ ) { signed short sample; // Left channel sample = scale_audio(mxhouse->synth.pcm.samples[0][i], &rnscale); // Originally big-endian: // *(mxhouse->output_ptr++)=sample>>8; // *(mxhouse->output_ptr++)=sample&0xff; // 16-bit little-endian *(mxhouse->output_ptr++)=((sample>>0) & 0xff); *(mxhouse->output_ptr++)=((sample>>8) & 0xff); // Right channel. // If the decoded stream is monophonic then // the right output channel is the same as // the left one. if(MAD_NCHANNELS(&mxhouse->frame.header)==2) sample = scale_audio(mxhouse->synth.pcm.samples[1][i], &rnscale); // Originally big-endian: // *(mxhouse->output_ptr++)=sample>>8; // *(mxhouse->output_ptr++)=sample&0xff; // 16-bit little-endian *(mxhouse->output_ptr++)=((sample>>0) & 0xff); *(mxhouse->output_ptr++)=((sample>>8) & 0xff); } // Tell calling code buffer size mxstat->write_size = mxhouse->output_ptr - out_buffer; // Indicate that buffer is ready to be // written. if (mxhouse->synth.pcm.length < 1152 || MADX_OUTPUT_BUFFER_SIZE - mxstat->write_size < 1152) { // Reset pointer mxhouse->output_ptr = out_buffer; return(FLUSH_BUFFER); } else return(CALL_AGAIN); // Otherwise, continue }