static gboolean xmms_metadata_test_xform_init (xmms_xform_t *xform) { const gchar *musicbrainz_va_id = "89ad4ac3-39f7-470e-963a-56509c546377"; const gchar *title, *rpgain; gint track, totaltracks, compilation; CU_ASSERT_FALSE (xmms_xform_metadata_mapper_match (xform, "missing", "missing", -1)); /* Basic string mapping */ CU_ASSERT_TRUE (xmms_xform_metadata_mapper_match (xform, "title", "the title", -1)); CU_ASSERT_TRUE (xmms_xform_metadata_get_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_TITLE, &title)); CU_ASSERT_STRING_EQUAL ("the title", title); /* Mapping track number, without total tracks */ CU_ASSERT_TRUE (xmms_xform_metadata_mapper_match (xform, "tracknr", "1", -1)); CU_ASSERT_TRUE (xmms_xform_metadata_get_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_TRACKNR, &track)); CU_ASSERT_FALSE (xmms_xform_metadata_get_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_TOTALTRACKS, &totaltracks)); CU_ASSERT_EQUAL (1, track); /* Mapping track number, with total tracks */ CU_ASSERT_TRUE (xmms_xform_metadata_mapper_match (xform, "tracknr", "1/10", -1)); CU_ASSERT_TRUE (xmms_xform_metadata_get_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_TRACKNR, &track)); CU_ASSERT_TRUE (xmms_xform_metadata_get_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_TOTALTRACKS, &totaltracks)); CU_ASSERT_EQUAL (1, track); CU_ASSERT_EQUAL (10, totaltracks); /* Broken track number */ CU_ASSERT_FALSE (xmms_xform_metadata_mapper_match (xform, "tracknr", "bad", -1)); /* Mapping compilation indicator to boolean compilation */ CU_ASSERT_TRUE (xmms_xform_metadata_mapper_match (xform, "compilation", "1", -1)); CU_ASSERT_TRUE (xmms_xform_metadata_get_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_COMPILATION, &compilation)); CU_ASSERT_EQUAL (TRUE, compilation); /* Mapping compilation indicator to boolean compilation */ CU_ASSERT_TRUE (xmms_xform_metadata_mapper_match (xform, "compilation", musicbrainz_va_id, -1)); CU_ASSERT_TRUE (xmms_xform_metadata_get_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_COMPILATION, &compilation)); CU_ASSERT_EQUAL (TRUE, compilation); /* Mapping replaygain to the format the replaygain xform expects */ CU_ASSERT_TRUE (xmms_xform_metadata_mapper_match (xform, "replaygain_track_gain", "-14.69", -1)); CU_ASSERT_TRUE (xmms_xform_metadata_get_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_GAIN_TRACK, &rpgain)); CU_ASSERT_STRING_EQUAL ("0.18428", rpgain); CU_ASSERT_TRUE (xmms_xform_metadata_mapper_match (xform, "replaygain_track_gain", "-14.69 dB", -1)); CU_ASSERT_TRUE (xmms_xform_metadata_get_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_GAIN_TRACK, &rpgain)); CU_ASSERT_STRING_EQUAL ("0.18428", rpgain); CU_ASSERT_TRUE (xmms_xform_metadata_mapper_match (xform, "coverart", "test", 10)); xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_END); return TRUE; }
static void handle_comments (xmms_xform_t *xform, xmms_flac_data_t *data) { FLAC__StreamMetadata_VorbisComment *vc; gint i; g_return_if_fail (data->vorbiscomment); vc = &data->vorbiscomment->data.vorbis_comment; for (i = 0; i < vc->num_comments; i++) { const gchar *entry, *ptr; gchar key[64]; gsize length; entry = (const gchar *) vc->comments[i].entry; length = vc->comments[i].length; if (entry == NULL || *entry == '\0') continue; ptr = memchr (entry, '=', length); if (ptr == NULL) continue; ptr++; g_strlcpy (key, entry, MIN (ptr - entry, sizeof (key))); if (!xmms_xform_metadata_mapper_match (xform, key, ptr, length - (ptr - entry))) { XMMS_DBG ("Unhandled tag '%s'", entry); } } }
static gboolean xmms_asf_handle_tag_old_tracknr (xmms_xform_t *xform, const gchar *key, const gchar *value, gsize length) { gint ivalue; /* WM/TrackNumber overrides WM/Track value as specified in the Microsoft * documentation at http://msdn2.microsoft.com/en-us/library/aa392014.aspx * so lets check if something else has set the tracknr property before us. */ if (xmms_xform_metadata_get_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_TRACKNR, &ivalue)) { return FALSE; } /* Ok, nothing set, lets handle "WM/Track" as "WM/TrackNumber" */ if (!xmms_xform_metadata_mapper_match (xform, "WM/TrackNumber", value, length)) { return FALSE; } /* Last quirk, WM/Track is 0-indexed, need to fix that */ xmms_xform_metadata_get_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_TRACKNR, &ivalue); xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_TRACKNR, ivalue + 1); return TRUE; }
static void xmms_vorbis_read_metadata (xmms_xform_t *xform, xmms_vorbis_data_t *data) { vorbis_comment *vc; gint i; vc = ov_comment (&data->vorbisfile, -1); if (!vc) return; for (i = 0; i < vc->comments; i++) { const gchar *ptr, *entry; gsize length; gchar key[64]; entry = vc->user_comments[i]; length = vc->comment_lengths[i]; if (entry == NULL || *entry == '\0') continue; /* check whether it's a valid comment */ ptr = memchr (entry, '=', length); if (ptr == NULL) continue; ptr++; g_strlcpy (key, entry, MIN (ptr - entry, sizeof (key))); if (!xmms_xform_metadata_mapper_match (xform, key, ptr, length - (ptr - entry))) { XMMS_DBG ("Unhandled tag '%s'", entry); } } }
static void xmms_mp4_get_mediainfo (xmms_xform_t *xform) { xmms_mp4_data_t *data; const gchar *metakey; glong temp; gint i, num_items; g_return_if_fail (xform); data = xmms_xform_private_data_get (xform); g_return_if_fail (data); if ((temp = mp4ff_get_sample_rate (data->mp4ff, data->track)) > 0) { glong srate = temp; if ((temp = mp4ff_get_track_duration (data->mp4ff, data->track)) >= 0) { glong msec = ((gint64) temp) * 1000 / srate; metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION, xmms_xform_metadata_set_int (xform, metakey, msec); } } if ((temp = mp4ff_get_avg_bitrate (data->mp4ff, data->track)) >= 0) { metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_BITRATE; xmms_xform_metadata_set_int (xform, metakey, temp); } num_items = mp4ff_meta_get_num_items (data->mp4ff); for (i = 0; i < num_items; i++) { gchar *key, *value; guint length; length = mp4ff_meta_get_by_index (data->mp4ff, i, &key, &value); if (length > 0) { if (!xmms_xform_metadata_mapper_match (xform, key, value, length)) { /* iTunSMPB should be handled in xmms_mp4_gapless_try */ if (0 != g_ascii_strcasecmp (key, "iTunSMPB")) { XMMS_DBG ("Unhandled tag '%s' = '%s'", key, value); } } g_free (key); g_free (value); } } }
static void xmms_opus_read_metadata (xmms_xform_t *xform, xmms_opus_data_t *data) { data->opushead = op_head (data->opusfile, -1); data->opustags = op_tags (data->opusfile, -1); data->channels = op_channel_count (data->opusfile, -1); gint i; if (!data->opustags) return; for (i = 0; i < data->opustags->comments; i++) { const gchar *ptr, *entry; gsize length; gchar key[64]; entry = data->opustags->user_comments[i]; length = data->opustags->comment_lengths[i]; if (entry == NULL || *entry == '\0') continue; /* check whether it's a valid comment */ ptr = memchr (entry, '=', length); if (ptr == NULL) continue; ptr++; g_strlcpy (key, entry, MIN (ptr - entry, sizeof (key))); if (!xmms_xform_metadata_mapper_match (xform, key, ptr, length - (ptr - entry))) { XMMS_DBG ("Unhandled tag '%s'", entry); } } }
static gboolean xmms_apetag_read (xmms_xform_t *xform) { guchar buffer[32], *tagdata; xmms_error_t error; guint version, tag_size, items, flags; gint64 tag_position; gint pos, i, ret; g_return_val_if_fail (xform, FALSE); /* Try to find the 32-byte footer from the end of file */ tag_position = xmms_xform_seek (xform, -32, XMMS_XFORM_SEEK_END, &error); if (tag_position < 0) { /* Seeking failed, failed to read tags */ return FALSE; } /* Read footer data if seeking was possible */ ret = xmms_xform_read (xform, buffer, 32, &error); if (ret != 32) { xmms_log_error ("Failed to read APE tag footer"); return FALSE; } /* Check that the footer is valid, if not continue searching */ if (memcmp (buffer, "APETAGEX", 8)) { /* Try to find the 32-byte footer before 128-byte ID3v1 tag */ tag_position = xmms_xform_seek (xform, -160, XMMS_XFORM_SEEK_END, &error); if (tag_position < 0) { /* Seeking failed, failed to read tags */ xmms_log_error ("Failed to seek to APE tag footer"); return FALSE; } /* Read footer data if seeking was possible */ ret = xmms_xform_read (xform, buffer, 32, &error); if (ret != 32) { xmms_log_error ("Failed to read APE tag footer"); return FALSE; } if (memcmp (buffer, "APETAGEX", 8)) { /* Didn't find any APE tag from the file */ return FALSE; } } version = xmms_apetag_get_le32 (buffer + 8); tag_size = xmms_apetag_get_le32 (buffer + 12); items = xmms_apetag_get_le32 (buffer + 16); flags = xmms_apetag_get_le32 (buffer + 20); if (flags & APE_TAG_FLAG_IS_HEADER) { /* We need a footer, not a header... */ return FALSE; } if (version != 1000 && version != 2000) { xmms_log_error ("Invalid tag version, the writer is probably corrupted!"); return FALSE; } /* Seek to the beginning of the actual tag data */ ret = xmms_xform_seek (xform, tag_position - tag_size + 32, XMMS_XFORM_SEEK_SET, &error); if (ret < 0) { xmms_log_error ("Couldn't seek to the tag starting position, returned %d", ret); return FALSE; } tagdata = g_malloc (tag_size); ret = xmms_xform_read (xform, tagdata, tag_size, &error); if (ret != tag_size) { xmms_log_error ("Couldn't read the tag data, returned %d", ret); g_free (tagdata); return FALSE; } pos = 0; for (i = 0; i < items; i++) { gint itemlen, flags; gchar *key, *item; itemlen = xmms_apetag_get_le32 (tagdata + pos); pos += 4; flags = xmms_apetag_get_le32 (tagdata + pos); pos += 4; key = (gchar *) tagdata + pos; pos += strlen (key) + 1; switch (flags & APE_TAG_FLAG_DATA_TYPE) { case APE_TAG_DATA_TYPE_UTF8: item = g_strndup ((gchar *) tagdata + pos, itemlen); break; case APE_TAG_DATA_TYPE_BINARY: item = g_malloc (itemlen); memcpy (item, tagdata + pos, itemlen); break; case APE_TAG_DATA_TYPE_LOCATOR: item = NULL; break; } if (item != NULL && !xmms_xform_metadata_mapper_match (xform, key, item, itemlen)) { if ((flags & APE_TAG_FLAG_DATA_TYPE) == APE_TAG_DATA_TYPE_UTF8) { XMMS_DBG ("Unhandled tag '%s' = '%s'", key, item); } else { XMMS_DBG ("Unhandled tag '%s' = '(binary)'", key); } } g_free (item); pos += itemlen; } g_free (tagdata); return TRUE; }
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); }