Пример #1
0
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);
		break;
	}

	if (_stream.error != MAD_ERROR_NONE)
		_state = MP3_STATE_EOS;
}
Пример #2
0
// Seek in the stream, finding the next valid header
void Mp3PspStream::findValidHeader() {
	DEBUG_ENTER_FUNC();

	if (_state != MP3_STATE_READY)
		return;

	// If necessary, load more data into the stream decoder
	if (_stream.error == MAD_ERROR_BUFLEN)
		readMP3DataIntoBuffer();

	while (_state != MP3_STATE_EOS) {
		_stream.error = MAD_ERROR_NONE;

		// Decode the next header.
		if (mad_header_decode(&_header, &_stream) == -1) {
			if (_stream.error == MAD_ERROR_BUFLEN) {
				readMP3DataIntoBuffer();  // Read more data
				continue;
			} else if (MAD_RECOVERABLE(_stream.error)) {
				debug(6, "MP3PSPStream: Recoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream));
				continue;
			} else {
				warning("MP3PSPStream: Unrecoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream));
				break;
			}
		}

		// Sum up the total playback time so far
		mad_timer_add(&_totalTime, _header.duration);
		break;
	}

	if (_stream.error != MAD_ERROR_NONE)
		_state = MP3_STATE_EOS;
}
Пример #3
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);
}
Пример #4
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;
}
Пример #5
0
static void
scan_file (FILE * fd, int *length, int *bitrate)
{
    struct mad_stream stream;
    struct mad_header header;
    mad_timer_t timer;
    unsigned char buffer[8192];
    unsigned int buflen = 0;

    mad_stream_init (&stream);
    mad_header_init (&header);

    timer = mad_timer_zero;

    while (1)
    {
	if (buflen < 8192)
	{
            int bytes = 0;

            bytes = fread (buffer + buflen, 1, 8192 - buflen, fd);
            if (bytes <= 0)
		break;

            buflen += bytes;
	}

	mad_stream_buffer (&stream, buffer, buflen);

	while (1)
	{
            if (mad_header_decode (&header, &stream) == -1)
            {
		if (!MAD_RECOVERABLE (stream.error))
                    break;
		continue;
            }
            if (length)
		mad_timer_add (&timer, header.duration);

	}

	if (stream.error != MAD_ERROR_BUFLEN)
            break;

	memmove (buffer, stream.next_frame, &buffer[buflen] - stream.next_frame);
	buflen -= stream.next_frame - &buffer[0];
        SDL_Delay(1);
    }

    mad_header_finish (&header);
    mad_stream_finish (&stream);

    if (length)
	*length = mad_timer_count (timer, MAD_UNITS_MILLISECONDS);
}
Пример #6
0
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;
}
Пример #7
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;
}
Пример #8
0
void LibMadWrapper::open()
{
    // avoid multiple calls to open()
    if (this->infile != nullptr)
    {
        return;
    }

    this->infile = fopen(this->Filename.c_str(), "rb");
    if (this->infile == nullptr)
    {
        THROW_RUNTIME_ERROR("fopen failed, errno: " << string(strerror(errno)));
    }

    int fd = fileno(this->infile);
    this->mpeglen = getFileSize(fd);
    this->mpegbuf = static_cast<unsigned char *>(mmap(nullptr, this->mpeglen, PROT_READ, MAP_SHARED, fd, 0));
    if (this->mpegbuf == MAP_FAILED)
    {
        THROW_RUNTIME_ERROR("mmap failed for File \"" << this->Filename << ")\"");
    }


    this->stream = new struct mad_stream;
    mad_stream_init(this->stream);
    /* load buffer with MPEG audio data */
    mad_stream_buffer(this->stream, this->mpegbuf, this->mpeglen);

    // we want to know how many pcm frames there are decoded in this file
    // therefore decode header of every mpeg frame
    // pretty expensive, so only to this once
    if (this->numFrames == 0)
    {
        struct mad_header header;
        mad_header_init(&header);

        // try to find a valid header
        int ret = this->findValidHeader(header);
        if (ret != 0)
        {
            // only free the locally used header here, this->stream and this->mpegbuf are freed in LibMadWrapper::close()
            mad_header_finish(&header);

            THROW_RUNTIME_ERROR("unable to find a valid frame-header for File \"" + this->Filename + "\"");
        }

        this->Format.SetVoices(1);
        // a first valid header is good, but it may contain garbage
        this->Format.VoiceChannels[0] = MAD_NCHANNELS(&header);
        this->Format.SampleRate = header.samplerate;
        CLOG(LogLevel_t::Debug, "found a first valid header within File \"" << this->Filename << "\"\n\tchannels: " << MAD_NCHANNELS(&header) << "\nsrate: " << header.samplerate);

        // no clue what this 32 does
        // stolen from mad_synth_frame() in synth.c
        this->numFrames += 32 * MAD_NSBSAMPLES(&header);

        // try to find a second valid header
        ret = this->findValidHeader(header);
        if (ret == 0)
        {
            // better use format infos from this header
            this->Format.VoiceChannels[0] = max<int>(MAD_NCHANNELS(&header), this->Format.VoiceChannels[0]);
            this->Format.SampleRate = header.samplerate;
            CLOG(LogLevel_t::Debug, "found a second valid header within File \"" << this->Filename << "\"\n\tchannels: " << MAD_NCHANNELS(&header) << "\nsrate: " << header.samplerate);

            this->numFrames += 32 * MAD_NSBSAMPLES(&header);

            // now lets go on and decode rest of file
            while (1)
            {
                if (mad_header_decode(&header, this->stream) != 0)
                {
                    if (MAD_RECOVERABLE(this->stream->error))
                    {
                        continue;
                    }
                    else
                    {
                        break;
                    }
                }

                // sanity checks
                if (this->Format.Channels() != MAD_NCHANNELS(&header))
                {
                    CLOG(LogLevel_t::Warning, "channelcount varies (now: " << MAD_NCHANNELS(&header) << ") within File \"" << this->Filename << ")\"");

                    if (!gConfig.MadPermissive)
                    {
                        THROW_RUNTIME_ERROR("invalid mp3: channelcount varies");
                    }
                }

                if (this->Format.SampleRate != header.samplerate)
                {
                    CLOG(LogLevel_t::Warning, "samplerate varies (now: " << header.samplerate << ") within File \"" << this->Filename << ")\"");

                    if (!gConfig.MadPermissive)
                    {
                        THROW_RUNTIME_ERROR("invalid mp3: samplerate varies");
                    }
                }

                this->numFrames += 32 * MAD_NSBSAMPLES(&header);
            }
        }
        else
        {
            CLOG(LogLevel_t::Warning, "only one valid header found, probably no valid mp3 File \"" << this->Filename << "\"");
        }

        // somehow reset libmad stream
        mad_stream_finish(this->stream);
        mad_stream_init(this->stream);
        /* load buffer with MPEG audio data */
        mad_stream_buffer(this->stream, this->mpegbuf, this->mpeglen);

        mad_header_finish(&header);
    }

    this->frame.hasValue = true;
    mad_frame_init(&this->frame.Value);

    this->synth.hasValue = true;
    mad_synth_init(&this->synth.Value);
}
Пример #9
0
/* Following two functions are adapted from mad_timer, from the 
   libmad distribution */
