Esempio n. 1
0
/* Attempts to read an ID3 tag at the current location in stream and
 * consume it all.  Returns -1 if no tag is found.  Its up to caller
 * to recover.  */
static int mp3_inputtag(snd_stream_t *stream)
{
	mp3_priv_t *p = (mp3_priv_t *) stream->priv;
	int rc = -1;
	size_t remaining;
	size_t tagsize;

	/* FIXME: This needs some more work if we are to ever
	 * look at the ID3 frame.  This is because the Stream
	 * may not be able to hold the complete ID3 frame.
	 * We should consume the whole frame inside tagtype()
	 * instead of outside of tagframe().  That would support
	 * recovering when Stream contains less then 8-bytes (header)
	 * and also when ID3v2 is bigger then Stream buffer size.
	 * Need to pass in stream so that buffer can be
	 * consumed as well as letting additional data to be
	 * read in.
	 */
	remaining = p->Stream.bufend - p->Stream.next_frame;
	tagsize = mp3_tagsize(p->Stream.this_frame, remaining);
	if (tagsize != 0)
	{
		mad_stream_skip(&p->Stream, tagsize);
		rc = 0;
	}

	/* We know that a valid frame hasn't been found yet
	 * so help libmad out and go back into frame seek mode.
	 * This is true whether an ID3 tag was found or not.
	 */
	mad_stream_sync(&p->Stream);

	return rc;
}
Esempio n. 2
0
static enum mad_flow handle_error(void *data, struct mad_stream *stream, struct mad_frame *frame)
{
	signed long tagsize;

	switch(stream->error)
	{
		case MAD_ERROR_BADDATAPTR:
			return MAD_FLOW_CONTINUE;
		case MAD_ERROR_LOSTSYNC:
			tagsize = id3_tag_query(stream->this_frame,stream->bufend - stream->this_frame);
			if(tagsize > 0)
			{
				mad_stream_skip(stream, tagsize);
				return MAD_FLOW_CONTINUE;
			}

		default:
			break;
	}

	if(stream->error == MAD_ERROR_BADCRC)
	{
		mad_frame_mute(frame);
		return MAD_FLOW_IGNORE;
	}

	return MAD_FLOW_CONTINUE;
}
Esempio n. 3
0
    // Attempts to read an ID3 tag at the current location in stream and
    // consume it all.  Returns SOX_EOF if no tag is found.  Its up to
    // caller to recover.
    // Returns true if a tag was found and consumed.
    //
    bool MadDecoder::consumeId3Tag()
    {
        // FIXME: This needs some more work if we are to ever
        // look at the ID3 frame.  This is because the Stream
        // may not be able to hold the complete ID3 frame.
        // We should consume the whole frame inside getId3TagSize()
        // instead of outside of tagframe().  That would support
        // recovering when Stream contains less then 8-bytes (header)
        // and also when ID3v2 is bigger then Stream buffer size.
        // Need to pass in stream so that buffer can be
        // consumed as well as letting additional data to be
        // read in.
        //
        bool result = false;

        size_t leftover = madStream_.bufend - madStream_.next_frame;
        size_t tagsize = getId3TagSize(madStream_.this_frame, leftover);
        if (tagsize > 0)
        {
            mad_stream_skip(&madStream_, tagsize);
            result = true;
        }
        /* We know that a valid frame hasn't been found yet
         * so help libmad out and go back into frame seek mode.
         * This is true whether an ID3 tag was found or not.
         */
        mad_stream_sync(&madStream_);

        return result;
    }
