Пример #1
0
static gboolean
xmms_mad_init (xmms_xform_t *xform)
{
	struct mad_frame frame;
	struct mad_stream stream;
	xmms_error_t err;
	guchar buf[40960];
	xmms_mad_data_t *data;
	int len;
	const gchar *metakey;

	g_return_val_if_fail (xform, FALSE);

	data = g_new0 (xmms_mad_data_t, 1);

	mad_stream_init (&data->stream);
	mad_frame_init (&data->frame);
	mad_synth_init (&data->synth);

	xmms_xform_private_data_set (xform, data);

	data->buffer_length = 0;

	data->synthpos = 0x7fffffff;

	mad_stream_init (&stream);
	mad_frame_init (&frame);

	len = xmms_xform_peek (xform, buf, 40960, &err);
	mad_stream_buffer (&stream, buf, len);

	while (mad_frame_decode (&frame, &stream) == -1) {
		if (!MAD_RECOVERABLE (stream.error)) {
			XMMS_DBG ("couldn't decode %02x %02x %02x %02x",buf[0],buf[1],buf[2],buf[3]);
			mad_frame_finish (&frame);
			mad_stream_finish (&stream);
			return FALSE;
		}
	}

	data->channels = frame.header.mode == MAD_MODE_SINGLE_CHANNEL ? 1 : 2;
	data->samplerate = frame.header.samplerate;


	if (frame.header.flags & MAD_FLAG_PROTECTION) {
		XMMS_DBG ("Frame has protection enabled");
		if (stream.anc_ptr.byte > stream.buffer + 2) {
			stream.anc_ptr.byte = stream.anc_ptr.byte - 2;
		}
	}

	data->samples_to_play = -1;

	data->xing = xmms_xing_parse (stream.anc_ptr);
	if (data->xing) {
		xmms_xing_lame_t *lame;
		XMMS_DBG ("File with Xing header!");

		metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_IS_VBR;
		xmms_xform_metadata_set_int (xform, metakey, 1);

		if (xmms_xing_has_flag (data->xing, XMMS_XING_FRAMES)) {
			guint duration;
			mad_timer_t timer;

			timer = frame.header.duration;
			mad_timer_multiply (&timer, xmms_xing_get_frames (data->xing));
			duration = mad_timer_count (timer, MAD_UNITS_MILLISECONDS);

			XMMS_DBG ("XING duration %d", duration);

			metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION;
			xmms_xform_metadata_set_int (xform, metakey, duration);

			if (xmms_xing_has_flag (data->xing, XMMS_XING_BYTES) && duration) {
				guint tmp;

				tmp = xmms_xing_get_bytes (data->xing) * ((guint64)8000) / duration;
				XMMS_DBG ("XING bitrate %d", tmp);
				metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_BITRATE;
				xmms_xform_metadata_set_int (xform, metakey, tmp);
			}
		}

		lame = xmms_xing_get_lame (data->xing);
		if (lame) {
			/* FIXME: add a check for ignore_lame_headers from the medialib */
			data->frames_to_skip = 1;
			data->samples_to_skip = lame->start_delay;
			data->samples_to_play = ((guint64) xmms_xing_get_frames (data->xing) * 1152ULL) -
			                        lame->start_delay - lame->end_padding;
			XMMS_DBG ("Samples to skip in the beginning: %d, total: %" G_GINT64_FORMAT,
			          data->samples_to_skip, data->samples_to_play);
			/*
			metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_GAIN_ALBUM;
			xmms_xform_metadata_set_int (xform, metakey, lame->audiophile_gain);

			metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_PEAK_TRACK;
			xmms_xform_metadata_set_int (xform, metakey, lame->peak_amplitude);

			metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_GAIN_TRACK;
			xmms_xform_metadata_set_int (xform, metakey, lame->radio_gain);
			*/
		}

	} else {
		gint filesize;

		metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_BITRATE;
		xmms_xform_metadata_set_int (xform, metakey, frame.header.bitrate);

		metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION;
		if (!xmms_xform_metadata_get_int (xform, metakey, &filesize)) {
			metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_SIZE;

			if (xmms_xform_metadata_get_int (xform, metakey, &filesize)) {
				gint32 val;

				val = (gint32) (filesize * (gdouble) 8000.0 / frame.header.bitrate);

				metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION;
				xmms_xform_metadata_set_int (xform, metakey, val);
			}
		}
	}

	/* seeking needs bitrate */
	data->bitrate = frame.header.bitrate;

	if (xmms_id3v1_get_tags (xform) < 0) {
		mad_stream_finish (&data->stream);
		mad_frame_finish (&data->frame);
		mad_synth_finish (&data->synth);
		if (data->xing) {
			xmms_xing_free (data->xing);
		}
		return FALSE;
	}

	xmms_xform_outdata_type_add (xform,
	                             XMMS_STREAM_TYPE_MIMETYPE,
	                             "audio/pcm",
	                             XMMS_STREAM_TYPE_FMT_FORMAT,
	                             XMMS_SAMPLE_FORMAT_S16,
	                             XMMS_STREAM_TYPE_FMT_CHANNELS,
	                             data->channels,
	                             XMMS_STREAM_TYPE_FMT_SAMPLERATE,
	                             data->samplerate,
	                             XMMS_STREAM_TYPE_END);

	mad_frame_finish (&frame);
	mad_stream_finish (&stream);

	return TRUE;
}
Пример #2
0
static gboolean
xmms_mpg123_init (xmms_xform_t *xform)
{
	xmms_mpg123_data_t *data;
	const long *rates;
	size_t num_rates;
	int encoding;
	off_t length;
	int i, result;

	g_return_val_if_fail (xform, FALSE);

	data = g_new0 (xmms_mpg123_data_t, 1);
	xmms_xform_private_data_set (xform, data);

	/* Get the total size of this stream and store it for later */
	if (xmms_xform_metadata_get_int (xform,
	                                 XMMS_MEDIALIB_ENTRY_PROPERTY_SIZE,
	                                 &result)) {
		data->filesize = result;
	}

	mpg123_rates (&rates, &num_rates);

	data->param = mpg123_new_pars (&result);
	g_return_val_if_fail (data->param, FALSE);

	/* Create a quiet (stderr) decoder with auto choosen optimization.
	 * Stuff set here should be tunable via plugin config properties!
	 * You can also change some things during playback...
	 */
	mpg123_par (data->param, MPG123_ADD_FLAGS, MPG123_QUIET, 0);
	mpg123_par (data->param, MPG123_ADD_FLAGS, MPG123_GAPLESS, 0);
	/* choose: MPG123_RVA_OFF, MPG123_RVA_MIX, MPG123_RVA_ALBUM
	 * xmms2 has its own ReplayGain plugin to handle the RVA field */
	mpg123_par (data->param, MPG123_RVA, MPG123_RVA_OFF, 0);

	/* You could choose a decoder from the list provided by
	 * mpg123_supported_decoders () and give that as second parameter.
	 */
	data->decoder = mpg123_parnew (data->param, NULL, &result);
	if (data->decoder == NULL) {
		xmms_log_error ("%s", mpg123_plain_strerror (result));
		goto bad;
	}

	/* Prepare for buffer input feeding. */
	result = mpg123_open_feed (data->decoder);
	if (result != MPG123_OK) {
		goto mpg123_bad;
	}

	/* Let's always decode to signed 16bit for a start.
	   Any mpg123-supported sample rate is accepted. */
	if (MPG123_OK != mpg123_format_none (data->decoder)) {
		goto mpg123_bad;
	}

	for (i = 0; i < num_rates; i++) {
		result = mpg123_format (data->decoder, rates[i],
		                        MPG123_MONO | MPG123_STEREO,
		                        MPG123_ENC_SIGNED_16);
		if (result != MPG123_OK) {
			goto mpg123_bad;
		}
	}

	/* Fetch ID3v1 data from the end of file if possible */
	result = xmms_id3v1_get_tags (xform);
	if (result < 0) {
		xmms_log_error ("Seeking error when reading ID3v1 tags");
		goto bad;
	} else if (data->filesize > result) {
		/* Reduce the size of tag data from the filesize */
		data->filesize -= result;
	}

	/* Read data from input until decoded data is available from decoder */
	do {
		/* Parse stream and get info. */
		gint ret;
		xmms_error_t err;

		ret = xmms_xform_read (xform, data->buf, BUFSIZE, &err);
		if (ret < 0) {
			xmms_log_error ("Error when trying to find beginning of stream");
			goto bad;
		} else if (ret == 0) {
			/* EOF reached before format was found, handled after loop */
			break;
		}

		/* With zero output size nothing is actually outputted */
		result = mpg123_decode (data->decoder, data->buf,
		                        (size_t) ret, NULL, 0, NULL);
	} while (result == MPG123_NEED_MORE); /* Keep feeding... */

	if (result != MPG123_NEW_FORMAT) {
		xmms_log_error ("Unable to find beginning of stream (%s)!",
		                result == MPG123_ERR ? mpg123_strerror (data->decoder)
		                : "unexpected EOF");
		goto bad;
	}

	result = mpg123_getformat (data->decoder, &data->samplerate,
	                           &data->channels, &encoding);
	if (result != MPG123_OK) {
		goto mpg123_bad;
	}

	/* Set the filesize so it can be used for duration estimation */
	if (data->filesize > 0) {
		mpg123_set_filesize (data->decoder, data->filesize);
	}

	/* Get duration in samples, convert to ms and save to xmms2 */
	length = mpg123_length (data->decoder);
	if (length > 0 &&
	    !xmms_xform_metadata_get_int (xform,
		                              XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION,
		                              &i)) {
		length = (off_t) ((gfloat) length / data->samplerate * 1000);
		xmms_xform_metadata_set_int (xform,
		                             XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION,
		                             (gint) length);
	}

	XMMS_DBG ("mpg123: got stream with %li Hz %i channels, encoding %i",
	          data->samplerate, data->channels, encoding);

	xmms_xform_outdata_type_add (xform,
	                             XMMS_STREAM_TYPE_MIMETYPE,
	                             "audio/pcm",
	                             XMMS_STREAM_TYPE_FMT_FORMAT,
	                             XMMS_SAMPLE_FORMAT_S16,
	                             XMMS_STREAM_TYPE_FMT_CHANNELS,
	                             data->channels,
	                             XMMS_STREAM_TYPE_FMT_SAMPLERATE,
	                             (gint) data->samplerate,
	                             XMMS_STREAM_TYPE_END);
	return TRUE;

mpg123_bad:
	xmms_log_error ("mpg123 error: %s", mpg123_strerror (data->decoder));

bad:
	mpg123_delete (data->decoder);
	mpg123_delete_pars (data->param);
	g_free (data);

	return FALSE;
}