void scan(void const *ptr, ssize_t len, buffer *buf)
{
    struct mad_stream stream;
    struct mad_header header;
    struct xing xing;
    
    unsigned long bitrate = 0;
    int has_xing = 0;
    int is_vbr = 0;

    mad_stream_init(&stream);
    mad_header_init(&header);

    mad_stream_buffer(&stream, ptr, len);

    buf->num_frames = 0;

    /* 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)
    {
        if (mad_header_decode(&header, &stream) == -1)
        {
            if (MAD_RECOVERABLE(stream.error))
                continue;
            else
                break;
        }

        /* Limit xing testing to the first frame header */
        if (!buf->num_frames++)
        {
            if(parse_xing(&xing, stream.anc_ptr, stream.anc_bitlen))
            {
                is_vbr = 1;
                
                if (xing.flags & XING_FRAMES)
                {
                    /* We use the Xing tag only for frames. If it doesn't have that
                       information, it's useless to us and we have to treat it as a
                       normal VBR file */
                    has_xing = 1;
                    buf->num_frames = xing.frames;
                    break;
                }
            }
        }                

        /* Test the first n frames to see if this is a VBR file */
        if (!is_vbr && !(buf->num_frames > 20))
        {
            if (bitrate && header.bitrate != bitrate)
            {
                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)
        {
            break;
        }
            
        mad_timer_add(&buf->duration, header.duration);
    }

    if (!is_vbr)
    {
        double time = (len * 8.0) / (header.bitrate); /* time in seconds */
        double timefrac = (double)time - ((long)(time));
        long nsamples = 32 * MAD_NSBSAMPLES(&header); /* samples per frame */
        
        /* samplerate is a constant */
        buf->num_frames = (long) (time * header.samplerate / nsamples);

        mad_timer_set(&buf->duration, (long)time, (long)(timefrac*100), 100);
    }
        
    else if (has_xing)
    {
        /* modify header.duration since we don't need it anymore */
        mad_timer_multiply(&header.duration, buf->num_frames);
        buf->duration = header.duration;
    }

    else
    {
        /* the durations have been added up, and the number of frames
           counted. We do nothing here. */
    }
    
    mad_header_finish(&header);
    mad_stream_finish(&stream);
}
Пример #10
0
static int get_format(bgav_stream_t * s)
  {
  mad_priv_t * priv;
  const char * version_string;

  struct mad_header h;
  
  priv = s->decoder_priv;

  mad_header_init(&h);
  mad_header_decode(&h, &priv->stream);
  
  /* Get audio format and create frame */

  s->data.audio.format.samplerate = h.samplerate;

  if(h.mode == MAD_MODE_SINGLE_CHANNEL)
    s->data.audio.format.num_channels = 1;
  else
    s->data.audio.format.num_channels = 2;
    
  s->data.audio.format.samplerate = h.samplerate;
  s->data.audio.format.sample_format = GAVL_SAMPLE_FLOAT;
  s->data.audio.format.interleave_mode = GAVL_INTERLEAVE_NONE;
  s->data.audio.format.samples_per_frame =
    MAD_NSBSAMPLES(&h) * 32;

  if(!s->codec_bitrate)
    {
    if(s->container_bitrate == GAVL_BITRATE_VBR)
      s->codec_bitrate = GAVL_BITRATE_VBR;
    else
      s->codec_bitrate = h.bitrate;
    }
  gavl_set_channel_setup(&s->data.audio.format);

  if(h.flags & MAD_FLAG_MPEG_2_5_EXT)
    {
    if(h.layer == 3)
      s->data.audio.preroll = s->data.audio.format.samples_per_frame * 30;
    else
      s->data.audio.preroll = s->data.audio.format.samples_per_frame;
    version_string = "2.5";
    }
  else if(h.flags & MAD_FLAG_LSF_EXT)
    {
    if(h.layer == 3)
      s->data.audio.preroll = s->data.audio.format.samples_per_frame * 30;
    else
      s->data.audio.preroll = s->data.audio.format.samples_per_frame;
    version_string = "2";
    }
  else
    {
    if(h.layer == 3)
      s->data.audio.preroll = s->data.audio.format.samples_per_frame * 10;
    else
      s->data.audio.preroll = s->data.audio.format.samples_per_frame;
    version_string = "1";
    }
  
  gavl_metadata_set_nocpy(&s->m, GAVL_META_FORMAT,
                          bgav_sprintf("MPEG-%s layer %d",
                                       version_string, h.layer));
  
  priv->audio_frame = gavl_audio_frame_create(&s->data.audio.format);
  return 1;
  }