Esempio n. 4
0
int TrackDuration::duration(const QFileInfo &fileinfo)
{
    QString fn = fileinfo.absoluteFilePath();
    if (fn.isEmpty())
        return 0;

    QFile file(fn);
    if (!file.open(QFile::ReadOnly))
        return 0;

    mad_stream infostream;
    mad_header infoheader;
    mad_timer_t infotimer;
    mad_stream_init(&infostream);
    mad_header_init(&infoheader);
    mad_timer_reset(&infotimer);

    qint64 r;
    qint64 l = 0;
    unsigned char* buf = new unsigned char[INPUT_BUFFER_SIZE];

    while (!file.atEnd()) {
        if (l < INPUT_BUFFER_SIZE) {
            r = file.read(reinterpret_cast<char*>(buf) + l, INPUT_BUFFER_SIZE - l);
            l += r;
        }
        mad_stream_buffer(&infostream, buf, l);
        for (;;) {
            if (mad_header_decode(&infoheader, &infostream)) {
                if (!MAD_RECOVERABLE(infostream.error))
                    break;
                if (infostream.error == MAD_ERROR_LOSTSYNC) {
                    TagLib::ID3v2::Header header;
                    uint size = (uint)(infostream.bufend - infostream.this_frame);
                    if (size >= header.size()) {
                        header.setData(TagLib::ByteVector(reinterpret_cast<const char*>(infostream.this_frame), size));
                        uint tagsize = header.tagSize();
                        if (tagsize > 0) {
                            mad_stream_skip(&infostream, qMin(tagsize, size));
                            continue;
                        }
                    }
                }
                qDebug() << "header decode error while getting file info" << infostream.error;
                continue;
            }
            mad_timer_add(&infotimer, infoheader.duration);
        }
        if (infostream.error != MAD_ERROR_BUFLEN && infostream.error != MAD_ERROR_BUFPTR)
            break;
        memmove(buf, infostream.next_frame, &(buf[l]) - infostream.next_frame);
        l -= (infostream.next_frame - buf);
    }

    mad_stream_finish(&infostream);
    mad_header_finish(&infoheader);
    delete[] buf;

    return timerToMs(&infotimer);
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
int LibMadWrapper::findValidHeader(struct mad_header &header)
{
    int ret;

    while ((ret = mad_header_decode(&header, this->stream)) != 0 && MAD_RECOVERABLE(this->stream->error))
    {
        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;
            }
        }
    }

    return ret;
}
Esempio n. 7
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;
}
Esempio n. 8
0
/**
 * MP3音乐播放回调函数,
 * 负责将解码数据填充声音缓存区
 *
 * @note 声音缓存区的格式为双声道,16位低字序
 *
 * @param buf 声音缓冲区指针
 * @param reqn 缓冲区帧大小
 * @param pdata 用户数据,无用
 */
static int mp3_audiocallback(void *buf, unsigned int reqn, void *pdata)
{
	int avail_frame;
	int snd_buf_frame_size = (int) reqn;
	int ret;
	double incr;
	signed short *audio_buf = buf;
	unsigned i;
	uint16_t *output;

	UNUSED(pdata);

	if (g_status != ST_PLAYING) {
		if (handle_seek() == -1) {
			__end();
			return -1;
		}

		xAudioClearSndBuf(buf, snd_buf_frame_size);
		xrKernelDelayThread(100000);
		return 0;
	}

	while (snd_buf_frame_size > 0) {
		avail_frame = g_buff_frame_size - g_buff_frame_start;

		if (avail_frame >= snd_buf_frame_size) {
			send_to_sndbuf(audio_buf,
						   &g_buff[g_buff_frame_start * 2],
						   snd_buf_frame_size, 2);
			g_buff_frame_start += snd_buf_frame_size;
			audio_buf += snd_buf_frame_size * 2;
			snd_buf_frame_size = 0;
		} else {
			send_to_sndbuf(audio_buf,
						   &g_buff[g_buff_frame_start * 2], avail_frame, 2);
			snd_buf_frame_size -= avail_frame;
			audio_buf += avail_frame * 2;

			if (stream.buffer == NULL || stream.error == MAD_ERROR_BUFLEN) {
				size_t read_size, remaining = 0;
				uint8_t *read_start;
				int bufsize;

				if (stream.next_frame != NULL) {
					remaining = stream.bufend - stream.next_frame;
					memmove(g_input_buff, stream.next_frame, remaining);
					read_start = g_input_buff + remaining;
					read_size = BUFF_SIZE - remaining;
				} else {
					read_size = BUFF_SIZE;
					read_start = g_input_buff;
					remaining = 0;
				}

				if (mp3_data.use_buffer)
					bufsize =
						buffered_reader_read(mp3_data.r, read_start, read_size);
				else
					bufsize = xrIoRead(mp3_data.fd, read_start, read_size);

				if (bufsize <= 0) {
					__end();
					return -1;
				}
				if (bufsize < read_size) {
					uint8_t *guard = read_start + read_size;

					memset(guard, 0, MAD_BUFFER_GUARD);
					read_size += MAD_BUFFER_GUARD;
				}
				mad_stream_buffer(&stream, g_input_buff, read_size + remaining);
				stream.error = 0;
			}

			ret = mad_frame_decode(&frame, &stream);

			if (ret == -1) {
				if (MAD_RECOVERABLE(stream.error)
					|| stream.error == MAD_ERROR_BUFLEN) {
					if (stream.error == MAD_ERROR_LOSTSYNC) {
						long tagsize = id3_tag_query(stream.this_frame,
													 stream.bufend -
													 stream.this_frame);

						if (tagsize > 0) {
							mad_stream_skip(&stream, tagsize);
						}

						if (mad_header_decode(&frame.header, &stream) == -1) {
							if (stream.error != MAD_ERROR_BUFLEN) {
								if (!MAD_RECOVERABLE(stream.error)) {
									__end();
									return -1;
								}
							}
						} else {
							stream.error = MAD_ERROR_NONE;
						}
					}

					g_buff_frame_size = 0;
					g_buff_frame_start = 0;
					continue;
				} else {
					__end();
					return -1;
				}
			}

			output = &g_buff[0];

			if (stream.error != MAD_ERROR_NONE) {
				continue;
			}

			mad_synth_frame(&synth, &frame);
			for (i = 0; i < synth.pcm.length; i++) {
				signed short sample;

				if (MAD_NCHANNELS(&frame.header) == 2) {
					/* Left channel */
					sample = MadFixedToSshort(synth.pcm.samples[0][i]);
					*(output++) = sample;
					sample = MadFixedToSshort(synth.pcm.samples[1][i]);
					*(output++) = sample;
				} else {
					sample = MadFixedToSshort(synth.pcm.samples[0][i]);
					*(output++) = sample;
					*(output++) = sample;
				}
			}

			g_buff_frame_size = synth.pcm.length;
			g_buff_frame_start = 0;
			incr = frame.header.duration.seconds;
			incr +=
				mad_timer_fraction(frame.header.duration,
								   MAD_UNITS_MILLISECONDS) / 1000.0;
			g_play_time += incr;
			add_bitrate(&g_inst_br, frame.header.bitrate, incr);
		}
	}

	return 0;
}
Esempio n. 9
0
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;
        }
    }
}
Esempio n. 10
0
static void mp3_parse_id3(struct mp3_data *data, size_t tagsize,
			  struct tag **mpd_tag,
			  struct replay_gain_info **replay_gain_info_r)
{
	struct id3_tag *id3_tag = NULL;
	id3_length_t count;
	id3_byte_t const *id3_data;
	id3_byte_t *allocated = NULL;

