Ejemplo n.º 1
0
static bool
mp3_decode_first_frame(struct mp3_data *data, struct tag **tag,
		       struct replay_gain_info **replay_gain_info_r)
{
	struct xing xing;
	struct lame lame;
	struct mad_bitptr ptr;
	int bitlen;
	enum mp3_action ret;

	/* stfu gcc */
	memset(&xing, 0, sizeof(struct xing));
	xing.flags = 0;

	while (true) {
		do {
			ret = decode_next_frame_header(data, tag,
						       replay_gain_info_r);
		} while (ret == DECODE_CONT);
		if (ret == DECODE_BREAK)
			return false;
		if (ret == DECODE_SKIP) continue;

		do {
			ret = decodeNextFrame(data);
		} while (ret == DECODE_CONT);
		if (ret == DECODE_BREAK)
			return false;
		if (ret == DECODE_OK) break;
	}

	ptr = data->stream.anc_ptr;
	bitlen = data->stream.anc_bitlen;

	mp3_filesize_to_song_length(data);

	/*
	 * if an xing tag exists, use that!
	 */
	if (parse_xing(&xing, &ptr, &bitlen)) {
		data->found_xing = true;
		data->mute_frame = MUTEFRAME_SKIP;

		if ((xing.flags & XING_FRAMES) && xing.frames) {
			mad_timer_t duration = data->frame.header.duration;
			mad_timer_multiply(&duration, xing.frames);
			data->total_time = ((float)mad_timer_count(duration, MAD_UNITS_MILLISECONDS)) / 1000;
			data->max_frames = xing.frames;
		}

		if (parse_lame(&lame, &ptr, &bitlen)) {
			if (gapless_playback &&
			    data->input_stream->seekable) {
				data->drop_start_samples = lame.encoder_delay +
				                           DECODERDELAY;
				data->drop_end_samples = lame.encoder_padding;
			}

			/* Album gain isn't currently used.  See comment in
			 * parse_lame() for details. -- jat */
			if (replay_gain_info_r && !*replay_gain_info_r &&
			    lame.track_gain) {
				*replay_gain_info_r = replay_gain_info_new();
				(*replay_gain_info_r)->tuples[REPLAY_GAIN_TRACK].gain = lame.track_gain;
				(*replay_gain_info_r)->tuples[REPLAY_GAIN_TRACK].peak = lame.peak;
			}
		}
	} 

	if (!data->max_frames)
		return false;

	if (data->max_frames > 8 * 1024 * 1024) {
		g_warning("mp3 file header indicates too many frames: %lu\n",
			  data->max_frames);
		return false;
	}

	data->frame_offsets = g_malloc(sizeof(long) * data->max_frames);
	data->times = g_malloc(sizeof(mad_timer_t) * data->max_frames);

