示例#1
0
JNIEXPORT jint JNICALL Java_com_ssb_droidsound_utils_ID3Tag_checkForTag(JNIEnv *env, jobject obj, jbyteArray bArray, jint offset, jint size)
{
	jbyte *ptr = env->GetByteArrayElements(bArray, NULL);
	int len = id3_tag_query((const id3_byte_t*)(ptr + offset), size);
	env->ReleaseByteArrayElements(bArray, ptr, 0);
	return len;
}
示例#2
0
文件: file.c 项目: flyingtime/boxee
/*
 * NAME:	query_tag()
 * DESCRIPTION:	check for a tag at a file's current position
 */
static
signed long query_tag(FILE *iofile)
{
#ifdef __APPLE__
  fpos_t save_position = 0;
#else
  fpos_t save_position = {0};
#endif
  id3_byte_t query[ID3_TAG_QUERYSIZE+2];
  signed long size = 0;

  memset(query,0, (ID3_TAG_QUERYSIZE+2) * sizeof(id3_byte_t) );

  if (fgetpos(iofile, &save_position) == -1)
  {
    return 0;
  }

  size = id3_tag_query(query, fread(query, 1, ID3_TAG_QUERYSIZE * sizeof(id3_byte_t) , iofile));
  if (fsetpos(iofile, &save_position) == -1)
  {
    return 0;
  }

  return size;
}
示例#3
0
文件: id3tag.c 项目: FLYKingdom/vlc
static void CheckHeader( demux_meta_t *p_demux_meta )
{
    const uint8_t *p_peek;
    int i_size;

    demux_t      *p_demux = (demux_t *)p_demux_meta->p_demux;

    if( stream_Seek( p_demux->s, 0 ) )
        return;

    /* Test ID3v2 first */
    if( stream_Peek( p_demux->s, &p_peek, ID3_TAG_QUERYSIZE ) != ID3_TAG_QUERYSIZE )
        return;
    i_size = id3_tag_query( p_peek, ID3_TAG_QUERYSIZE );
    if( i_size > 0 &&
        stream_Peek( p_demux->s, &p_peek, i_size ) == i_size )
    {
        msg_Dbg( p_demux, "found ID3v2 tag" );
        ParseID3Tag( p_demux_meta, p_peek, i_size );
        return;
    }

    /* Test APEv1 */
    if( stream_Peek( p_demux->s, &p_peek, APE_TAG_HEADERSIZE ) != APE_TAG_HEADERSIZE )
        return;
    i_size = GetAPEvXSize( p_peek, APE_TAG_HEADERSIZE );
    if( i_size > 0 &&
        stream_Peek( p_demux->s, &p_peek, i_size ) == i_size )
    {
        msg_Dbg( p_demux, "found APEv1/2 tag" );
        ParseAPEvXTag( p_demux_meta, p_peek, i_size );
    }
}
示例#4
0
static struct id3_tag *
tag_id3_read(FILE *stream, long offset, int whence)
{
	struct id3_tag *tag;
	id3_byte_t query_buffer[ID3_TAG_QUERYSIZE];
	id3_byte_t *tag_buffer;
	int tag_size;
	int query_buffer_size;
	int tag_buffer_size;

	/* It's ok if we get less than we asked for */
	query_buffer_size = fill_buffer(query_buffer, ID3_TAG_QUERYSIZE,
				   stream, offset, whence);
	if (query_buffer_size <= 0) return NULL;

	/* Look for a tag header */
	tag_size = id3_tag_query(query_buffer, query_buffer_size);
	if (tag_size <= 0) return NULL;

	/* Found a tag.  Allocate a buffer and read it in. */
	tag_buffer = g_malloc(tag_size);
	if (!tag_buffer) return NULL;

	tag_buffer_size = fill_buffer(tag_buffer, tag_size, stream, offset, whence);
	if (tag_buffer_size < tag_size) {
		g_free(tag_buffer);
		return NULL;
	}

	tag = id3_tag_parse(tag_buffer, tag_buffer_size);

	g_free(tag_buffer);

	return tag;
}
示例#5
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;
}
示例#6
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;
}
示例#7
0
文件: tag_id3.c 项目: azuwis/mpd
static int getId3v2FooterSize(FILE * stream, long offset, int whence)
{
	id3_byte_t buf[ID3_TAG_QUERYSIZE];
	int bufsize;

	bufsize = fillBuffer(buf, ID3_TAG_QUERYSIZE, stream, offset, whence);
	if (bufsize <= 0) return 0;
	return id3_tag_query(buf, bufsize);
}
示例#8
0
enum mad_flow input_cb(void *_data, struct mad_stream *stream)
{
   struct private_data *data = (struct private_data *)_data;

