mad_flow MADStream::ms_error(void* user, mad_stream* stream, mad_frame* frame) { RW_UNUSED(user); RW_UNUSED(frame); std::cerr << "libmad error: " << mad_stream_errorstr(stream) << std::endl; return MAD_FLOW_BREAK; }
static enum mp3_action decode_next_frame_header(struct mp3_data *data, G_GNUC_UNUSED struct tag **tag) { enum mad_layer layer; if ((data->stream).buffer == NULL || (data->stream).error == MAD_ERROR_BUFLEN) { if (!mp3_fill_buffer(data)) return DECODE_BREAK; } if (mad_header_decode(&data->frame.header, &data->stream)) { if ((data->stream).error == MAD_ERROR_LOSTSYNC && (data->stream).this_frame) { signed long tagsize = id3_tag_query((data->stream). this_frame, (data->stream). bufend - (data->stream). this_frame); if (tagsize > 0) { if (tag && !(*tag)) { mp3_parse_id3(data, (size_t)tagsize, tag); } else { mad_stream_skip(&(data->stream), tagsize); } return DECODE_CONT; } } 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; } } } layer = data->frame.header.layer; if (!data->layer) { if (layer != MAD_LAYER_II && layer != MAD_LAYER_III) { /* Only layer 2 and 3 have been tested to work */ return DECODE_SKIP; } data->layer = layer; } else if (layer != data->layer) { /* Don't decode frames with a different layer than the first */ return DECODE_SKIP; } return DECODE_OK; }
/***************************************************************************** * 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) ); } }
static enum mad_flow error(void *data, struct mad_stream *stream, struct mad_frame *frame) { struct buffer *buffer = (struct buffer *)data; fprintf(stderr, "decoding error 0x%04x (%s) at byte offset %u\n", stream->error, mad_stream_errorstr(stream), stream->this_frame - buffer->start); /* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */ return MAD_FLOW_CONTINUE; }
static const void *mp_registersong (music_player_t *music, const void *data, unsigned len) { mp_player_t *mp = (mp_player_t*)music; int i; int maxtry; int success = 0; // the MP3 standard doesn't include any global file header. the only way to tell filetype // is to start decoding stuff. you can't be too strict however because MP3 is resilient to // crap in the stream. // this routine is a bit slower than it could be, but apparently there are lots of files out // there with some dodgy stuff at the beginning. // if the stream begins with an ID3v2 magic, search hard and long for our first valid header if (memcmp (data, "ID3", 3) == 0) maxtry = 100; // otherwise, search for not so long else maxtry = 20; mad_stream_buffer (&mp->Stream, data, len); for (i = 0; i < maxtry; i++) { if (mad_header_decode (&mp->Header, &mp->Stream) != 0) { if (!MAD_RECOVERABLE (mp->Stream.error)) { lprintf (LO_WARN, "mad_registersong failed: %s\n", mad_stream_errorstr (&mp->Stream)); return NULL; } } else { success++; } } // 80% to pass if (success < maxtry * 8 / 10) { lprintf (LO_WARN, "mad_registersong failed\n"); return NULL; } lprintf (LO_INFO, "mad_registersong succeed. bitrate %lu samplerate %d\n", mp->Header.bitrate, mp->Header.samplerate); mp->mp_data = data; mp->mp_len = len; // handle not used return data; }
static enum mad_flow IoMP3Decoder_errorCallback(void *data, struct mad_stream *stream, struct mad_frame *frame) { //IoMP3Decoder *self = data; fprintf(stderr, "lbmad error %i (%s)\n", stream->error, mad_stream_errorstr(stream)); /* IoState_error_(IOSTATE, 0x0, "MP3Decoder %s", mad_stream_errorstr(stream)); DATA(self)->isRunning = 0; return MAD_FLOW_BREAK; */ return MAD_FLOW_CONTINUE; }
/* 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; }
void MP3Stream::readHeader() { if (_state != MP3_STATE_READY) return; // If necessary, load more data into the stream decoder if (_stream.error == MAD_ERROR_BUFLEN) readMP3Data(); while (_state != MP3_STATE_EOS) { _stream.error = MAD_ERROR_NONE; // Decode the next header. Note: mad_frame_decode would do this for us, too. // However, for seeking we don't want to decode the full frame (else it would // be far too slow). Hence we perform this explicitly in a separate step. if (mad_header_decode(&_frame.header, &_stream) == -1) { if (_stream.error == MAD_ERROR_BUFLEN) { readMP3Data(); // Read more data continue; } else if (MAD_RECOVERABLE(_stream.error)) { //status("MP3Stream: Recoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream)); continue; } else { warning("MP3Stream: Unrecoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream)); break; } } // Sum up the total playback time so far mad_timer_add(&_totalTime, _frame.header.duration); _samples += 32 * MAD_NSBSAMPLES(&_frame.header); break; } if (_stream.error != MAD_ERROR_NONE) _state = MP3_STATE_EOS; }
/* 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 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; }
/***************************************************************************** * 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; } } } }
/* * this is a really simple bash at an EQ graph * just a quick hack */ enum mad_flow filter(void *closure, struct mad_stream const *stream, struct mad_frame *frame) { int channel, slice, band; unsigned long avg = 0; int sample; /* JDH - if we're not showing the song that's playing don't show the equalizer either */ if (np_check_state() == 0) { return MAD_FLOW_CONTINUE; } for (channel = 0; channel < 2; channel++) { for (band = 1; band < 31; band++) { avg = 0; for (slice = 0; slice < MAD_NSBSAMPLES(&frame->header); slice++) { mad_fixed_t fixed = frame->sbsample[channel][slice][band]; avg += abs(fixed >> (MAD_F_FRACBITS-5)); /*avg >> 1;*/ } sample = avg; /* Fixed point values cover the range [-8.0, 8.0). Convert this to the int range [-1024, 1023] meaning that [-1.0, 1.0) ==> [-128, 127]. */ /*int sample = fixed >> 18; */ /*DBG_PRINTF("mp3: %3d ", sample); */ if (sample > 50) { sample = 50; } sample -= 10; if (sample < 0) { sample = 0; } video_set_colour (&vid, 255, 255, 255); video_v_line (&vid, 250 + band * 3 + (100 * channel), vid.visy - 100, -sample); video_set_colour (&vid, 0, 0, 0); video_v_line (&vid, 250 + band * 3 + (100 * channel), vid.visy - sample - 100, -50 - sample); video_set_colour (&vid, 255, 255, 255); video_v_line (&vid, 250 + band * 3 + 1 + (100 * channel), vid.visy - 100, -sample); video_set_colour (&vid, 0, 0, 0); video_v_line (&vid, 250 + band * 3 + 1 + (100 * channel), vid.visy - sample - 100, -50 - sample); #if 0 avg += sample; #endif } /*DBG_PRINTF("\n"); */ return MAD_FLOW_CONTINUE; } #endif /* * error */ static enum mad_flow error(void *data, struct mad_stream *stream, struct mad_frame *frame) { DBG_PRINTF("mp3_play: decoding error 0x%04x (%s)\n", stream->error, mad_stream_errorstr(stream)); return MAD_FLOW_CONTINUE; }
/* 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);
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; }
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 }
/***************************************************************************** * 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; } } }
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; }
SoundSource::OpenResult SoundSourceMp3::tryOpen(const AudioSourceConfig& /*audioSrcCfg*/) { DEBUG_ASSERT(!hasValidChannelCount()); DEBUG_ASSERT(!hasValidSamplingRate()); DEBUG_ASSERT(!m_file.isOpen()); if (!m_file.open(QIODevice::ReadOnly)) { qWarning() << "Failed to open file:" << m_file.fileName(); return OpenResult::FAILED; } // Get a pointer to the file using memory mapped IO m_fileSize = m_file.size(); m_pFileData = m_file.map(0, m_fileSize); // NOTE(uklotzde): If the file disappears unexpectedly while mapped // a SIGBUS error might occur that is not handled and will terminate // Mixxx immediately. This behavior is documented in the manpage of // mmap(). It has already appeared due to hardware errors and is // described in the following bug report: // https://bugs.launchpad.net/mixxx/+bug/1452005 // Transfer it to the mad stream-buffer: mad_stream_options(&m_madStream, MAD_OPTION_IGNORECRC); mad_stream_buffer(&m_madStream, m_pFileData, m_fileSize); DEBUG_ASSERT(m_pFileData == m_madStream.this_frame); DEBUG_ASSERT(m_seekFrameList.empty()); m_avgSeekFrameCount = 0; m_curFrameIndex = getMinFrameIndex(); int headerPerSamplingRate[kSamplingRateCount]; for (int i = 0; i < kSamplingRateCount; ++i) { headerPerSamplingRate[i] = 0; } // Decode all the headers and calculate audio properties unsigned long sumBitrate = 0; mad_header madHeader; mad_header_init(&madHeader); SINT maxChannelCount = getChannelCount(); do { if (!decodeFrameHeader(&madHeader, &m_madStream, true)) { if (isStreamValid(m_madStream)) { // Skip frame continue; } else { // Abort decoding break; } } // Grab data from madHeader const unsigned int madSampleRate = madHeader.samplerate; // TODO(XXX): Replace DEBUG_ASSERT with static_assert // MAD must not change its enum values! DEBUG_ASSERT(MAD_UNITS_8000_HZ == 8000); const mad_units madUnits = static_cast<mad_units>(madSampleRate); const long madFrameLength = mad_timer_count(madHeader.duration, madUnits); if (0 >= madFrameLength) { qWarning() << "Skipping MP3 frame with invalid length" << madFrameLength << "in:" << m_file.fileName(); // Skip frame continue; } const SINT madChannelCount = MAD_NCHANNELS(&madHeader); if (isValidChannelCount(maxChannelCount) && (madChannelCount != maxChannelCount)) { qWarning() << "Differing number of channels" << madChannelCount << "<>" << maxChannelCount << "in some MP3 frame headers:" << m_file.fileName(); } maxChannelCount = math_max(madChannelCount, maxChannelCount); const int samplingRateIndex = getIndexBySamplingRate(madSampleRate); if (samplingRateIndex >= kSamplingRateCount) { qWarning() << "Invalid sample rate:" << m_file.fileName() << madSampleRate; // Abort mad_header_finish(&madHeader); return OpenResult::FAILED; } // Count valid frames separated by its sampling rate headerPerSamplingRate[samplingRateIndex]++; addSeekFrame(m_curFrameIndex, m_madStream.this_frame); // Accumulate data from the header sumBitrate += madHeader.bitrate; // Update current stream position m_curFrameIndex += madFrameLength; DEBUG_ASSERT(m_madStream.this_frame); DEBUG_ASSERT(0 <= (m_madStream.this_frame - m_pFileData)); } while (quint64(m_madStream.this_frame - m_pFileData) < m_fileSize); mad_header_finish(&madHeader); if (MAD_ERROR_NONE != m_madStream.error) { // Unreachable code for recoverable errors DEBUG_ASSERT(!MAD_RECOVERABLE(m_madStream.error)); if (MAD_ERROR_BUFLEN != m_madStream.error) { qWarning() << "Unrecoverable MP3 header error:" << mad_stream_errorstr(&m_madStream); // Abort return OpenResult::FAILED; } } if (m_seekFrameList.empty()) { // This is not a working MP3 file. qWarning() << "SSMP3: This is not a working MP3 file:" << m_file.fileName(); // Abort return OpenResult::FAILED; } int mostCommonSamplingRateIndex = kSamplingRateCount; // invalid int mostCommonSamplingRateCount = 0; int differentRates = 0; for (int i = 0; i < kSamplingRateCount; ++i) { // Find most common sampling rate if (mostCommonSamplingRateCount < headerPerSamplingRate[i]) { mostCommonSamplingRateCount = headerPerSamplingRate[i]; mostCommonSamplingRateIndex = i; differentRates++; } } if (differentRates > 1) { qWarning() << "Differing sampling rate in some headers:" << m_file.fileName(); for (int i = 0; i < kSamplingRateCount; ++i) { if (0 < headerPerSamplingRate[i]) { qWarning() << headerPerSamplingRate[i] << "MP3 headers with sampling rate" << getSamplingRateByIndex(i); } } qWarning() << "MP3 files with varying sample rate are not supported!"; qWarning() << "Since this happens most likely due to a corrupt file"; qWarning() << "Mixxx tries to plays it with the most common sample rate for this file"; } if (mostCommonSamplingRateIndex < kSamplingRateCount) { setSamplingRate(getSamplingRateByIndex(mostCommonSamplingRateIndex)); } else { qWarning() << "No single valid sampling rate in header"; // Abort return OpenResult::FAILED; } // Initialize the AudioSource setChannelCount(maxChannelCount); setFrameCount(m_curFrameIndex); // Calculate average values m_avgSeekFrameCount = getFrameCount() / m_seekFrameList.size(); const unsigned long avgBitrate = sumBitrate / m_seekFrameList.size(); setBitrate(avgBitrate / 1000); // Terminate m_seekFrameList addSeekFrame(m_curFrameIndex, 0); // Reset positions m_curFrameIndex = getMinFrameIndex(); // Restart decoding at the beginning of the audio stream m_curFrameIndex = restartDecoding(m_seekFrameList.front()); if (m_curFrameIndex != m_seekFrameList.front().frameIndex) { qWarning() << "Failed to start decoding:" << m_file.fileName(); // Abort return OpenResult::FAILED; } return OpenResult::SUCCEEDED; }
// // 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 count_time_internal (struct mp3_data *data) { struct xing xing; unsigned long bitrate = 0; int has_xing = 0; int is_vbr = 0; int num_frames = 0; mad_timer_t duration = mad_timer_zero; struct mad_header header; int good_header = 0; /* Have we decoded any header? */ mad_header_init (&header); xing_init (&xing); /* There are three ways of calculating the length of an mp3: 1) Constant bitrate: One frame can provide the information needed: # of frames and duration. Just see how long it is and do the division. 2) Variable bitrate: Xing tag. It provides the number of frames. Each frame has the same number of samples, so just use that. 3) All: Count up the frames and duration of each frames by decoding each one. We do this if we've no other choice, i.e. if it's a VBR file with no Xing tag. */ while (1) { /* Fill the input buffer if needed */ if (data->stream.buffer == NULL || data->stream.error == MAD_ERROR_BUFLEN) { if (!fill_buff(data)) break; } if (mad_header_decode(&header, &data->stream) == -1) { if (MAD_RECOVERABLE(data->stream.error)) continue; else if (data->stream.error == MAD_ERROR_BUFLEN) continue; else { debug ("Can't decode header: %s", mad_stream_errorstr( &data->stream)); break; } } good_header = 1; /* Limit xing testing to the first frame header */ if (!num_frames++) { if (xing_parse(&xing, data->stream.anc_ptr, data->stream.anc_bitlen) != -1) { is_vbr = 1; debug ("Has XING header"); if (xing.flags & XING_FRAMES) { has_xing = 1; num_frames = xing.frames; break; } debug ("XING header doesn't contain number of " "frames."); } } /* Test the first n frames to see if this is a VBR file */ if (!is_vbr && !(num_frames > 20)) { if (bitrate && header.bitrate != bitrate) { debug ("Detected VBR after %d frames", num_frames); is_vbr = 1; } else bitrate = header.bitrate; } /* We have to assume it's not a VBR file if it hasn't already * been marked as one and we've checked n frames for different * bitrates */ else if (!is_vbr) { debug ("Fixed rate MP3"); break; } mad_timer_add (&duration, header.duration); } if (!good_header) return -1; if (!is_vbr) { /* time in seconds */ double time = (data->size * 8.0) / (header.bitrate); double timefrac = (double)time - ((long)(time)); /* samples per frame */ long nsamples = 32 * MAD_NSBSAMPLES(&header); /* samplerate is a constant */ num_frames = (long) (time * header.samplerate / nsamples); /* the average bitrate is the constant bitrate */ data->avg_bitrate = bitrate; mad_timer_set(&duration, (long)time, (long)(timefrac*100), 100); } else if (has_xing) { mad_timer_multiply (&header.duration, num_frames); duration = header.duration; } else { /* the durations have been added up, and the number of frames counted. We do nothing here. */ debug ("Counted duration by counting frames durations in " "VBR file."); } if (data->avg_bitrate == -1 && mad_timer_count(duration, MAD_UNITS_SECONDS) > 0) { data->avg_bitrate = data->size / mad_timer_count(duration, MAD_UNITS_SECONDS) * 8; } mad_header_finish(&header); debug ("MP3 time: %ld", mad_timer_count (duration, MAD_UNITS_SECONDS)); return mad_timer_count (duration, MAD_UNITS_SECONDS); }
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; }
/* Handle first-stage decoding: extracting the MP3 frame data. */ int RageSoundReader_MP3::do_mad_frame_decode( bool headers_only ) { int bytes_read = 0; while(1) { int ret; /* Always actually decode the first packet, so we cleanly parse Xing tags. */ if( headers_only && !mad->first_frame ) ret=mad_header_decode( &mad->Frame.header,&mad->Stream ); else ret=mad_frame_decode( &mad->Frame,&mad->Stream ); if( ret == -1 && (mad->Stream.error == MAD_ERROR_BUFLEN || mad->Stream.error == MAD_ERROR_BUFPTR) ) { if( bytes_read > 25000 ) { /* We've read this much without actually getting a frame; error. */ SetError( "Can't find data" ); return -1; } ret = fill_buffer(); if( ret <= 0 ) return ret; bytes_read += ret; continue; } if( ret == -1 && mad->Stream.error == MAD_ERROR_LOSTSYNC ) { /* This might be an ID3V2 tag. */ const int tagsize = id3_tag_query(mad->Stream.this_frame, mad->Stream.bufend - mad->Stream.this_frame); if( tagsize ) { mad_stream_skip(&mad->Stream, tagsize); /* Don't count the tagsize against the max-read-per-call figure. */ bytes_read -= tagsize; continue; } } if( ret == -1 && mad->Stream.error == MAD_ERROR_BADDATAPTR ) { /* * Something's corrupt. One cause of this is cutting an MP3 in the middle * without reencoding; the first two frames will reference data from previous * frames that have been removed. The frame is valid--we can get a header from * it, we just can't synth useful data. * * BASS pretends the bad frames are silent. Emulate that, for compatibility. */ ret = 0; /* pretend success */ } if( !ret ) { /* OK. */ if( mad->first_frame ) { /* We're at the beginning. Is this a Xing tag? */ if(handle_first_frame()) { /* The first frame contained a header. Continue searching. */ continue; } /* We've decoded the first frame of data. * * We want mad->Timer to represent the timestamp of the first sample of the * currently decoded frame. Don't increment mad->Timer on the first frame, * or it'll be the time of the *next* frame. (All frames have the same * duration.) */ mad->first_frame = false; mad->Timer = mad_timer_zero; mad->header_bytes = get_this_frame_byte(mad); } else { mad_timer_add( &mad->Timer,mad->Frame.header.duration ); } fill_frame_index_cache( mad ); return 1; } if( mad->Stream.error == MAD_ERROR_BADCRC ) { /* XXX untested */ mad_frame_mute(&mad->Frame); mad_synth_mute(&mad->Synth); continue; } if( !MAD_RECOVERABLE(mad->Stream.error) ) { /* We've received an unrecoverable error. */ SetError( mad_stream_errorstr(&mad->Stream) ); return -1; } } }
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; }
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; }
bool Mp3AudioFileReader::run(AudioProcessor& processor) { if (file_ == nullptr) { return false; } enum { STATUS_OK, STATUS_INIT_ERROR, STATUS_READ_ERROR, STATUS_PROCESS_ERROR } status = STATUS_OK; unsigned char input_buffer[INPUT_BUFFER_SIZE + MAD_BUFFER_GUARD]; unsigned char* guard_ptr = nullptr; unsigned long frame_count = 0; short output_buffer[OUTPUT_BUFFER_SIZE]; short* output_ptr = output_buffer; const short* const output_buffer_end = output_buffer + OUTPUT_BUFFER_SIZE; int channels = 0; // Decoding options can here be set in the options field of the stream // structure. // {1} When decoding from a file we need to know when the end of the file is // reached at the same time as the last bytes are read (see also the comment // marked {3} below). Neither the standard C fread() function nor the POSIX // read() system call provides this feature. We thus need to perform our // reads through an interface having this feature, this is implemented here // by the bstdfile.c module. BStdFile bstd_file(file_); // Initialize the structures used by libmad. MadStream stream; MadFrame frame; MadSynth synth; mad_timer_t timer; mad_timer_reset(&timer); // This is the decoding loop. for (;;) { // The input bucket must be filled if it becomes empty or if it's the // first execution of the loop. if (stream.buffer == nullptr || stream.error == MAD_ERROR_BUFLEN) { size_t read_size; size_t remaining; unsigned char* read_start; // {2} libmad may not consume all bytes of the input buffer. If the // last frame in the buffer is not wholly contained by it, then that // frame's start is pointed by the next_frame member of the stream // structure. This common situation occurs when mad_frame_decode() // fails, sets the stream error code to MAD_ERROR_BUFLEN, and sets // the next_frame pointer to a non-NULL value. (See also the comment // marked {4} below.) // // When this occurs, the remaining unused bytes must be put back at // the beginning of the buffer and taken in account before refilling // the buffer. This means that the input buffer must be large enough // to hold a whole frame at the highest observable bit-rate // (currently 448 kb/s). XXX=XXX Is 2016 bytes the size of the // largest frame? (448000*(1152/32000))/8 if (stream.next_frame != nullptr) { remaining = stream.bufend - stream.next_frame; memmove(input_buffer, stream.next_frame, remaining); read_start = input_buffer + remaining; read_size = INPUT_BUFFER_SIZE - remaining; } else { read_size = INPUT_BUFFER_SIZE; read_start = input_buffer; remaining = 0; } // Fill-in the buffer. If an error occurs print a message and leave // the decoding loop. If the end of stream is reached we also leave // the loop but the return status is left untouched. read_size = bstd_file.read(read_start, 1, read_size); if (read_size <= 0) { if (ferror(file_)) { error_stream << "\nRead error on bit-stream: " << strerror(errno) << '\n'; status = STATUS_READ_ERROR; } break; } // {3} When decoding the last frame of a file, it must be followed // by MAD_BUFFER_GUARD zero bytes if one wants to decode that last // frame. When the end of file is detected we append that quantity // of bytes at the end of the available data. Note that the buffer // can't overflow as the guard size was allocated but not used the // the buffer management code. (See also the comment marked {1}.) // // In a message to the mad-dev mailing list on May 29th, 2001, Rob // Leslie explains the guard zone as follows: // // "The reason for MAD_BUFFER_GUARD has to do with the way // decoding is performed. In Layer III, Huffman decoding may // inadvertently read a few bytes beyond the end of the buffer in // the case of certain invalid input. This is not detected until // after the fact. To prevent this from causing problems, and // also to ensure the next frame's main_data_begin pointer is // always accessible, MAD requires MAD_BUFFER_GUARD (currently 8) // bytes to be present in the buffer past the end of the current // frame in order to decode the frame." if (bstd_file.eof()) { guard_ptr = read_start + read_size; memset(guard_ptr, 0, MAD_BUFFER_GUARD); read_size += MAD_BUFFER_GUARD; } // Pipe the new buffer content to libmad's stream decoder facility. mad_stream_buffer(&stream, input_buffer, read_size + remaining); stream.error = MAD_ERROR_NONE; } // Decode the next MPEG frame. The streams is read from the buffer, its // constituents are break down and stored the the frame structure, ready // for examination/alteration or PCM synthesis. Decoding options are // carried in the frame structure from the stream structure. // // Error handling: mad_frame_decode() returns a non zero value when an // error occurs. The error condition can be checked in the error member // of the stream structure. A mad error is recoverable or fatal, the // error status is checked with the MAD_RECOVERABLE macro. // // {4} When a fatal error is encountered all decoding activities shall // be stopped, except when a MAD_ERROR_BUFLEN is signaled. This // condition means that the mad_frame_decode() function needs more input // to complete its work. One shall refill the buffer and repeat the // mad_frame_decode() call. Some bytes may be left unused at the end of // the buffer if those bytes forms an incomplete frame. Before // refilling, the remaining bytes must be moved to the beginning of the // buffer and used for input for the next mad_frame_decode() invocation. // (See the comments marked {2} earlier for more details.) // // Recoverable errors are caused by malformed bit-streams, in this case // one can call again mad_frame_decode() in order to skip the faulty // part and re-sync to the next frame. if (mad_frame_decode(&frame, &stream)) { if (MAD_RECOVERABLE(stream.error)) { // Do not print a message if the error is a loss of // synchronization and this loss is due to the end of stream // guard bytes. (See the comment marked {3} above for more // information about guard bytes.) if (stream.error != MAD_ERROR_LOSTSYNC || stream.this_frame != guard_ptr) { // For any MP3 file we typically see two errors in the // first frame processed: // - lost synchronization // - reserved header layer value // This seems to be OK, so don't print these if (frame_count != 0) { error_stream << "\nRecoverable frame level error: " << mad_stream_errorstr(&stream) << '\n'; } } continue; } else { if (stream.error == MAD_ERROR_BUFLEN) { continue; } else { error_stream << "\nUnrecoverable frame level error: " << mad_stream_errorstr(&stream) << '\n'; status = STATUS_READ_ERROR; break; } } } // Display the characteristics of the stream's first frame. The first // frame is representative of the entire stream. if (frame_count == 0) { const int sample_rate = frame.header.samplerate; channels = MAD_NCHANNELS(&frame.header); dumpInfo(output_stream, frame.header); if (!processor.init(sample_rate, channels, OUTPUT_BUFFER_SIZE)) { status = STATUS_PROCESS_ERROR; break; } showProgress(0, file_size_); } // Accounting. The computed frame duration is in the frame header // structure. It is expressed as a fixed point number whole data type is // mad_timer_t. It is different from the samples fixed point format and // unlike it, it can't directly be added or subtracted. The timer module // provides several functions to operate on such numbers. Be careful // there, as some functions of libmad's timer module receive some of // their mad_timer_t arguments by value! frame_count++; mad_timer_add(&timer, frame.header.duration); // Once decoded the frame is synthesized to PCM samples. No errors are // reported by mad_synth_frame(); mad_synth_frame(&synth, &frame); // Synthesized samples must be converted from libmad's fixed point // number to the consumer format. Here we use signed 16 bit integers on // two channels. Integer samples are temporarily stored in a buffer that // is flushed when full. for (int i = 0; i < synth.pcm.length; i++) { // Left channel short sample = MadFixedToSshort(synth.pcm.samples[0][i]); *output_ptr++ = sample; // Right channel. If the decoded stream is monophonic then the right // output channel is the same as the left one. if (MAD_NCHANNELS(&frame.header) == 2) { sample = MadFixedToSshort(synth.pcm.samples[1][i]); *output_ptr++ = sample; } // Flush the output buffer if it is full if (output_ptr == output_buffer_end) { long pos = ftell(file_); showProgress(pos, file_size_); bool success = processor.process( output_buffer, OUTPUT_BUFFER_SIZE / channels ); if (!success) { status = STATUS_PROCESS_ERROR; break; } output_ptr = output_buffer; } } } // If the output buffer is not empty and no error occurred during the last // write, then flush it. if (output_ptr != output_buffer && status != STATUS_PROCESS_ERROR) { int buffer_size = static_cast<int>(output_ptr - output_buffer); bool success = processor.process(output_buffer, buffer_size / channels); if (!success) { status = STATUS_PROCESS_ERROR; } } // Accounting report if no error occurred. if (status == STATUS_OK) { // Report 100% done. showProgress(file_size_, file_size_); char buffer[80]; // The duration timer is converted to a human readable string with the // versatile, but still constrained mad_timer_string() function, in a // fashion not unlike strftime(). The main difference is that the timer // is broken into several values according some of its arguments. The // units and fracunits arguments specify the intended conversion to be // executed. // // The conversion unit (MAD_UNIT_MINUTES in our example) also specify // the order and kind of conversion specifications that can be used in // the format string. // // It is best to examine libmad's timer.c source-code for details of the // available units, fraction of units, their meanings, the format // arguments, etc. mad_timer_string(timer, buffer, "%lu:%02lu.%03u", MAD_UNITS_MINUTES, MAD_UNITS_MILLISECONDS, 0); output_stream << "\nFrames decoded: " << frame_count << " (" << buffer << ")\n"; } processor.done(); close(); return status == STATUS_OK; }
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; } } }
static int himd_mp3stream_split_frames(struct himd_mp3stream * stream, unsigned int databytes, unsigned int firstframe, unsigned int lastframe, struct himderrinfo * status) { int gotdata = 1; unsigned int i; struct mad_stream madstream; struct mad_header madheader; /* stream->frameptrs is NULL if the current frame has not been splitted yet */ g_warn_if_fail(stream->frameptrs == NULL); stream->frameptrs = malloc((lastframe - firstframe + 2) * sizeof stream->frameptrs[0]); if(!stream->frameptrs) { set_status_printf(status, HIMD_ERROR_OUT_OF_MEMORY, _("Can't allocate memory for %u frame pointers"), lastframe-firstframe+2); return -1; } /* parse block */ mad_stream_init(&madstream); mad_header_init(&madheader); mad_stream_buffer(&madstream, &stream->blockbuf[0x20], databytes+MAD_BUFFER_GUARD); /* drop unneeded frames in front */ while(firstframe > 0) { if(mad_header_decode(&madheader, &madstream) < 0) { set_status_printf(status, HIMD_ERROR_BAD_DATA_FORMAT, _("Still %u frames to skip: %s"), firstframe, mad_stream_errorstr(&madstream)); gotdata = 0; goto cleanup_decoder; } firstframe--; lastframe--; } /* store needed frames */ for(i = 0;i <= lastframe;i++) { if(mad_header_decode(&madheader, &madstream) < 0 && (madstream.error != MAD_ERROR_LOSTSYNC || i != lastframe)) { set_status_printf(status, HIMD_ERROR_BAD_DATA_FORMAT, _("Frame %u of %u to store: %s"), i+1, lastframe, mad_stream_errorstr(&madstream)); gotdata = 0; goto cleanup_decoder; } stream->frameptrs[i] = madstream.this_frame; } stream->frameptrs[i] = madstream.next_frame; stream->frames = lastframe+1; stream->curframe = 0; cleanup_decoder: mad_header_finish(&madheader); mad_stream_finish(&madstream); if(!gotdata) return -1; return 0; }