static void handle_id3v2_comm (xmms_xform_t *xform, xmms_id3v2_header_t *head, const gchar *key, gchar *buf, gsize len) { /* COMM is weird but it's like this: * $xx enc * $xx xx xx lang * $text $0 desc according to enc * $text $0 comment according to enc */ const gchar *enc, *desc, *comm; gchar *cbuf; gsize clen; enc = binary_to_enc (buf[0]); buf++; len--; /* Language is always three _bytes_ - we currently don't care */ buf += 3; len -= 3; cbuf = convert_id3_text (enc, buf, len, &clen); if (!cbuf) return; desc = cbuf; comm = find_nul (cbuf, &clen); if (comm && comm[0]) { const gchar *metakey; gchar *tmp; if (desc && desc[0]) { metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_COMMENT; tmp = g_strdup_printf ("%s_%s", metakey, desc); xmms_xform_metadata_set_str (xform, tmp, comm); g_free (tmp); } else { metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_COMMENT; xmms_xform_metadata_set_str (xform, metakey, comm); } } g_free (cbuf); }
static gboolean xmms_apetag_handle_tag_coverart (xmms_xform_t *xform, const gchar *key, const gchar *value, gsize length) { const gchar *mime, *ptr; gchar *filename; gchar hash[33]; gsize size; if (*value == '\0') { return FALSE; } filename = g_strndup (value, length); if (!filename) { return FALSE; } if (g_str_has_suffix (filename, "jpg")) { mime = "image/jpeg"; } else if (g_str_has_suffix (filename, "png")) { mime = "image/png"; } else { XMMS_DBG ("Unknown image format: %s", filename); g_free (filename); return FALSE; } ptr = value + strlen (filename) + 1; size = length - (ptr - value); if (xmms_bindata_plugin_add ((const guchar *) ptr, size, hash)) { const gchar *metakey; metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_PICTURE_FRONT; xmms_xform_metadata_set_str (xform, metakey, hash); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_PICTURE_FRONT_MIME; xmms_xform_metadata_set_str (xform, metakey, mime); } g_free (filename); return TRUE; }
static gboolean xmms_mp4_mediainfo_set_coverart (xmms_xform_t *xform, const gchar *key, const gchar *value, gsize length) { const gchar *metakey; gchar hash[33]; if (!xmms_bindata_plugin_add ((const guchar *) value, length, hash)) { return FALSE; } metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_PICTURE_FRONT; xmms_xform_metadata_set_str (xform, metakey, hash); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_PICTURE_FRONT_MIME; xmms_xform_metadata_set_str (xform, metakey, "image/jpeg"); return TRUE; }
static void handle_id3v2_tcon (xmms_xform_t *xform, xmms_id3v2_header_t *head, const gchar *key, gchar *buf, gsize len) { gint res; guint genre_id; gchar *val; const gchar *tmp; const gchar *metakey; /* XXX - we should handle it differently v4 separates them with NUL instead of using () */ /* if (head->ver == 4) { buf++; len -= 1; } */ tmp = binary_to_enc (buf[0]); val = convert_id3_text (tmp, &buf[1], len - 1, NULL); if (!val) return; if (head->ver >= 4) { res = sscanf (val, "%u", &genre_id); } else { res = sscanf (val, "(%u)", &genre_id); } if (res > 0 && genre_id < G_N_ELEMENTS (id3_genres)) { metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_GENRE; xmms_xform_metadata_set_str (xform, metakey, (gchar *) id3_genres[genre_id]); } else { metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_GENRE; xmms_xform_metadata_set_str (xform, metakey, val); } g_free (val); }
static void handle_id3v2_apic (xmms_xform_t *xform, xmms_id3v2_header_t *head, const gchar *key, gchar *buf, gsize len) { const gchar *typ, *desc, *data, *mime; gchar hash[33]; /* skip encoding */ buf++; len--; mime = buf; typ = find_nul (buf, &len); if (!typ || len == 0) { XMMS_DBG ("Unable to read APIC frame, malformed tag?"); return; } if (typ[0] != 0x00 && typ[0] != 0x03) { XMMS_DBG ("Picture type %02x not handled", typ[0]); return; } desc = typ + 1; len--; /* XXX desc might be UCS2 and find_nul will not do what we want */ data = find_nul (desc, &len); if (data && xmms_bindata_plugin_add ((const guchar *)data, len, hash)) { const gchar *metakey; metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_PICTURE_FRONT; xmms_xform_metadata_set_str (xform, metakey, hash); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_PICTURE_FRONT_MIME; xmms_xform_metadata_set_str (xform, metakey, mime); } }
static void handle_id3v2_txxx (xmms_xform_t *xform, xmms_id3v2_header_t *head, const gchar *_key, gchar *buf, gsize len) { const gchar *enc; gchar *cbuf; const gchar *key, *val; const gchar *metakey; gsize clen; enc = binary_to_enc (buf[0]); cbuf = convert_id3_text (enc, &buf[1], len - 1, &clen); if (!cbuf) return; key = cbuf; val = find_nul (cbuf, &clen); if (!val) { g_free (cbuf); return; } if (g_ascii_strcasecmp (key, "MusicBrainz Album Id") == 0) { metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM_ID; xmms_xform_metadata_set_str (xform, metakey, val); } else if (g_ascii_strcasecmp (key, "MusicBrainz Artist Id") == 0) { metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST_ID; xmms_xform_metadata_set_str (xform, metakey, val); } else if ((g_ascii_strcasecmp (key, "MusicBrainz Album Artist Id") == 0) && (g_ascii_strcasecmp (val, MUSICBRAINZ_VA_ID) == 0)) { metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_COMPILATION; xmms_xform_metadata_set_int (xform, metakey, 1); } else if (g_ascii_strcasecmp (key, "ASIN") == 0) { metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_ASIN; xmms_xform_metadata_set_str (xform, metakey, val); } else if (g_ascii_strcasecmp (key, "QuodLibet::albumartist") == 0) { metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM_ARTIST; xmms_xform_metadata_set_str (xform, metakey, val); } else if (g_ascii_strcasecmp (key, "ALBUMARTISTSORT") == 0) { metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM_ARTIST_SORT; xmms_xform_metadata_set_str (xform, metakey, val); } else if (g_ascii_strcasecmp (key, "BARCODE") == 0) { metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_BARCODE; xmms_xform_metadata_set_str (xform, metakey, val); } else if (g_ascii_strcasecmp (key, "CATALOGNUMBER") == 0) { metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_CATALOGNUMBER; xmms_xform_metadata_set_str (xform, metakey, val); } else { XMMS_DBG ("Unhandled tag 'TXXX:%s' = '%s'", key, val); } g_free (cbuf); }
gboolean xmms_xform_metadata_parse_replay_gain (xmms_xform_t *xform, const gchar *key, const gchar *value, gsize length) { gchar *endptr = NULL; gdouble number; number = strtod (value, &endptr); if (endptr > value) { gchar buffer[8]; g_snprintf (buffer, sizeof (buffer), "%f", pow (10.0, number / 20)); xmms_xform_metadata_set_str (xform, key, buffer); return TRUE; } return FALSE; }
static gboolean xmms_ofa_init (xmms_xform_t *xform) { xmms_ofa_data_t *data; xmms_medialib_entry_t entry; char *fp; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_ofa_data_t, 1); g_return_val_if_fail (data, FALSE); data->thread = g_thread_new ("x2 ofa calc", xmms_ofa_thread, data); if (!data->thread) { g_free (data); return FALSE; } g_mutex_init (&data->mutex); g_cond_init (&data->cond); data->bytes_to_read = 44100 * 135 * 4; data->buf = g_malloc (data->bytes_to_read); entry = xmms_xform_entry_get (xform); /* TODO: #2482 fp = xmms_medialib_entry_property_get_str (entry, "ofa_fingerprint"); */ fp = NULL; if (fp) { XMMS_DBG ("Entry already has ofa_fingerprint, not recalculating"); /* keep it! */ xmms_xform_metadata_set_str (xform, "ofa_fingerprint", fp); g_free (fp); } else { data->run_ofa = TRUE; } xmms_xform_private_data_set (xform, data); xmms_xform_outdata_type_copy (xform); return TRUE; }
static void add_to_entry (xmms_xform_t *xform, xmms_id3v2_header_t *head, const gchar *key, gchar *val, gint len) { gchar *nval; const gchar *tmp; if (len < 1) return; tmp = binary_to_enc (val[0]); nval = convert_id3_text (tmp, &val[1], len - 1, NULL); if (nval) { xmms_xform_metadata_set_str (xform, key, nval); g_free (nval); } }
static gint xmms_ofa_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len, xmms_error_t *error) { xmms_ofa_data_t *data; gint read; g_return_val_if_fail (xform, -1); data = xmms_xform_private_data_get (xform); g_return_val_if_fail (data, -1); read = xmms_xform_read (xform, buf, len, error); if (data->run_ofa && read > 0 && data->pos < data->bytes_to_read) { int l = MIN (data->bytes_to_read - data->pos, read); memcpy (data->buf + data->pos, buf, l); data->pos += l; if (data->pos == data->bytes_to_read) { g_mutex_lock (&data->mutex); data->thread_state = XMMS_OFA_CALCULATE; g_cond_signal (&data->cond); g_mutex_unlock (&data->mutex); data->run_ofa = FALSE; } } else if (data->pos == data->bytes_to_read){ if (!data->done) { g_mutex_lock (&data->mutex); if (data->thread_state == XMMS_OFA_DONE) { xmms_xform_metadata_set_str (xform, "ofa_fingerprint", data->fp); data->done = TRUE; } g_mutex_unlock (&data->mutex); } } return read; }
static void handle_id3v2_ufid (xmms_xform_t *xform, xmms_id3v2_header_t *head, const gchar *key, gchar *buf, gsize len) { const gchar *val; val = find_nul (buf, &len); if (!val) return; if (g_ascii_strcasecmp (buf, "http://musicbrainz.org") == 0) { const gchar *metakey; gchar *val0; /* make sure it is NUL terminated */ val0 = g_strndup (val, len); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_TRACK_ID, xmms_xform_metadata_set_str (xform, metakey, val0); g_free (val0); } }
static void xmms_mpc_collect_metadata (xmms_xform_t *xform) { xmms_mpc_data_t *data; xmms_apetag_t *tag; gint i, intval; const gchar *strval; g_return_if_fail (xform); data = xmms_xform_private_data_get (xform); g_return_if_fail (data); tag = xmms_apetag_init (xform); if (xmms_apetag_read (tag)) { for (i = 0; i < G_N_ELEMENTS (properties); i++) { switch (properties[i].type) { case INTEGER: intval = xmms_apetag_lookup_int (tag, properties[i].vname); if (intval > 0) { xmms_xform_metadata_set_int (xform, properties[i].xname, intval); } break; case STRING: strval = xmms_apetag_lookup_str (tag, properties[i].vname); if (strval != NULL) { xmms_xform_metadata_set_str (xform, properties[i].xname, strval); } break; } } } xmms_apetag_destroy (tag); }
static gboolean xmms_gvfs_init (xmms_xform_t *xform) { xmms_gvfs_data_t *data; GFile *file; GFileInfo *info; GFileInputStream *handle; GError *error = NULL; const gchar *url; url = xmms_xform_indata_get_str (xform, XMMS_STREAM_TYPE_URL); g_return_val_if_fail (url, FALSE); /* This is an ugly hack to handle files with chars needing url encoding */ if (!g_ascii_strncasecmp (url, "file://", 7)) { file = g_file_new_for_path (url+7); } else { file = g_file_new_for_uri (url); } handle = g_file_read (file, NULL, &error); g_object_unref (file); if (!handle) { xmms_log_error ("Failed to upen url %s for reading: %s", url, error->message); return FALSE; } data = g_new (xmms_gvfs_data_t, 1); data->handle = G_INPUT_STREAM (handle); xmms_xform_private_data_set (xform, data); info = g_file_input_stream_query_info (handle, (char *)query_attributes, NULL, &error); if (!info) { xmms_log_info ("failed to query information for %s", url); } else { int i; for (i = 0; i < G_N_ELEMENTS (attr_map); i++) { if (!g_file_info_has_attribute (info, attr_map[i].gvfs)) { continue; } switch (attr_map[i].type) { case XMMSV_TYPE_STRING: { gchar *attr = g_file_info_get_attribute_as_string (info, attr_map[i].gvfs); xmms_xform_metadata_set_str (xform, attr_map[i].mlib, attr); g_free (attr); break; } case XMMSV_TYPE_INT32: { /* right now the xform metadata api only handles strings * and 32 bit ints. however the gvfs api returns uint64 for * the numeric attributes we're interested in and we just * pass that to the xform and pray that it doesn't overflow * as we know it's unsafe. */ gint64 attr = g_file_info_get_attribute_uint64 (info, attr_map[i].gvfs); xmms_xform_metadata_set_int (xform, attr_map[i].mlib, attr); break; } default: g_assert_not_reached (); } } g_object_unref (info); } xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "application/octet-stream", XMMS_STREAM_TYPE_END); return TRUE; }
static void flac_callback_metadata (const FLAC__StreamDecoder *flacdecoder, const FLAC__StreamMetadata *metadata, void *client_data) { xmms_flac_data_t *data; xmms_xform_t *xform = (xmms_xform_t *) client_data; gint32 filesize; const gchar *metakey; g_return_if_fail (xform); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_SIZE; if (!xmms_xform_metadata_get_int (xform, metakey, &filesize)) { filesize = -1; } data = xmms_xform_private_data_get (xform); switch (metadata->type) { case FLAC__METADATA_TYPE_STREAMINFO: /* FLAC__metadata_object_clone ()? */ data->bits_per_sample = metadata->data.stream_info.bits_per_sample; data->sample_rate = metadata->data.stream_info.sample_rate; data->channels = metadata->data.stream_info.channels; data->total_samples = metadata->data.stream_info.total_samples; if (filesize > 0 && data->total_samples) { data->bit_rate = (guint) ((guint64) filesize * 8 * (guint64) data->sample_rate / (guint64) data->total_samples); } XMMS_DBG ("STREAMINFO: BPS %d. Samplerate: %d. Channels: %d.", data->bits_per_sample, data->sample_rate, data->channels); break; case FLAC__METADATA_TYPE_VORBIS_COMMENT: data->vorbiscomment = FLAC__metadata_object_clone (metadata); break; #if defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT > 7 case FLAC__METADATA_TYPE_PICTURE: { gchar hash[33]; if (metadata->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER && xmms_bindata_plugin_add (metadata->data.picture.data, metadata->data.picture.data_length, hash)) { const gchar *metakey; metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_PICTURE_FRONT; xmms_xform_metadata_set_str (xform, metakey, hash); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_PICTURE_FRONT_MIME; xmms_xform_metadata_set_str (xform, metakey, metadata->data.picture.mime_type); } break; } #endif /* if we want to support more metadata types here, * don't forget to add a call to * FLAC__stream_decoder_set_metadata_respond() below. */ default: break; } }
static void xmms_asf_get_mediainfo (xmms_xform_t *xform) { xmms_asf_data_t *data; asf_metadata_t *metadata; uint64_t tmp; gchar *track = NULL; gint i; g_return_if_fail (xform); data = xmms_xform_private_data_get (xform); g_return_if_fail (data); if ((tmp = asf_get_duration (data->file)) > 0) { xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION, tmp/10000); } if ((tmp = asf_get_max_bitrate (data->file)) > 0) { xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_BITRATE, tmp); } metadata = asf_header_get_metadata (data->file); if (!metadata) { XMMS_DBG ("No metadata object found in the file"); return; } if (metadata->title && metadata->title[0]) { xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_TITLE, metadata->title); } if (metadata->artist && metadata->artist[0]) { xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST, metadata->artist); } if (metadata->description && metadata->description[0]) { xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_COMMENT, metadata->description); } for (i=0; i<metadata->extended_count; i++) { char *key, *value; key = metadata->extended[i].key; value = metadata->extended[i].value; if (key == NULL || value == NULL || !strlen (value)) { continue; } else if (!strcmp (key, "WM/AlbumTitle")) { xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM, value); } else if (!strcmp (key, "WM/Year")) { xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_YEAR, value); } else if (!strcmp (key, "WM/Genre")) { xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_GENRE, value); } else if ((!track && !strcmp (key, "WM/Track")) || !strcmp (key, "WM/TrackNumber")) { /* WM/TrackNumber overrides WM/Track value as specified in the Microsoft * documentation at http://msdn2.microsoft.com/en-us/library/aa392014.aspx */ track = value; } else if (!strcmp (key, "MusicBrainz/Album Id")) { xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM_ID, value); } else if (!strcmp (key, "MusicBrainz/Artist Id")) { xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST_ID, value); } else if (!strcmp (key, "MusicBrainz/Track Id")) { xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_TRACK_ID, value); } } if (track) { gint tracknr; gchar *end; tracknr = strtol (track, &end, 10); if (end && *end == '\0') { xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_TRACKNR, tracknr); } } asf_metadata_destroy (metadata); }
static gboolean xmms_gme_init (xmms_xform_t *xform) { xmms_gme_data_t *data; gme_err_t init_error; GString *file_contents; /* The raw data from the file. */ gme_info_t *metadata = NULL; xmms_config_property_t *val; int loops; int maxlength; const char *subtune_str; int subtune = 0; long fadelen = -1; int samplerate; double stereodepth; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_gme_data_t, 1); xmms_xform_private_data_set (xform, data); val = xmms_xform_config_lookup (xform, "samplerate"); samplerate = xmms_config_property_get_int (val); if (samplerate < 1) samplerate = GME_DEFAULT_SAMPLE_RATE; data->samplerate = samplerate; xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", /* PCM samples */ XMMS_STREAM_TYPE_FMT_FORMAT, XMMS_SAMPLE_FORMAT_S16, /* 16-bit signed */ XMMS_STREAM_TYPE_FMT_CHANNELS, 2, /* stereo */ XMMS_STREAM_TYPE_FMT_SAMPLERATE, samplerate, XMMS_STREAM_TYPE_END); file_contents = g_string_new (""); for (;;) { xmms_error_t error; gchar buf[4096]; gint ret; ret = xmms_xform_read (xform, buf, sizeof (buf), &error); if (ret == -1) { XMMS_DBG ("Error reading emulated music data"); return FALSE; } if (ret == 0) { break; } g_string_append_len (file_contents, buf, ret); } init_error = gme_open_data (file_contents->str, file_contents->len, &data->emu, samplerate); g_string_free (file_contents, TRUE); if (init_error) { XMMS_DBG ("gme_open_data returned an error: %s", init_error); return FALSE; } if (xmms_xform_metadata_get_str (xform, "subtune", &subtune_str)) { subtune = strtol (subtune_str, NULL, 10); XMMS_DBG ("Setting subtune to %d", subtune); if ((subtune < 0 || subtune > gme_track_count (data->emu))) { XMMS_DBG ("Invalid subtune index"); return FALSE; } } else { xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_SUBTUNES, gme_track_count (data->emu)); } /* * Get metadata here */ init_error = gme_track_info (data->emu, &metadata, subtune); if (init_error) { XMMS_DBG ("Couldn't get GME track info: %s", init_error); init_error = ""; } else { xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_TITLE, metadata->song); xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST, metadata->author); xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM, metadata->game); xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_COMMENT, metadata->comment); xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_YEAR, metadata->copyright); xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_GENRE, metadata->system); /* I mapped genre to the system type */ val = xmms_xform_config_lookup (xform, "loops"); loops = xmms_config_property_get_int (val); XMMS_DBG ("intro_length = %d, loops = %d, loop_length = %d", metadata->intro_length, loops, metadata->loop_length); if (metadata->intro_length > 0) { if ((loops > 0) && (metadata->loop_length > 0)) { fadelen = metadata->intro_length + loops * metadata->loop_length; XMMS_DBG ("fadelen now = %ld", fadelen); } else { fadelen = metadata->length; XMMS_DBG ("fadelen now = %ld", fadelen); } } } val = xmms_xform_config_lookup (xform, "maxlength"); maxlength = xmms_config_property_get_int (val); XMMS_DBG ("maxlength = %d seconds", maxlength); if (maxlength > 0 && (fadelen < 0 || (maxlength * 1000L < fadelen))) { fadelen = maxlength * 1000L; XMMS_DBG ("fadelen now = %ld", fadelen); } XMMS_DBG ("gme.fadelen = %ld", fadelen); val = xmms_xform_config_lookup (xform, "stereodepth"); stereodepth = xmms_config_property_get_float (val); if (stereodepth >= 0.0 && stereodepth <= 1.0) { XMMS_DBG ("Setting stereo depth to %f.", stereodepth); gme_set_stereo_depth (data->emu, stereodepth); } else { XMMS_DBG ("gme.stereodepth = %f out of range 0.0 - 1.0; not setting.", stereodepth); } init_error = gme_start_track (data->emu, subtune); if (init_error) { XMMS_DBG ("gme_start_track returned an error: %s", init_error); gme_free_info (metadata); return FALSE; } if (fadelen > 0) { XMMS_DBG ("Setting song length and fade length..."); xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION, fadelen); gme_set_fade (data->emu, fadelen); } gme_free_info (metadata); return TRUE; }
static gboolean xmms_xform_metadata_parse_string (xmms_xform_t *xform, const gchar *key, const gchar *value, gsize length) { return xmms_xform_metadata_set_str (xform, key, value); }
static gboolean handle_image_comment (xmms_xform_t *xform, const gchar *key, const gchar *encoded_value, gsize length) { gsize len; guchar *value; guint32 typ, mime_len, desc_len, img_len; guchar *pos, *end, *mime_data, *img_data; gchar hash[33]; #if GLIB_CHECK_VERSION(2,12,0) value = g_base64_decode (encoded_value, &len); #else /* TODO: Implement/backport base64 decoding */ return; #endif pos = value; end = value + len; if (pos + sizeof (guint32) > end) { XMMS_DBG ("Malformed picture comment"); goto finish; } typ = decode_uint32 (&pos); if (typ != 0 && typ != 3) { XMMS_DBG ("Picture type %d not handled", typ); goto finish; } if (pos + sizeof (guint32) > end) { XMMS_DBG ("Malformed picture comment"); goto finish; } mime_len = decode_uint32 (&pos); mime_data = pos; pos += mime_len; if (pos + sizeof (guint32) > end) { XMMS_DBG ("Malformed picture comment"); goto finish; } desc_len = decode_uint32 (&pos); pos += desc_len; decode_uint32 (&pos); /* width */ decode_uint32 (&pos); /* height */ decode_uint32 (&pos); /* depth */ decode_uint32 (&pos); /* indexed palette length */ if (pos + sizeof (guint32) > end) { XMMS_DBG ("Malformed picture comment"); goto finish; } img_len = decode_uint32 (&pos); img_data = pos; if (img_data + img_len > end) { XMMS_DBG ("Malformed picture comment"); goto finish; } if (xmms_bindata_plugin_add (img_data, img_len, hash)) { const gchar *metakey; metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_PICTURE_FRONT; xmms_xform_metadata_set_str (xform, metakey, hash); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_PICTURE_FRONT_MIME; mime_data[mime_len] = '\0'; xmms_xform_metadata_set_str (xform, metakey, (gchar *)mime_data); } finish: g_free (value); return TRUE; }
static xmms_xform_t * chain_setup (xmms_medialib_entry_t entry, const gchar *url, GList *goal_formats) { xmms_xform_t *xform, *last; gchar *durl, *args; if (!entry) { entry = 1; /* FIXME: this is soooo ugly, don't do this */ } xform = xmms_xform_new (NULL, NULL, 0, goal_formats); durl = g_strdup (url); args = strchr (durl, '?'); if (args) { gchar **params; gint i; *args = 0; args++; xmms_medialib_decode_url (args); params = g_strsplit (args, "&", 0); for (i = 0; params && params[i]; i++) { gchar *v; v = strchr (params[i], '='); if (v) { *v = 0; v++; xmms_xform_metadata_set_str (xform, params[i], v); } else { xmms_xform_metadata_set_int (xform, params[i], 1); } } g_strfreev (params); } xmms_medialib_decode_url (durl); xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "application/x-url", XMMS_STREAM_TYPE_URL, durl, XMMS_STREAM_TYPE_END); g_free (durl); last = xform; do { xform = xmms_xform_find (last, entry, goal_formats); if (!xform) { xmms_log_error ("Couldn't set up chain for '%s' (%d)", url, entry); xmms_object_unref (last); return NULL; } xmms_object_unref (last); last = xform; } while (!has_goalformat (xform, goal_formats)); outdata_type_metadata_collect (last); return last; }
static void xmms_asf_get_mediainfo (xmms_xform_t *xform) { xmms_asf_data_t *data; asf_metadata_t *metadata; uint64_t tmp; gint i; g_return_if_fail (xform); data = xmms_xform_private_data_get (xform); g_return_if_fail (data); if ((tmp = asf_get_duration (data->file)) > 0) { xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION, tmp/10000); } if ((tmp = asf_get_max_bitrate (data->file)) > 0) { xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_BITRATE, tmp); } metadata = asf_header_get_metadata (data->file); if (!metadata) { XMMS_DBG ("No metadata object found in the file"); return; } if (metadata->title && metadata->title[0]) { xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_TITLE, metadata->title); } if (metadata->artist && metadata->artist[0]) { xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST, metadata->artist); } if (metadata->description && metadata->description[0]) { xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_COMMENT, metadata->description); } for (i = 0; i < metadata->extended_count; i++) { const char *key, *value; guint16 length; key = metadata->extended[i].key; value = metadata->extended[i].value; length = metadata->extended[i].length; if (!xmms_xform_metadata_mapper_match (xform, key, value, length)) { XMMS_DBG ("Unhandled tag '%s' = '%s'", key, value); } } asf_metadata_destroy (metadata); }
static gboolean xmms_asf_handle_tag_coverart (xmms_xform_t *xform, const gchar *key, const gchar *value, gsize length) { const guint8 *uptr; const gchar *ptr; gchar *mime; gchar hash[33]; guint32 picture_length; gsize size; GError *err = NULL; uptr = (const guchar *) value; /* check picture type */ if (uptr[0] != 0x00 && uptr[0] != 0x03) { return FALSE; } /* step past picture type */ uptr++; picture_length = ((guint32) uptr[3] << 24) | ((guint32) uptr[2] << 16) | ((guint32) uptr[1] << 8) | ((guint32) uptr[0]); if (picture_length == 0) { return FALSE; } /* step past picture size */ uptr += sizeof (guint32); ptr = (const gchar *) uptr; /* parse the UTF-16 mime type */ size = xmms_asf_utf16_strnlen (ptr, (value + length) - ptr); mime = g_convert (ptr, size, "UTF-8", "UTF-16", NULL, NULL, &err); ptr += size + 2; if (mime == NULL || mime[0] == '\0') { return FALSE; } /* step past picture description */ size = xmms_asf_utf16_strnlen (ptr, (value + length) - ptr); ptr += size + 2; uptr = (const guchar *) ptr; if (xmms_bindata_plugin_add (uptr, picture_length, hash)) { const gchar *metakey; metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_PICTURE_FRONT; xmms_xform_metadata_set_str (xform, metakey, hash); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_PICTURE_FRONT_MIME; xmms_xform_metadata_set_str (xform, metakey, mime); } g_free (mime); return TRUE; }
static void xmms_sid_get_songlength (xmms_xform_t *xform) { xmms_config_property_t *config; const gchar *tmp, *md5sum, *songlength_path; gint subtune = 1; GIOChannel* io; GString *buf; g_return_if_fail (xform); config = xmms_xform_config_lookup (xform, "songlength_path"); g_return_if_fail (config); songlength_path = xmms_config_property_get_string (config); if (!songlength_path[0]) return; if (xmms_xform_metadata_get_str (xform, "subtune", &tmp)) { subtune = atoi (tmp); } if (!xmms_xform_metadata_get_str (xform, "HVSCfingerprint", &md5sum)) { return; } io = g_io_channel_new_file (songlength_path, "r", NULL); if (!io) { xmms_log_error ("Unable to load songlengths database '%s'", songlength_path); return; } buf = g_string_new (""); while (g_io_channel_read_line_string (io, buf, NULL, NULL) == G_IO_STATUS_NORMAL) { if (buf->len > 33 && g_ascii_strncasecmp (buf->str, md5sum, 32) == 0) { gint cur = 0; gchar *b; b = buf->str + 33; while (*b) { gint min, sec; /* read timestamp */ if (sscanf (b, "%d:%d", &min, &sec) != 2) { /* no more timestamps on this line */ break; } else { cur++; } if (cur == subtune) { const gchar *metakey; gchar ms_str[10 + 1]; /* LONG_MAX in str, \w NULL */ glong ms; ms = (min * 60 + sec) * 1000; metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION; xmms_xform_metadata_set_int (xform, metakey, ms); if (g_snprintf (ms_str, 10 + 1, "%ld", ms) > 0) { metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_STARTMS; xmms_xform_metadata_set_str (xform, metakey, "0"); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_STOPMS; xmms_xform_metadata_set_str (xform, metakey, ms_str); } goto done; } /* forward to next possible timestamp */ b = strchr (b, ' '); if (!b) { /* no more timestamps on this line */ break; } b++; } } } xmms_log_info ("Couldn't find sid tune in songlength.txt"); done: g_io_channel_unref (io); }
static gboolean xmms_modplug_init (xmms_xform_t *xform) { xmms_modplug_data_t *data; const gchar *metakey; gint filesize; xmms_config_property_t *cfgv; gint i; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_modplug_data_t, 1); xmms_xform_private_data_set (xform, data); for (i = 0; i < G_N_ELEMENTS (config_params); i++) { cfgv = xmms_xform_config_lookup (xform, config_params[i].key); xmms_config_property_callback_set (cfgv, xmms_modplug_config_changed, data); xmms_modplug_config_changed (XMMS_OBJECT (cfgv), NULL, data); } /* mFrequency and mResamplingMode are set in config_changed */ data->settings.mChannels = 2; data->settings.mBits = 16; ModPlug_SetSettings (&data->settings); 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, 2, XMMS_STREAM_TYPE_FMT_SAMPLERATE, data->settings.mFrequency, XMMS_STREAM_TYPE_END); data->buffer = g_string_new (""); for (;;) { xmms_error_t error; gchar buf[4096]; gint ret; ret = xmms_xform_read (xform, buf, sizeof (buf), &error); if (ret == -1) { XMMS_DBG ("Error reading mod"); return FALSE; } if (ret == 0) { break; } g_string_append_len (data->buffer, buf, ret); } data->mod = ModPlug_Load (data->buffer->str, data->buffer->len); if (!data->mod) { XMMS_DBG ("Error loading mod"); return FALSE; } metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_SIZE; if (xmms_xform_metadata_get_int (xform, metakey, &filesize)) { metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION; xmms_xform_metadata_set_int (xform, metakey, ModPlug_GetLength (data->mod)); } metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_TITLE; xmms_xform_metadata_set_str (xform, metakey, ModPlug_GetName (data->mod)); return TRUE; }
static gboolean xmms_cdda_init (xmms_xform_t *xform) { CdIo_t *cdio = NULL; cdrom_drive_t *drive = NULL; const gchar *url; gchar **url_data = NULL; gchar *url_end; xmms_cdda_data_t *data; guint playtime; lsn_t first_lsn; track_t track; gchar *disc_id = NULL; gchar *cddb_id = NULL; xmms_config_property_t *val; const gchar *device; const gchar *metakey; gboolean ret = TRUE; g_return_val_if_fail (xform, FALSE); url = xmms_xform_indata_get_str (xform, XMMS_STREAM_TYPE_URL); if (g_ascii_strcasecmp (url, "cdda://") == 0) { xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "application/x-xmms2-playlist-entries", XMMS_STREAM_TYPE_END); return TRUE; } val = xmms_xform_config_lookup (xform, "device"); device = xmms_config_property_get_string (val); if (!get_disc_ids (device, &disc_id, &cddb_id, 0)) { return FALSE; } url += 7; url_data = g_strsplit (url, "/", 2); if (g_ascii_strcasecmp (url_data[0], disc_id)) { xmms_log_error ("Wrong disc inserted."); ret = FALSE; goto end; } if (url_data[1] == NULL) { xmms_log_error ("Missing track number."); ret = FALSE; goto end; } track = strtol (url_data[1], &url_end, 10); if (url_data[1] == url_end) { xmms_log_error ("Invalid track, need a number."); ret = FALSE; goto end; } cdio = open_cd (xform); if (!cdio) { ret = FALSE; goto end; } drive = cdio_cddap_identify_cdio (cdio, 1, NULL); if (!drive) { xmms_log_error ("Failed to identify drive."); ret = FALSE; goto end; } if (cdio_cddap_open (drive)) { xmms_log_error ("Unable to open disc."); ret = FALSE; goto end; } first_lsn = cdio_cddap_track_firstsector (drive, track); if (first_lsn == -1) { xmms_log_error ("No such track."); ret = FALSE; goto end; } data = g_new (xmms_cdda_data_t, 1); data->cdio = cdio; data->drive = drive; data->track = track; data->first_lsn = first_lsn; data->last_lsn = cdio_cddap_track_lastsector (drive, data->track); data->current_lsn = first_lsn; data->buf_used = CDIO_CD_FRAMESIZE_RAW; playtime = (data->last_lsn - data->first_lsn) * 1000.0 / CDIO_CD_FRAMES_PER_SEC; metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION; xmms_xform_metadata_set_int (xform, metakey, playtime); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_BITRATE; xmms_xform_metadata_set_int (xform, metakey, 141120); xmms_xform_metadata_set_str (xform, "disc_id", url_data[0]); xmms_xform_metadata_set_str (xform, "cddb_id", cddb_id); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_TRACKNR; xmms_xform_metadata_set_int (xform, metakey, track); xmms_xform_private_data_set (xform, data); 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, 2, XMMS_STREAM_TYPE_FMT_SAMPLERATE, 44100, XMMS_STREAM_TYPE_END); end: /* These are to be destroyed in every cases... */ g_free (cddb_id); g_free (disc_id); g_strfreev (url_data); /* destroy cdio/drive in case of failure */ if (!ret) { if (drive) { cdio_cddap_close_no_free_cdio (drive); } if (cdio) { cdio_destroy (cdio); } } return ret; }
static gboolean xmms_id3v1_parse (xmms_xform_t *xform, guchar *buf) { xmms_config_property_t *config; const char *encoding; const gchar *metakey; xmmsv_t *bb; unsigned char data[32]; bb = xmmsv_new_bitbuffer_ro (buf, 128); xmmsv_bitbuffer_get_data (bb, data, 3); if (memcmp (data, "TAG", 3) != 0) { xmmsv_unref (bb); return FALSE; } XMMS_DBG ("Found ID3v1 TAG!"); config = xmms_xform_config_lookup (xform, "id3v1_encoding"); g_return_val_if_fail (config, FALSE); encoding = xmms_config_property_get_string (config); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_TITLE; xmmsv_bitbuffer_get_data (bb, data, 30); xmms_id3v1_set (xform, metakey, data, 30, encoding); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST; xmmsv_bitbuffer_get_data (bb, data, 30); xmms_id3v1_set (xform, metakey, data, 30, encoding); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM; xmmsv_bitbuffer_get_data (bb, data, 30); xmms_id3v1_set (xform, metakey, data, 30, encoding); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_YEAR; xmmsv_bitbuffer_get_data (bb, data, 4); xmms_id3v1_set (xform, metakey, data, 4, encoding); xmmsv_bitbuffer_get_data (bb, data, 30); /* v1.1 */ if (data[28] == '\0' && data[29]) { metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_COMMENT; xmms_id3v1_set (xform, metakey, data, 28, encoding); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_TRACKNR; if (!xmms_xform_metadata_has_val (xform, metakey)) { xmms_xform_metadata_set_int (xform, metakey, data[29]); } } else { metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_COMMENT; xmms_id3v1_set (xform, metakey, data, 30, encoding); } xmmsv_bitbuffer_get_data (bb, data, 1); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_GENRE; if (data[0] >= G_N_ELEMENTS (id3_genres)) { xmms_xform_metadata_set_str (xform, metakey, "Unknown"); } else { xmms_xform_metadata_set_str (xform, metakey, id3_genres[data[0]]); } xmmsv_unref (bb); return TRUE; }