	count = data->stream.bufend - data->stream.this_frame;

	if (tagsize <= count) {
		id3_data = data->stream.this_frame;
		mad_stream_skip(&(data->stream), tagsize);
	} else {
		allocated = g_malloc(tagsize);
		memcpy(allocated, data->stream.this_frame, count);
		mad_stream_skip(&(data->stream), count);

		while (count < tagsize) {
			size_t len;

			len = decoder_read(data->decoder, data->input_stream,
					   allocated + count, tagsize - count);
			if (len == 0)
				break;
			else
				count += len;
		}

		if (count != tagsize) {
			g_debug("error parsing ID3 tag");
			g_free(allocated);
			return;
		}

		id3_data = allocated;
	}

	id3_tag = id3_tag_parse(id3_data, tagsize);
	if (id3_tag == NULL) {
		g_free(allocated);
		return;
	}

	if (mpd_tag) {
		struct tag *tmp_tag = tag_id3_import(id3_tag);
		if (tmp_tag != NULL) {
			if (*mpd_tag != NULL)
				tag_free(*mpd_tag);
			*mpd_tag = tmp_tag;
		}
	}

	if (replay_gain_info_r) {
		struct replay_gain_info *tmp_rgi =
			parse_id3_replay_gain_info(id3_tag);
		if (tmp_rgi != NULL) {
			if (*replay_gain_info_r)
				replay_gain_info_free(*replay_gain_info_r);
			*replay_gain_info_r = tmp_rgi;
		}
	}

	id3_tag_delete(id3_tag);

	g_free(allocated);
}
Esempio n. 11
0
static void mp3_parse_id3(struct mp3_data *data, size_t tagsize,
			  struct tag **mpd_tag)
{
#ifdef HAVE_ID3TAG
	struct id3_tag *id3_tag = NULL;
	id3_length_t count;
	id3_byte_t const *id3_data;
	id3_byte_t *allocated = NULL;

	count = data->stream.bufend - data->stream.this_frame;

	if (tagsize <= count) {
		id3_data = data->stream.this_frame;
		mad_stream_skip(&(data->stream), tagsize);
	} else {
		allocated = g_malloc(tagsize);
		memcpy(allocated, data->stream.this_frame, count);
		mad_stream_skip(&(data->stream), count);

		while (count < tagsize) {
			size_t len;

			len = decoder_read(data->decoder, data->input_stream,
					   allocated + count, tagsize - count);
			if (len == 0)
				break;
			else
				count += len;
		}

		if (count != tagsize) {
			g_debug("error parsing ID3 tag");
			g_free(allocated);
			return;
		}

		id3_data = allocated;
	}

	id3_tag = id3_tag_parse(id3_data, tagsize);
	if (id3_tag == NULL) {
		g_free(allocated);
		return;
	}

	if (mpd_tag) {
		struct tag *tmp_tag = tag_id3_import(id3_tag);
		if (tmp_tag != NULL) {
			if (*mpd_tag != NULL)
				tag_free(*mpd_tag);
			*mpd_tag = tmp_tag;
		}
	}