   if(data->progressCallback) {
      data->cancelled = data->progressCallback(data->userData,
                                               (float)data->file->Tell() /
                                               data->file->Length());
      if(data->cancelled)
         return MAD_FLOW_STOP;
   }

   if(data->file->Eof()) {
      data->cancelled = false;
      return MAD_FLOW_STOP;
   }

#ifdef USE_LIBID3TAG 
   if (!data->id3checked) {
      off_t read = data->file->Read(data->inputBuffer, ID3_TAG_QUERYSIZE);
      int len = id3_tag_query(data->inputBuffer, ID3_TAG_QUERYSIZE);
      if (len > 0) {
         data->file->Seek(len, wxFromCurrent);
      }
      else {
         data->file->Seek(0);
      }
      
      data->id3checked = true;
   }
#endif

   /* "Each time you refill your buffer, you need to preserve the data in
    *  your existing buffer from stream.next_frame to the end.
    *
    *  This usually amounts to calling memmove() on this unconsumed portion
    *  of the buffer and appending new data after it, before calling
    *  mad_stream_buffer()"
    *           -- Rob Leslie, on the mad-dev mailing list */

   unsigned int unconsumedBytes;
   if(stream->next_frame) {
      unconsumedBytes = data->inputBuffer + INPUT_BUFFER_SIZE - stream->next_frame;
      memmove(data->inputBuffer, stream->next_frame, unconsumedBytes);
   }
   else
      unconsumedBytes = 0;


   off_t read = data->file->Read(data->inputBuffer + unconsumedBytes,
                                 INPUT_BUFFER_SIZE - unconsumedBytes);

   mad_stream_buffer(stream, data->inputBuffer, read + unconsumedBytes);

   return MAD_FLOW_CONTINUE;
}
示例#9
0
/*
** long getTagLength(string strFile)
**
** This is a static method so that you can easily get the length of id3 tag if there is
** an id3 tag residing in the beginning of the MP3 file. This is useful when you try
** to decode a mp3 file. You can simply skip the id3 tag to the real audio data. However
** some exception exists such as a mp3 file with XING header or Lame information
*/
long CMP3ID3::getTagLength(string strFile){
	int fileID = -1;
	fileID = open(strFile.c_str(),O_RDONLY);
	if ( fileID != -1 ){
		unsigned char buffer[ID3_TAG_QUERYSIZE];
		read(fileID,(unsigned char *)buffer,ID3_TAG_QUERYSIZE);
		long lRet = id3_tag_query(buffer, ID3_TAG_QUERYSIZE);
		if ( lRet < 0 ) lRet = 0;
		close(fileID);
		return lRet;
	}
	return 0;
}
示例#10
0
/*
 * NAME:	query_tag()
 * DESCRIPTION:	check for a tag at a file's current position
 */
static
signed long query_tag(FILE *iofile)
{
  fpos_t save_position;
  id3_byte_t query[ID3_TAG_QUERYSIZE];
  signed long size;

  if (fgetpos(iofile, &save_position) == -1)
    return 0;

  size = id3_tag_query(query, fread(query, 1, sizeof(query), iofile));
  if (fsetpos(iofile, &save_position) == -1)
    return 0;

  return size;
}
示例#11
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;
}
示例#12
0
文件: mad_plugin.c 项目: azuwis/mpd
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;
}
示例#13
0
ImportFileHandle *FLACImportPlugin::Open(const wxString &filename)
{
   // First check if it really is a FLAC file

   int cnt;
   wxFile binaryFile;
   if (!binaryFile.Open(filename)) {
      return false; // File not found
   }

#ifdef USE_LIBID3TAG
   // Skip any ID3 tags that might be present
   id3_byte_t query[ID3_TAG_QUERYSIZE];
   cnt = binaryFile.Read(query, sizeof(query));
   cnt = id3_tag_query(query, cnt);
   binaryFile.Seek(cnt);
#endif

   char buf[5];
   cnt = binaryFile.Read(buf, 4);
   binaryFile.Close();

   if (cnt == wxInvalidOffset || strncmp(buf, FLAC_HEADER, 4) != 0) {
      // File is not a FLAC file
      return false;
   }

   // Open the file for import
   FLACImportFileHandle *handle = new FLACImportFileHandle(filename);

   bool success = handle->Init();
   if (!success) {
      delete handle;
      return NULL;
   }

   return handle;
}
示例#14
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;
}
示例#15
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;
        }
    }
}
/* 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;
		}
	}
}
示例#17
0
文件: id3tag.c 项目: FLYKingdom/vlc
/*****************************************************************************
 * CheckFooter: check for ID3/APE at the end of the file
 * CheckHeader: check for ID3/APE at the begining of the file
 *****************************************************************************/