Пример #11
0
static int mad_frame_seek(input_object *obj, int frame)
{
	struct mad_local_data *data;
	struct mad_header header;
	int skip;
	ssize_t byte_offset;

	if (!obj)
		return 0;
	data = (struct mad_local_data *)obj->local_data;

	if (!data || !data->seekable)
		return 0;

	//alsaplayer_error("frame_seek(..., %d)", frame);
	mad_header_init(&header);

	data->bytes_avail = 0;
	if (frame <= data->highest_frame) {
		skip = 0;

		if (frame > 4) {
			skip = 3;
		}
		byte_offset = data->frames[frame-skip];

		/* Prepare the buffer for a read */
		fill_buffer(data, byte_offset);
		mad_stream_buffer(&data->stream, data->mad_map, data->bytes_avail);
		skip++;
		while (skip != 0) {
			skip--;

			mad_frame_decode(&data->frame, &data->stream);
			if (skip == 0)
				mad_synth_frame (&data->synth, &data->frame);
		}
		data->bytes_avail = data->stream.bufend - 
			data->stream.next_frame;
		data->current_frame = frame;
		data->seeking = 0;
		return data->current_frame;
	}

	data->seeking = 1;
	fill_buffer(data, data->frames[data->highest_frame]);
	mad_stream_buffer(&data->stream, data->mad_map, data->bytes_avail);
	while (data->highest_frame < frame) {
		if (data->bytes_avail < 3072) {
			fill_buffer(data, data->map_offset + MAD_BUFSIZE - data->bytes_avail);
			mad_stream_buffer(&data->stream, data->mad_map, data->bytes_avail);
		}	
		if (mad_header_decode(&header, &data->stream) == -1) {
			if (!MAD_RECOVERABLE(data->stream.error)) {
				fill_buffer(data, 0);
				mad_stream_buffer(&data->stream, data->mad_map, data->bytes_avail);
				data->seeking = 0;
				return 0;
			}				
		}
		data->frames[++data->highest_frame] =
			data->map_offset + data->stream.this_frame - data->mad_map;
		data->bytes_avail = data->stream.bufend - data->stream.next_frame;
	}

	data->current_frame = data->highest_frame;
	if (data->current_frame > 4) {
		skip = 3;
		fill_buffer(data, data->frames[data->current_frame-skip]);
		mad_stream_buffer(&data->stream, data->mad_map, data->bytes_avail);
		skip++;
		while (skip != 0) { 
			skip--;
			mad_frame_decode(&data->frame, &data->stream);
			if (skip == 0) 
				mad_synth_frame (&data->synth, &data->frame);
			data->bytes_avail = data->stream.bufend -
				data->stream.next_frame;
		}
	}

	data->seeking = 0;
	return data->current_frame;

	return 0;
}
/* 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;
		}
	}
}
Пример #13
0
static void 
MP3_getInfo()
{
    int FrameCount = 0;
    struct mad_stream stream;
    struct mad_header header; 
    mad_stream_init (&stream);
    mad_header_init (&header);

    MP3_info.fileSize = size;
    mad_timer_reset(&MP3_info.length);
    mad_stream_buffer (&stream, mp3_data, size);
    while (1){
        if (mad_header_decode (&header, &stream) == -1){
            if (MAD_RECOVERABLE(stream.error)){
                continue;                
            }else{
                break;
            }
        }
        //Informazioni solo dal primo frame:
        if (FrameCount == 0){
            switch (header.layer) {
            case MAD_LAYER_I:
                strcpy(MP3_info.layer,"I");
                break;
            case MAD_LAYER_II:
                strcpy(MP3_info.layer,"II");
                break;
            case MAD_LAYER_III:
                strcpy(MP3_info.layer,"III");
                break;
            default:
                strcpy(MP3_info.layer,"unknown");
                break;
            }

            MP3_info.kbit = header.bitrate / 1000;
            MP3_info.hz = header.samplerate;
            switch (header.mode) {
            case MAD_MODE_SINGLE_CHANNEL:
                strcpy(MP3_info.mode, "single channel");
                break;
            case MAD_MODE_DUAL_CHANNEL:
                strcpy(MP3_info.mode, "dual channel");
                break;
            case MAD_MODE_JOINT_STEREO:
                strcpy(MP3_info.mode, "joint (MS/intensity) stereo");
                break;
            case MAD_MODE_STEREO:
                strcpy(MP3_info.mode, "normal LR stereo");
                break;
            default:
                strcpy(MP3_info.mode, "unknown");
                break;
            }

            switch (header.emphasis) {
            case MAD_EMPHASIS_NONE:
                strcpy(MP3_info.emphasis,"no");
                break;
            case MAD_EMPHASIS_50_15_US:
                strcpy(MP3_info.emphasis,"50/15 us");
                break;
            case MAD_EMPHASIS_CCITT_J_17:
                strcpy(MP3_info.emphasis,"CCITT J.17");
                break;
            case MAD_EMPHASIS_RESERVED:
                strcpy(MP3_info.emphasis,"reserved(!)");
                break;
            default:
                strcpy(MP3_info.emphasis,"unknown");
                break;
            }            
        }
        FrameCount++;
        mad_timer_add (&MP3_info.length, header.duration);
    }
    mad_header_finish (&header);
    mad_stream_finish (&stream);

    MP3_info.frames = FrameCount;
    mad_timer_string(MP3_info.length, MP3_info.strLength, "%02lu:%02u:%02u", MAD_UNITS_HOURS, MAD_UNITS_MILLISECONDS, 0);
}
Пример #14
0
static
	int run_sync(struct mad_decoder *decoder)
{

	/*
	if (decoder->input_func == 0)
	return 0;

	if (decoder->error_func) {
	error_func = decoder->error_func;
	//error_data = decoder->cb_data;
	}
	else {
	error_func = error_default;
	error_data = &bad_last_frame;
	}

	stream = &decoder->sync->stream;
	frame  = &decoder->sync->frame;
	synth  = &decoder->sync->synth;

	mad_stream_init(stream);
	mad_frame_init(frame);
	mad_synth_init(synth);

	mad_stream_options(stream, decoder->options);
	*/
	do {
		switch (decoder->input_func(decoder->cb_data, stream)) {
		case MAD_FLOW_STOP:
			goto done;
		case MAD_FLOW_BREAK:
			goto fail;
		case MAD_FLOW_IGNORE:
			continue;
		case MAD_FLOW_CONTINUE:
			break;
		}

		while (1) {
# if defined(USE_ASYNC)
			if (decoder->mode == MAD_DECODER_MODE_ASYNC) {
				switch (check_message(decoder)) {
				case MAD_FLOW_IGNORE:
				case MAD_FLOW_CONTINUE:
					break;
				case MAD_FLOW_BREAK:
					goto fail;
				case MAD_FLOW_STOP:
					goto done;
				}
			}
# endif

			if (decoder->header_func) {
				if (mad_header_decode(&frame->header, stream) == -1) {
					if (!MAD_RECOVERABLE(stream->error))
						break;

					switch (error_func(decoder->cb_data, stream, frame)) {
					case MAD_FLOW_STOP:
						goto done;
					case MAD_FLOW_BREAK:
						goto fail;
					case MAD_FLOW_IGNORE:
					case MAD_FLOW_CONTINUE:
					default:
						continue;
					}
				}

				switch (decoder->header_func(decoder->cb_data, &frame->header)) {
				case MAD_FLOW_STOP:
					goto done;
				case MAD_FLOW_BREAK:
					goto fail;
				case MAD_FLOW_IGNORE:
					continue;
				case MAD_FLOW_CONTINUE:
					break;
				}
			}

			if (mad_frame_decode(frame, stream) == -1) {
				if (!MAD_RECOVERABLE(stream->error))
					break;

				switch (error_func(decoder->cb_data, stream, frame)) {
				case MAD_FLOW_STOP:
					goto done;
				case MAD_FLOW_BREAK:
					goto fail;
				case MAD_FLOW_IGNORE:
					break;
				case MAD_FLOW_CONTINUE:
				default:
					continue;
				}
			}
			else
				bad_last_frame = 0;

			if (decoder->filter_func) {
				switch (decoder->filter_func(decoder->cb_data, stream, frame)) {
				case MAD_FLOW_STOP:
					goto done;
				case MAD_FLOW_BREAK:
					goto fail;
				case MAD_FLOW_IGNORE:
					continue;
				case MAD_FLOW_CONTINUE:
					break;
				}
			}

			mad_synth_frame(synth, frame);

			if (decoder->output_func) {
				switch (decoder->output_func(decoder->cb_data,
					&frame->header, &synth->pcm)) {
				case MAD_FLOW_STOP:
					goto done;
				case MAD_FLOW_BREAK:
					goto fail;
				case MAD_FLOW_IGNORE:
				case MAD_FLOW_CONTINUE:
					break;
				}
			}
		}
	}
	while (stream->error == MAD_ERROR_BUFLEN);