	if (data->decoder != NULL) {
		struct replay_gain_info rgi;
		char *mixramp_start;
		char *mixramp_end;
		float replay_gain_db = 0;

		if (parse_id3_replay_gain_info(&rgi, id3_tag)) {
			replay_gain_db = decoder_replay_gain(data->decoder, &rgi);
			data->found_replay_gain = true;
		}
		if (parse_id3_mixramp(&mixramp_start, &mixramp_end, id3_tag)) {
			g_debug("setting mixramp_tags");
			decoder_mixramp(data->decoder, replay_gain_db,
					mixramp_start, mixramp_end);
		}
	}

	id3_tag_delete(id3_tag);

	g_free(allocated);
#else /* !HAVE_ID3TAG */
	(void)mpd_tag;

	/* This code is enabled when libid3tag is disabled.  Instead
	   of parsing the ID3 frame, it just skips it. */

	size_t count = data->stream.bufend - data->stream.this_frame;

	if (tagsize <= count) {
		mad_stream_skip(&data->stream, tagsize);
	} else {
		mad_stream_skip(&data->stream, count);

		while (count < tagsize) {
			size_t len = tagsize - count;
			char ignored[1024];
			if (len > sizeof(ignored))
				len = sizeof(ignored);

			len = decoder_read(data->decoder, data->input_stream,
					   ignored, len);
			if (len == 0)
				break;
			else
				count += len;
		}
	}
#endif
}
/* 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;
		}
	}
}
Esempio n. 13
0
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;
}
Esempio n. 14
0
    int64 MadDecoder::getDurationMs(unsigned char* buffer, size_t bufferSize)
    {
        struct mad_stream madStream;
        struct mad_frame  madFrame;
        struct mad_header madHeader;
        mad_timer_t  time = mad_timer_zero;

        bool depadded = false;
        bool vbr = false;
        size_t tagsize = 0;
        size_t consumed = 0;
        size_t numFrames = 0;
        size_t initialBitrate = 0;


        mad_stream_init(&madStream);
        mad_header_init(&madHeader);
        mad_frame_init(&madFrame);

        do  // Read data from the MP3 file 
        {
            int padding = 0;
            size_t leftover = madStream.bufend - madStream.next_frame;
            memcpy(buffer, madStream.this_frame, leftover);

            int bytesRead = fread(buffer + leftover, (size_t)1, bufferSize - leftover, handle_);
            if (bytesRead <= 0) {
                break;
            }
            for (; !depadded && padding < bytesRead && !buffer[padding]; ++padding);
            depadded = true;
            mad_stream_buffer(&madStream, buffer + padding, leftover + bytesRead - padding);

            while (true)   // decode frame headers 
            {
                madStream.error = MAD_ERROR_NONE;
                if (mad_header_decode(&madHeader, &madStream) == -1)
                {
                    if (madStream.error == MAD_ERROR_BUFLEN)     // Normal behaviour; get some more data from the file
                        break;
                    if (MAD_RECOVERABLE(madStream.error) == 0)
                        break;
                    if (madStream.error == MAD_ERROR_LOSTSYNC)
                    {
                        unsigned available = (madStream.bufend - madStream.this_frame);
                        tagsize = getId3TagSize(madStream.this_frame, (size_t)available);

                        if (tagsize)    // It's some ID3 tags, so just skip 
                        {
                            if (tagsize >= available) {
                                _fseeki64(handle_, (int64)(tagsize - available), SEEK_CUR);
                                depadded = false;
                            }
                            mad_stream_skip(&madStream, std::min(tagsize, available));
                        }
                    }
                    continue; // not an audio frame
                }

                mad_timer_add(&time, madHeader.duration);
                consumed += madStream.next_frame - madStream.this_frame;

                if (numFrames == 0) {
                    initialBitrate = madHeader.bitrate;

                    // Get the precise frame count from the XING header if present 
                    madFrame.header = madHeader;
                    if (mad_frame_decode(&madFrame, &madStream) == -1)
                    {
                        if (MAD_RECOVERABLE(madStream.error) == 0) {
                            break;
                        }
                    }
                    if ((numFrames = xingFrames(madStream.anc_ptr, madStream.anc_bitlen)))
                    {
                        mad_timer_multiply(&time, (signed long)numFrames);
                        break;
                    }
                }
                else {
                    vbr |= madHeader.bitrate != initialBitrate;
                }

                // If not VBR, we can time just a few frames then extrapolate (not exact!)
                if (++numFrames == 25 && !vbr)
                {
                    struct stat st;
                    fstat(fileno(handle_), &st);
                    timerMultiply(&time, (double)(st.st_size - tagsize) / consumed);
                    break;
                }
            }   // while(true)
        } while (madStream.error == MAD_ERROR_BUFLEN);

        mad_frame_finish(&madFrame);
        mad_header_finish(&madHeader);
        mad_stream_finish(&madStream);
        rewind(handle_);

        return mad_timer_count(time, MAD_UNITS_MILLISECONDS);
    }