static void CheckFooter( demux_meta_t *p_demux_meta )
{
    demux_t      *p_demux = (demux_t *)p_demux_meta->p_demux;
    const int64_t i_pos = stream_Size( p_demux->s );
    const size_t i_peek = 128+APE_TAG_HEADERSIZE;
    const uint8_t *p_peek;
    const uint8_t *p_peek_id3;
    int64_t i_id3v2_pos = -1;
    int64_t i_apevx_pos = -1;
    int i_id3v2_size;
    int i_apevx_size;
    size_t i_id3v1_size;

    if( i_pos < i_peek )
        return;
    if( stream_Seek( p_demux->s, i_pos - i_peek ) )
        return;

    if( stream_Peek( p_demux->s, &p_peek, i_peek ) < i_peek )
        return;
    p_peek_id3 = &p_peek[APE_TAG_HEADERSIZE];

    /* Check/Parse ID3v1 */
    i_id3v1_size = id3_tag_query( p_peek_id3, ID3_TAG_QUERYSIZE );
    if( i_id3v1_size == 128 )
    {
        msg_Dbg( p_demux, "found ID3v1 tag" );
        ParseID3Tag( p_demux_meta, p_peek_id3, i_id3v1_size );
    }

    /* Compute ID3v2 position */
    i_id3v2_size = -id3_tag_query( &p_peek_id3[128-ID3_TAG_QUERYSIZE], ID3_TAG_QUERYSIZE );
    if( i_id3v2_size > 0 )
        i_id3v2_pos = i_pos - i_id3v2_size;

    /* Compute APE2v2 position */
    i_apevx_size = GetAPEvXSize( &p_peek[128+0], APE_TAG_HEADERSIZE );
    if( i_apevx_size > 0 )
    {
        i_apevx_pos = i_pos - i_apevx_size;
    }
    else if( i_id3v1_size > 0 )
    {
        /* it can be before ID3v1 */
        i_apevx_size = GetAPEvXSize( p_peek, APE_TAG_HEADERSIZE );
        if( i_apevx_size > 0 )
            i_apevx_pos = i_pos - 128 - i_apevx_size;
    }

    if( i_id3v2_pos > 0 && i_apevx_pos > 0 )
    {
        msg_Warn( p_demux,
                  "Both ID3v2 and APEv1/2 at the end of file, ignoring APEv1/2" );
        i_apevx_pos = -1;
    }

    /* Parse ID3v2.4 */
    if( i_id3v2_pos > 0 )
    {
        if( !stream_Seek( p_demux->s, i_id3v2_pos ) &&
            stream_Peek( p_demux->s, &p_peek, i_id3v2_size ) == i_id3v2_size )
        {
            msg_Dbg( p_demux, "found ID3v2 tag at end of file" );
            ParseID3Tag( p_demux_meta, p_peek, i_id3v2_size );
        }
    }

    /* Parse APEv1/2 */
    if( i_apevx_pos > 0 )
    {
        if( !stream_Seek( p_demux->s, i_apevx_pos ) &&
            stream_Peek( p_demux->s, &p_peek, i_apevx_size ) == i_apevx_size )
        {
            msg_Dbg( p_demux, "found APEvx tag at end of file" );
            ParseAPEvXTag( p_demux_meta, p_peek, i_apevx_size );
        }
    }
}