fail:
	result = -1;

done:
	/*
	mad_synth_finish(synth);
	mad_frame_finish(frame);
	mad_stream_finish(stream);
	*/
	//return result;
	return stream->this_frame - stream->buffer;
}
Пример #15
0
static
int run_sync(struct mad_decoder *decoder)
{
  enum mad_flow (*error_func)(void *, struct mad_stream *, struct mad_frame *);
  void *error_data;
  int bad_last_frame = 0;
  struct mad_stream *stream;
  struct mad_frame *frame;
  struct mad_synth *synth;
  int result = 0;

  if (decoder->input_func == 0)
    return 0;

  if (decoder->error_func) {
    error_func = decoder->error_func;
    error_data = decoder->cb_data;
  }
  else {
    error_func = error_default;
    error_data = &bad_last_frame;
  }

  stream = &decoder->sync->stream;
  frame  = &decoder->sync->frame;
  synth  = &decoder->sync->synth;

  mad_stream_init(stream);
  mad_frame_init(frame);
  mad_synth_init(synth);

  mad_stream_options(stream, decoder->options);

  do {
    switch (decoder->input_func(decoder->cb_data, stream)) {
    case MAD_FLOW_STOP:
      goto done;
    case MAD_FLOW_BREAK:
      goto fail;
    case MAD_FLOW_IGNORE:
      continue;
    case MAD_FLOW_CONTINUE:
      break;
    }

    while (1) {

      if (decoder->header_func) {
	if (mad_header_decode(&frame->header, stream) == -1) {
	  if (!MAD_RECOVERABLE(stream->error))
	    break;

	  switch (error_func(error_data, stream, frame)) {
	  case MAD_FLOW_STOP:
	    goto done;
	  case MAD_FLOW_BREAK:
	    goto fail;
	  case MAD_FLOW_IGNORE:
	  case MAD_FLOW_CONTINUE:
	  default:
	    continue;
	  }
	}

	switch (decoder->header_func(decoder->cb_data, &frame->header)) {
	case MAD_FLOW_STOP:
	  goto done;
	case MAD_FLOW_BREAK:
	  goto fail;
	case MAD_FLOW_IGNORE:
	  continue;
	case MAD_FLOW_CONTINUE:
	  break;
	}
      }

      if (mad_frame_decode(frame, stream) == -1) {
	if (!MAD_RECOVERABLE(stream->error))
	  break;

	switch (error_func(error_data, stream, frame)) {
	case MAD_FLOW_STOP:
	  goto done;
	case MAD_FLOW_BREAK:
	  goto fail;
	case MAD_FLOW_IGNORE:
	  break;
	case MAD_FLOW_CONTINUE:
	default:
	  continue;
	}
      }
      else
	bad_last_frame = 0;

      if (decoder->filter_func) {
	switch (decoder->filter_func(decoder->cb_data, stream, frame)) {
	case MAD_FLOW_STOP:
	  goto done;
	case MAD_FLOW_BREAK:
	  goto fail;
	case MAD_FLOW_IGNORE:
	  continue;
	case MAD_FLOW_CONTINUE:
	  break;
	}
      }

      mad_synth_frame(synth, frame);

      if (decoder->output_func) {
	switch (decoder->output_func(decoder->cb_data,
				     &frame->header, &synth->pcm)) {
	case MAD_FLOW_STOP:
	  goto done;
	case MAD_FLOW_BREAK:
	  goto fail;
	case MAD_FLOW_IGNORE:
	case MAD_FLOW_CONTINUE:
	  break;
	}
      }
    }
  }
  while (stream->error == MAD_ERROR_BUFLEN);

 fail:
  result = -1;

 done:
  mad_synth_finish(synth);
  mad_frame_finish(frame);
  mad_stream_finish(stream);

  return result;
}
Пример #16
0
//Get info on file:
//Uso LibMad per calcolare la durata del pezzo perché
//altrimenti dovrei gestire il buffer anche nella seekNextFrame (senza è troppo lenta).
//E' una porcheria ma è più semplice. :)
int MP3MEgetInfo(){
	unsigned long FrameCount = 0;
    int fd = -1;
    int bufferSize = 1024*496;
    u8 *localBuffer;
    long singleDataRed = 0;
	struct mad_stream stream;
	struct mad_header header;
    int timeFromID3 = 0;
    float mediumBitrate = 0.0f;
    int has_xing = 0;
    struct xing xing;
	memset(&xing, 0, sizeof(xing));

    if (!MP3ME_tagRead)
        getMP3METagInfo(MP3ME_fileName, &MP3ME_info);

	mad_stream_init (&stream);
	mad_header_init (&header);

    fd = sceIoOpen(MP3ME_fileName, PSP_O_RDONLY, 0777);
    if (fd < 0)
        return -1;

	long size = sceIoLseek(fd, 0, PSP_SEEK_END);
    sceIoLseek(fd, 0, PSP_SEEK_SET);

    MP3ME_tagsize = ID3v2TagSize(MP3ME_fileName);
	double startPos = MP3ME_tagsize;
	sceIoLseek32(fd, startPos, PSP_SEEK_SET);

    //Check for xing frame:
	unsigned char *xing_buffer;
	xing_buffer = (unsigned char *)malloc(XING_BUFFER_SIZE);
	if (xing_buffer != NULL)
	{
        sceIoRead(fd, xing_buffer, XING_BUFFER_SIZE);
        if(parse_xing(xing_buffer, 0, &xing))
        {
            if (xing.flags & XING_FRAMES && xing.frames){
                has_xing = 1;
                bufferSize = 50 * 1024;
            }
        }
        free(xing_buffer);
        xing_buffer = NULL;
    }

    size -= startPos;

    if (size < bufferSize * 3)
        bufferSize = size;
    localBuffer = (unsigned char *) malloc(sizeof(unsigned char)  * bufferSize);
    unsigned char *buff = localBuffer;

    MP3ME_info.fileType = MP3_TYPE;
    MP3ME_info.defaultCPUClock = MP3ME_defaultCPUClock;
    MP3ME_info.needsME = 1;
	MP3ME_info.fileSize = size;
	MP3ME_filesize = size;
    MP3ME_info.framesDecoded = 0;

    double totalBitrate = 0;
    int i = 0;

	for (i=0; i<3; i++){
        memset(localBuffer, 0, bufferSize);
        singleDataRed = sceIoRead(fd, localBuffer, bufferSize);
    	mad_stream_buffer (&stream, localBuffer, singleDataRed);

        while (1){
    		if (mad_header_decode (&header, &stream) == -1){
                if (stream.buffer == NULL || stream.error == MAD_ERROR_BUFLEN)
                    break;
    			else if (MAD_RECOVERABLE(stream.error)){
    				continue;
    			}else{
    				break;
    			}
    		}
    		//Informazioni solo dal primo frame:
    	    if (FrameCount++ == 0){
    			switch (header.layer) {
    			case MAD_LAYER_I:
    				strcpy(MP3ME_info.layer,"I");
    				break;
    			case MAD_LAYER_II:
    				strcpy(MP3ME_info.layer,"II");
    				break;
    			case MAD_LAYER_III:
    				strcpy(MP3ME_info.layer,"III");
    				break;
    			default:
    				strcpy(MP3ME_info.layer,"unknown");
    				break;
    			}

    			MP3ME_info.kbit = header.bitrate / 1000;
    			MP3ME_info.instantBitrate = header.bitrate;
    			MP3ME_info.hz = header.samplerate;
    			switch (header.mode) {
    			case MAD_MODE_SINGLE_CHANNEL:
    				strcpy(MP3ME_info.mode, "single channel");
    				break;
    			case MAD_MODE_DUAL_CHANNEL:
    				strcpy(MP3ME_info.mode, "dual channel");
    				break;
    			case MAD_MODE_JOINT_STEREO:
    				strcpy(MP3ME_info.mode, "joint (MS/intensity) stereo");
    				break;
    			case MAD_MODE_STEREO:
    				strcpy(MP3ME_info.mode, "normal LR stereo");
    				break;
    			default:
    				strcpy(MP3ME_info.mode, "unknown");
    				break;
    			}

    			switch (header.emphasis) {
    			case MAD_EMPHASIS_NONE:
    				strcpy(MP3ME_info.emphasis,"no");
    				break;
    			case MAD_EMPHASIS_50_15_US:
    				strcpy(MP3ME_info.emphasis,"50/15 us");
    				break;
    			case MAD_EMPHASIS_CCITT_J_17:
    				strcpy(MP3ME_info.emphasis,"CCITT J.17");
    				break;
    			case MAD_EMPHASIS_RESERVED:
    				strcpy(MP3ME_info.emphasis,"reserved(!)");
    				break;
    			default:
    				strcpy(MP3ME_info.emphasis,"unknown");
    				break;
    			}

    			//Check if lenght found in tag info:
                if (MP3ME_info.length > 0){
                    timeFromID3 = 1;
                    break;
                }
                if (has_xing)
                    break;
            }

            totalBitrate += header.bitrate;
		}
        if (size == bufferSize)
            break;
        else if (i==0)
            sceIoLseek(fd, startPos + size/3, PSP_SEEK_SET);
        else if (i==1)
            sceIoLseek(fd, startPos + 2 * size/3, PSP_SEEK_SET);

        if (timeFromID3 || has_xing)
            break;
	}
	mad_header_finish (&header);
	mad_stream_finish (&stream);
    if (buff){
    	free(buff);
        buff = NULL;
    }
    sceIoClose(fd);

    int secs = 0;
    if (has_xing)
    {
        /* modify header.duration since we don't need it anymore */
        mad_timer_multiply(&header.duration, xing.frames);
        secs = mad_timer_count(header.duration, MAD_UNITS_SECONDS);
		MP3ME_info.length = secs;
	}
    else if (!MP3ME_info.length){
		mediumBitrate = totalBitrate / (float)FrameCount;
		secs = size * 8 / mediumBitrate;
        MP3ME_info.length = secs;
    }else{
        secs = MP3ME_info.length;
    }

	//Formatto in stringa la durata totale:
	int h = secs / 3600;
	int m = (secs - h * 3600) / 60;
	int s = secs - h * 3600 - m * 60;
	snprintf(MP3ME_info.strLength, sizeof(MP3ME_info.strLength), "%2.2i:%2.2i:%2.2i", h, m, s);

    return 0;
}
Пример #17
0
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;
}
Пример #18
0
// This is a shorter and faster version of scanFile(), that only scans the samplerate and number of Channels of the stream.
void mpgDecoder::readMetaFromFile( playListItem * pli )
{
#ifdef HAVE_MAD
	// use QFile as input Buffer, which is needed by libMad, cause it cannot detect EOF....
	QFile madFile(pli->getFile());
	madFile.open( QIODevice::ReadOnly );

	unsigned char buffer[65536];

	mad_stream scanStream;
	mad_header scanHeader;

	mad_stream_init (&scanStream);
	mad_header_init (&scanHeader);

	// get some more Byte from File...
	int readCnt = 0;
	while( !madFile.atEnd() && readCnt < 65536 )
	{
                buffer[readCnt] = madFile.read(1).at(0);
		readCnt++;
	}

	if (madFile.atEnd())
		return;

	mad_stream_buffer (&scanStream, buffer, readCnt );

	while (1)
        {
		if (mad_header_decode (&scanHeader, &scanStream) == -1)
		{
			if (scanStream.error == MAD_ERROR_BUFLEN)
				break;
			if (!MAD_RECOVERABLE (scanStream.error))
				break;
			continue;
		}
	}
	pli->setSamplerate( scanHeader.samplerate );
	pli->setChannels( MAD_NCHANNELS(&scanHeader) );

	mad_header_finish (&scanHeader);
	mad_stream_finish (&scanStream);
#endif
// read ID3 Metadata
#ifdef HAVE_ID3TAG
    id3_file* id3f = id3_file_open( pli->getFile().toAscii(), ID3_FILE_MODE_READONLY );
    id3_tag* id3 = id3_file_tag( id3f );

    // only overwrite metadata of playlist-item if files contains own ones...
    QString temp = getID3String(id3, ID3_FRAME_ARTIST);
    if(!temp.isEmpty())
        pli->setArtist( temp );

    temp = getID3String(id3, ID3_FRAME_TITLE);
    if(!temp.isEmpty())
        pli->setTitle( temp );

    temp = getID3String(id3, ID3_FRAME_GENRE);
    if(!temp.isEmpty())
        pli->setGenre( temp );
    id3_file_close( id3f );

#endif
}
Пример #19
0
// the following function has been copied from XMMS' mad input plugin
// Copyright (C) 2001-2002 Sam Clegg
void mpgDecoder::scanFile( )
{
#ifdef HAVE_MAD
  mad_stream scanStream;
  mad_header scanHeader;
  int remainder = 0;
  int data_used = 0;
  int pos = 0;
  unsigned char buffer[4096];

  // reset file, so we can read from the beginning
  madFile->reset();
  mad_timer_reset( endPositionTimer );

  mad_stream_init (&scanStream);
  mad_header_init (&scanHeader);
  while (1)
    {
      remainder = scanStream.bufend - scanStream.next_frame;
      memcpy (buffer, scanStream.this_frame, remainder);
	// get some more Byte from File...
	int readCnt = 0;
	unsigned char* readStart;
	readStart = buffer+remainder;
	while( !madFile->atEnd() && readCnt < (4096 - remainder) )
	{
                readStart[readCnt] = madFile->read(1).at(0);
		readCnt++;
	}

      if (madFile->atEnd())
	break;

      mad_stream_buffer (&scanStream, buffer, readCnt + remainder);

      while (1)
        {
	  if (mad_header_decode (&scanHeader, &scanStream) == -1)
	    {
	      if (scanStream.error == MAD_ERROR_BUFLEN)
		{
		  break;
		}
	      if (!MAD_RECOVERABLE (scanStream.error))
		{
		  break;
		}
	      continue;
	    }
	  pos++;
	  data_used += scanStream.next_frame - scanStream.this_frame;
      mad_timer_add( endPositionTimer, scanHeader.duration );
	  if (pos == 1)
	    {
          sampleRate = scanHeader.samplerate;
	      channels = MAD_NCHANNELS(&scanHeader);
	    }
	}
      if (scanStream.error != MAD_ERROR_BUFLEN)
	break;
    }

  mad_header_finish (&scanHeader);
  mad_stream_finish (&scanStream);

  // reset the file again, so we can read from the beginning when playing
  madFile->reset();
#endif
}
Пример #20
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);
    }