	return true;
}
Ejemplo n.º 2
0
xmms_xing_t *
xmms_xing_parse (struct mad_bitptr ptr)
{
	xmms_xing_t *xing;
	guint32 xing_magic;

	xing_magic = mad_bit_read (&ptr, 4*8);

	/* Xing or Info */
	if (xing_magic != 0x58696e67 && xing_magic != 0x496e666f) {
		return NULL;
	}

	xing = g_new0 (xmms_xing_t, 1);

	g_return_val_if_fail (xing, NULL);

	xing->flags = mad_bit_read (&ptr, 32);

	if (xmms_xing_has_flag (xing, XMMS_XING_FRAMES))
		xing->frames = mad_bit_read (&ptr, 32);

	if (xmms_xing_has_flag (xing, XMMS_XING_BYTES))
		xing->bytes = mad_bit_read (&ptr, 32);

	if (xmms_xing_has_flag (xing, XMMS_XING_TOC)) {
		gint i;
		for (i = 0; i < 100; i++)
			xing->toc[i] = mad_bit_read (&ptr, 8);
	}

	if (xmms_xing_has_flag (xing, XMMS_XING_SCALE)) {
		/* just move the pointer forward */
		mad_bit_read (&ptr, 32);
	}


	xing->lame = parse_lame (&ptr);

	/*
	if (strncmp ((gchar *)ptr.byte, "LAME", 4) == 0) {
		lame = g_new0 (xmms_xing_lame_t, 1);
		XMMS_DBG ("Parsing LAME tag");
		mad_bit_skip (&ptr, 4 * 8);
		mad_bit_nextbyte (&ptr);
		mad_bit_skip (&ptr, (8 * 5) + 12);
		lame->peak_amplitude = mad_bit_read (&ptr, 32);
		lame->radio_gain = mad_bit_read (&ptr, 16);
		lame->audiophile_gain = mad_bit_read (&ptr, 16);
		mad_bit_skip (&ptr, 16);
		lame->encoder_delay_start = mad_bit_read (&ptr, 12);
		lame->encoder_delay_stop = mad_bit_read (&ptr, 12);
		mad_bit_skip (&ptr, 8);
		lame->mp3_gain = mad_bit_read (&ptr, 8);
		xing->lame = lame;
	}
	*/

	if (xmms_xing_has_flag (xing, XMMS_XING_FRAMES) && xing->frames == 0) {
		xmms_log_info ("Corrupt xing header (frames == 0), ignoring");
		xmms_xing_free (xing);
		return NULL;
	}

	if (xmms_xing_has_flag (xing, XMMS_XING_BYTES) && xing->bytes == 0) {
		xmms_log_info ("Corrupt xing header (bytes == 0), ignoring");
		xmms_xing_free (xing);
		return NULL;
	}

	if (xmms_xing_has_flag (xing, XMMS_XING_TOC)) {
		gint i;
		for (i = 0; i < 99; i++) {
			if (xing->toc[i] > xing->toc[i + 1]) {
				xmms_log_info ("Corrupt xing header (toc not monotonic), ignoring");
				xmms_xing_free (xing);
				return NULL;
			}
		}
	}

	return xing;
}
Ejemplo n.º 3
0
/*
 * NAME:	tag->parse()
 * DESCRIPTION:	parse Xing/LAME tag(s)
 */
int tag_parse(struct tag *tag, struct mad_stream const *stream)
{
  struct mad_bitptr ptr = stream->anc_ptr;
  struct mad_bitptr start = ptr;
  unsigned int bitlen = stream->anc_bitlen;
  unsigned long magic;
  int i;

  if (bitlen < 32)
    return -1;

  magic = mad_bit_read(&ptr, 32);
  bitlen -= 32;

  if (magic != XING_MAGIC &&
      magic != INFO_MAGIC &&
      magic != LAME_MAGIC) {
    /*
     * Due to an unfortunate historical accident, a Xing VBR tag may be
     * misplaced in a stream with CRC protection. We check for this by
     * assuming the tag began two octets prior and the high bits of the
     * following flags field are always zero.
     */

    if (magic != ((XING_MAGIC << 16) & 0xffffffffL) &&
	magic != ((INFO_MAGIC << 16) & 0xffffffffL))
      return -1;

    magic >>= 16;

    /* backtrack the bit pointer */

    ptr = start;
    mad_bit_skip(&ptr, 16);
    bitlen += 16;
  }

  if ((magic & 0x0000ffffL) == (XING_MAGIC & 0x0000ffffL))
    tag->flags |= TAG_VBR;

  /* Xing tag */

  if (magic == LAME_MAGIC) {
    ptr = start;
    bitlen += 32;
  }
  else if (parse_xing(&tag->xing, &ptr, &bitlen) == 0)
    tag->flags |= TAG_XING;

  /* encoder string */

  if (bitlen >= 20 * 8) {
    start = ptr;

    for (i = 0; i < 20; ++i) {
      tag->encoder[i] = mad_bit_read(&ptr, 8);

      if (tag->encoder[i] == 0)
	break;

      /* keep only printable ASCII chars */

      if (tag->encoder[i] < 0x20 || tag->encoder[i] >= 0x7f) {
	tag->encoder[i] = 0;
	break;
      }
    }

    tag->encoder[20] = 0;
    ptr = start;
  }

  /* LAME tag */

  if (stream->next_frame - stream->this_frame >= 192 &&
      parse_lame(&tag->lame, &ptr, &bitlen,
		 crc_compute(stream->this_frame, 190, 0x0000)) == 0) {
    tag->flags |= TAG_LAME;
    tag->encoder[9] = 0;
  }
  else {
    for (i = 0; i < 20; ++i) {
      if (tag->encoder[i] == 0)
	break;

      /* stop at padding chars */

      if (tag->encoder[i] == 0x55) {
	tag->encoder[i] = 0;
	break;
      }
    }
  }

  return 0;
}