static gint64 xmms_mad_seek (xmms_xform_t *xform, gint64 samples, xmms_xform_seek_mode_t whence, xmms_error_t *err) { xmms_mad_data_t *data; guint bytes; gint64 res; g_return_val_if_fail (whence == XMMS_XFORM_SEEK_SET, -1); g_return_val_if_fail (xform, -1); data = xmms_xform_private_data_get (xform); if (data->xing && xmms_xing_has_flag (data->xing, XMMS_XING_FRAMES) && xmms_xing_has_flag (data->xing, XMMS_XING_TOC)) { guint i; i = (guint) (100ULL * samples / xmms_xing_get_frames (data->xing) / 1152); bytes = xmms_xing_get_toc (data->xing, i) * (xmms_xing_get_bytes (data->xing) / 256); } else { bytes = (guint)(((gdouble)samples) * data->bitrate / data->samplerate) / 8; } XMMS_DBG ("Try seek %" G_GINT64_FORMAT " samples -> %d bytes", samples, bytes); res = xmms_xform_seek (xform, bytes, XMMS_XFORM_SEEK_SET, err); if (res == -1) { return -1; } /* we don't have sample accuracy when seeking, so there is no use trying */ data->samples_to_skip = 0; data->samples_to_play = -1; return samples; }
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; }
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; }