Пример #21
0
/**
 * 搜索下一个有效MP3 frame
 *
 * @return
 * - <0 失败
 * - 0 成功
 */
static int seek_valid_frame(void)
{
	int cnt = 0;
	int ret;

	mad_stream_finish(&stream);
	mad_stream_init(&stream);

	do {
		cnt++;
		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) {
				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;
		}

		if ((ret = mad_header_decode(&frame.header, &stream)) == -1) {
			/*
			 * MAD_ERROR_BUFLEN should be ignored
			 *
			 * We haven't reached the EOF as long as xrIoRead returned positive.
			 */
			if (!MAD_RECOVERABLE(stream.error) && stream.error != MAD_ERROR_BUFLEN) {
				return -1;
			}
		} else {
			ret = 0;
			stream.error = 0;
		}
	} while (!(ret == 0 && stream.sync == 1));
	dbg_printf(d, "%s: tried %d times", __func__, cnt);

	return 0;
}
Пример #22
0
static int mad_open(input_object *obj, const char *path)
{
	struct mad_local_data *data;
	char *p;
	int mode;

	if (!obj)
		return 0;

	obj->local_data = malloc(sizeof(struct mad_local_data));
	if (!obj->local_data) {
		puts("failed to allocate local data");
		return 0;
	}
	data = (struct mad_local_data *)obj->local_data;
	memset(data, 0, sizeof(struct mad_local_data));

	if ((data->mad_fd = reader_open(path, &reader_status, obj)) == NULL) {
		fprintf(stderr, "mad_open(obj, %s) failed\n", path);
		free(obj->local_data);
		obj->local_data = NULL;
		return 0;
	}
	obj->flags = 0;

	if (strncasecmp(path, "http://", 7) == 0) {
		obj->flags |= P_STREAMBASED;
		strcpy(data->sinfo.status, "Prebuffering");
	} else {
		obj->flags |= P_FILEBASED;
	}
	if (!reader_seekable(data->mad_fd)) {
		data->seekable = 0;
	} else {
		obj->flags |= P_SEEK;
		obj->flags |= P_PERFECTSEEK;
		data->seekable = 1;
	}
	obj->flags |= P_REENTRANT;

	mad_init_decoder(data);
	memset(&data->xing, 0, sizeof(struct xing));
	xing_init (&data->xing);
	data->mad_init = 1;
	fill_buffer(data, -1);
	//alsaplayer_error("initial bytes_avail = %d", data->bytes_avail);
	if (obj->flags & P_PERFECTSEEK) {
		data->offset = find_initial_frame(data->mad_map, 
				data->bytes_avail < STREAM_BUFFER_SIZE ? data->bytes_avail :
				STREAM_BUFFER_SIZE);
	} else {
		data->offset = 0;
	}	
	data->highest_frame = 0;
	if (data->offset < 0) {
		//fprintf(stderr, "mad_open() couldn't find valid MPEG header\n");
		data->offset = 0;
	}
	//alsaplayer_error("data->offset = %d", data->offset);
	if (data->offset > data->bytes_avail) {
		data->seekable = 1;
		//alsaplayer_error("Need to refill buffer (data->offset = %d)", data->offset);
		fill_buffer(data, 0);
		mad_stream_buffer(&data->stream, data->mad_map, data->bytes_avail);
	} else {
		mad_stream_buffer(&data->stream, data->mad_map + data->offset,
				data->bytes_avail - data->offset);
		data->bytes_avail -= data->offset;
	}	
first_frame:

	if ((mad_header_decode(&data->frame.header, &data->stream) == -1)) {
		switch (data->stream.error) {
			case MAD_ERROR_BUFLEN:
				return 0;
			case MAD_ERROR_LOSTSYNC:
			case MAD_ERROR_BADEMPHASIS:
			case MAD_ERROR_BADBITRATE:
			case MAD_ERROR_BADLAYER:	
			case MAD_ERROR_BADSAMPLERATE:	
				//alsaplayer_error("Error %x (frame %d)", data->stream.error, data->current_frame);
				data->bytes_avail-=(data->stream.next_frame - data->stream.this_frame);
				goto first_frame;
				break;
			case MAD_ERROR_BADBITALLOC:
				return 0;
			case MAD_ERROR_BADCRC:
				alsaplayer_error("MAD_ERROR_BADCRC: %s", error_str(data->stream.error, data->str));
			case MAD_ERROR_BADBIGVALUES:
			case MAD_ERROR_BADDATAPTR:
				break;
			default:
				alsaplayer_error("ERROR: %s", error_str(data->stream.error, data->str));
				alsaplayer_error("No valid frame found at start (pos: %d, error: 0x%x --> %x %x %x %x) (%s)", data->offset, data->stream.error, 
						data->stream.this_frame[0],
						data->stream.this_frame[1],
						data->stream.this_frame[2],
						data->stream.this_frame[3],path);
				return 0;
		}
	}

	mad_frame_decode(&data->frame, &data->stream);
	/*	
		alsaplayer_error("xing parsing...%x %x %x %x (%x %d)", 
		data->stream.this_frame[0], data->stream.this_frame[1],
		data->stream.this_frame[2], data->stream.this_frame[3],
		data->stream.anc_ptr, data->stream.anc_bitlen);
		*/		
	if (xing_parse(&data->xing, data->stream.anc_ptr, data->stream.anc_bitlen) == 0) {
		// We use the xing data later on
	}

	mode = (data->frame.header.mode == MAD_MODE_SINGLE_CHANNEL) ?
		1 : 2;
	data->samplerate = data->frame.header.samplerate;
	data->bitrate	= data->frame.header.bitrate;
	mad_synth_frame (&data->synth, &data->frame);
	{
		struct mad_pcm *pcm = &data->synth.pcm;			

		obj->nr_channels = pcm->channels;
		//alsaplayer_error("nr_channels = %d", obj->nr_channels);
	}
	//alsaplayer_error("Initial: %d, %d, %d", data->samplerate, data->bitrate, obj->nr_channels);
	/* Calculate some values */
	data->bytes_avail = data->stream.bufend - data->stream.next_frame;
	{
		int64_t time;
		int64_t samples;
		int64_t frames;

		long oldpos = reader_tell(data->mad_fd);
		reader_seek(data->mad_fd, 0, SEEK_END);

		data->filesize = reader_tell(data->mad_fd);
		data->filesize -= data->offset;

		reader_seek(data->mad_fd, oldpos, SEEK_SET);
		if (data->bitrate)
			time = (data->filesize * 8) / (data->bitrate);
		else
			time = 0;

		samples = 32 * MAD_NSBSAMPLES(&data->frame.header);

		obj->frame_size = (int) samples << 2; /* Assume 16-bit stereo */
		frames = data->samplerate * (time+1) / samples;
		if (data->xing.flags & XING_FRAMES) {
			obj->nr_frames = data->xing.frames;
		} else {	
			obj->nr_frames = (int) frames;
		}	
		obj->nr_tracks = 1;
	}
	/* Determine if nr_frames makes sense */
	if (!(obj->flags & P_SEEK) && (obj->flags & P_STREAMBASED)) {
		obj->nr_frames = -1;
	}	

	/* Allocate frame index */
	if (!data->seekable  || obj->nr_frames > 1000000 ||
			(data->frames = (ssize_t *)malloc((obj->nr_frames + FRAME_RESERVE) * sizeof(ssize_t))) == NULL) {
		data->seekable = 0; // Given really
	}	else {
		data->seekable = 1;
		data->frames[0] = 0;
	}	
	data->mad_init = 1;

	p = strrchr(path, '/');
	if (p) {
		strcpy(data->filename, ++p);
	} else {
		strcpy(data->filename, path);
	}
	strcpy(data->path, path);

	data->parse_id3 = prefs_get_bool(ap_prefs, "mad", "parse_id3", 1);

	return 1;
}
Пример #23
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;
}
Пример #24
0
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);
}