gst-libs/gst/tag/gstvorbistag.c: Serialise unknown vorbis comments into GST_TAG_EXTENDED_COMMENT tags and deserialise...

Original commit message from CVS:
* gst-libs/gst/tag/gstvorbistag.c: (gst_vorbis_tag_add),
(gst_tag_to_vorbis_comments):
Serialise unknown vorbis comments into GST_TAG_EXTENDED_COMMENT
tags and deserialise them properly as well (#351768).
Add some more gtk-doc blurbs and also some g_return_if_fail().
* tests/check/libs/tag.c: (GST_START_TEST),
(back_to_vorbis_comments), (taglists_are_equal), (tag_suite):
More tests.
This commit is contained in:
Tim-Philipp Müller 2006-08-17 16:52:06 +00:00
parent c973b2bf3e
commit e7c6df131b
3 changed files with 381 additions and 18 deletions

View file

@ -1,3 +1,15 @@
2006-08-17 Tim-Philipp Müller <tim at centricular dot net>
* gst-libs/gst/tag/gstvorbistag.c: (gst_vorbis_tag_add),
(gst_tag_to_vorbis_comments):
Serialise unknown vorbis comments into GST_TAG_EXTENDED_COMMENT
tags and deserialise them properly as well (#351768).
Add some more gtk-doc blurbs and also some g_return_if_fail().
* tests/check/libs/tag.c: (GST_START_TEST),
(back_to_vorbis_comments), (taglists_are_equal), (tag_suite):
More tests.
2006-08-17 Wim Taymans <wim@fluendo.com> 2006-08-17 Wim Taymans <wim@fluendo.com>
* ext/ogg/Makefile.am: * ext/ogg/Makefile.am:

View file

@ -130,14 +130,43 @@ gst_tag_to_vorbis_tag (const gchar * gst_tag)
} }
/**
* gst_vorbis_tag_add:
* @list: a #GstTagList
* @tag: a vorbiscomment tag string (key in key=value), must be valid UTF-8
* @val: a vorbiscomment value string (value in key=value), must be valid UTF-8
*
* Convenience function using gst_tag_from_vorbis_tag(), parsing
* a vorbis comment string into the right type and adding it to the
* given taglist @list.
*
* Unknown vorbiscomment tags will be added to the tag list in form
* of a #GST_TAG_EXTENDED_COMMENT (since 0.10.10 at least).
*/
void void
gst_vorbis_tag_add (GstTagList * list, const gchar * tag, const gchar * value) gst_vorbis_tag_add (GstTagList * list, const gchar * tag, const gchar * value)
{ {
const gchar *gst_tag = gst_tag_from_vorbis_tag (tag); const gchar *gst_tag;
GType tag_type; GType tag_type;
if (gst_tag == NULL) g_return_if_fail (list != NULL);
g_return_if_fail (tag != NULL);
g_return_if_fail (value != NULL);
g_return_if_fail (g_utf8_validate (tag, -1, NULL));
g_return_if_fail (g_utf8_validate (value, -1, NULL));
g_return_if_fail (strchr (tag, '=') == NULL);
gst_tag = gst_tag_from_vorbis_tag (tag);
if (gst_tag == NULL) {
gchar *ext_comment;
ext_comment = g_strdup_printf ("%s=%s", tag, value);
gst_tag_list_add (list, GST_TAG_MERGE_APPEND, GST_TAG_EXTENDED_COMMENT,
ext_comment, NULL);
g_free (ext_comment);
return; return;
}
tag_type = gst_tag_get_type (gst_tag); tag_type = gst_tag_get_type (gst_tag);
switch (tag_type) { switch (tag_type) {
@ -177,22 +206,18 @@ gst_vorbis_tag_add (GstTagList * list, const gchar * tag, const gchar * value)
if (strcmp (tag, "LANGUAGE") == 0) { if (strcmp (tag, "LANGUAGE") == 0) {
const gchar *s = strchr (value, '['); const gchar *s = strchr (value, '[');
/* FIXME: gsttaglist.h says our language tag contains ISO-639-1 /* Accept both ISO-639-1 and ISO-639-2 codes */
* codes, which are 2 letter codes. The code below extracts 3-letter
* identifiers, which would be ISO-639-2. Mixup? Oversight? Wrong core
* docs? What do files in the wild contain? (tpm) */
if (s && strchr (s, ']') == s + 4) { if (s && strchr (s, ']') == s + 4) {
valid = g_strndup (s + 1, 3); valid = g_strndup (s + 1, 3);
} else if (s && strchr (s, ']') == s + 3) {
valid = g_strndup (s + 1, 2);
} else if (strlen (value) != 2 && strlen (value) != 3) {
GST_WARNING ("doesn't contain an ISO-639 language code: %s", value);
} }
} }
if (!valid) { if (!valid) {
if (!g_utf8_validate (value, -1, (const gchar **) &valid)) { valid = g_strdup (value);
valid = g_strndup (value, valid - value);
GST_DEBUG ("Invalid vorbis comment tag, truncated it to %s", valid);
} else {
valid = g_strdup (value);
}
} }
gst_tag_list_add (list, GST_TAG_MERGE_APPEND, gst_tag, valid, NULL); gst_tag_list_add (list, GST_TAG_MERGE_APPEND, gst_tag, valid, NULL);
g_free (valid); g_free (valid);
@ -322,15 +347,32 @@ typedef struct
} }
MyForEach; MyForEach;
/**
* gst_tag_to_vorbis_comments:
* @list: a #GstTagList
* @tag: a GStreamer tag identifier, such as #GST_TAG_ARTIST
*
* Creates a new tag list that contains the information parsed out of a
* vorbiscomment packet.
*
* Returns: A #GList of newly-allowcated key=value strings. Free with
* g_list_foreach (list, (GFunc) g_free, NULL) plus g_list_free (list)
*/
GList * GList *
gst_tag_to_vorbis_comments (const GstTagList * list, const gchar * tag) gst_tag_to_vorbis_comments (const GstTagList * list, const gchar * tag)
{ {
const gchar *vorbis_tag = NULL;
GList *l = NULL; GList *l = NULL;
guint i; guint i;
const gchar *vorbis_tag = gst_tag_to_vorbis_tag (tag);
if (!vorbis_tag) g_return_val_if_fail (list != NULL, NULL);
return NULL; g_return_val_if_fail (tag != NULL, NULL);
if (strcmp (tag, GST_TAG_EXTENDED_COMMENT) != 0) {
vorbis_tag = gst_tag_to_vorbis_tag (tag);
if (!vorbis_tag)
return NULL;
}
for (i = 0; i < gst_tag_list_get_tag_size (list, tag); i++) { for (i = 0; i < gst_tag_list_get_tag_size (list, tag); i++) {
GType tag_type = gst_tag_get_type (tag); GType tag_type = gst_tag_get_type (tag);
@ -346,11 +388,25 @@ gst_tag_to_vorbis_comments (const GstTagList * list, const gchar * tag)
break; break;
} }
case G_TYPE_STRING:{ case G_TYPE_STRING:{
gchar *str; gchar *str = NULL;
if (!gst_tag_list_get_string_index (list, tag, i, &str)) if (!gst_tag_list_get_string_index (list, tag, i, &str))
g_return_val_if_reached (NULL); g_return_val_if_reached (NULL);
result = g_strdup_printf ("%s=%s", vorbis_tag, str);
/* special case: GST_TAG_EXTENDED_COMMENT */
if (vorbis_tag == NULL) {
gchar *key = NULL, *val = NULL;
if (gst_tag_parse_extended_comment (str, &key, NULL, &val, TRUE)) {
result = g_strdup_printf ("%s=%s", key, val);
g_free (key);
g_free (val);
} else {
GST_WARNING ("Not a valid extended comment string: %s", str);
}
} else {
result = g_strdup_printf ("%s=%s", vorbis_tag, str);
}
g_free (str); g_free (str);
break; break;
} }
@ -404,6 +460,8 @@ write_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
data->data_count += strlen (result); data->data_count += strlen (result);
data->entries = g_list_prepend (data->entries, result); data->entries = g_list_prepend (data->entries, result);
} }
g_list_free (comments);
} }
/** /**

View file

@ -133,6 +133,297 @@ GST_START_TEST (test_parse_extended_comment)
GST_END_TEST; GST_END_TEST;
#define ASSERT_TAG_LIST_HAS_STRING(list,field,string) \
{ \
gboolean got_match = FALSE; \
guint i, size; \
\
fail_unless (gst_tag_list_get_tag_size (list,field) > 0); \
size = gst_tag_list_get_tag_size (list,field); \
for (i = 0; i < size; ++i) { \
gchar *___s = NULL; \
\
fail_unless (gst_tag_list_get_string_index (list, field, i, &___s)); \
fail_unless (___s != NULL); \
if (g_str_equal (___s, string)) { \
got_match = TRUE; \
g_free (___s); \
break; \
} \
g_free (___s); \
} \
fail_unless (got_match); \
}
#define ASSERT_TAG_LIST_HAS_UINT(list,field,num) \
{ \
guint ___n; \
\
fail_unless (gst_tag_list_get_tag_size (list,field) > 0); \
fail_unless (gst_tag_list_get_tag_size (list,field) == 1); \
fail_unless (gst_tag_list_get_uint_index (list, field, 0, &___n)); \
fail_unless_equals_int (___n, num); \
}
GST_START_TEST (test_muscibrainz_tag_registration)
{
GstTagList *list;
gst_tag_register_musicbrainz_tags ();
list = gst_tag_list_new ();
/* musicbrainz tags aren't registered yet */
gst_vorbis_tag_add (list, "MUSICBRAINZ_TRACKID", "123456");
gst_vorbis_tag_add (list, "MUSICBRAINZ_ARTISTID", "234567");
gst_vorbis_tag_add (list, "MUSICBRAINZ_ALBUMID", "345678");
gst_vorbis_tag_add (list, "MUSICBRAINZ_ALBUMARTISTID", "4567890");
gst_vorbis_tag_add (list, "MUSICBRAINZ_TRMID", "5678901");
gst_vorbis_tag_add (list, "MUSICBRAINZ_SORTNAME", "Five, 678901");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_MUSICBRAINZ_TRACKID, "123456");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_MUSICBRAINZ_ARTISTID, "234567");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_MUSICBRAINZ_ALBUMID, "345678");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_MUSICBRAINZ_ALBUMARTISTID,
"4567890");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_MUSICBRAINZ_TRMID, "5678901");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_MUSICBRAINZ_SORTNAME,
"Five, 678901");
gst_tag_list_free (list);
}
GST_END_TEST;
/* is there an easier way to compare two structures / tagslists? */
static gboolean
taglists_are_equal (const GstTagList * list_1, const GstTagList * list_2)
{
GstCaps *c_list_1 = gst_caps_new_empty ();
GstCaps *c_list_2 = gst_caps_new_empty ();
gboolean ret;
gst_caps_append_structure (c_list_1,
gst_structure_copy ((GstStructure *) list_1));
gst_caps_append_structure (c_list_2,
gst_structure_copy ((GstStructure *) list_2));
ret = gst_caps_is_equal (c_list_2, c_list_1);
gst_caps_unref (c_list_1);
gst_caps_unref (c_list_2);
}
GST_START_TEST (test_vorbis_tags)
{
GstTagList *list;
list = gst_tag_list_new ();
/* NULL pointers aren't allowed */
ASSERT_CRITICAL (gst_vorbis_tag_add (NULL, "key", "value"));
ASSERT_CRITICAL (gst_vorbis_tag_add (list, NULL, "value"));
ASSERT_CRITICAL (gst_vorbis_tag_add (list, "key", NULL));
/* must be UTF-8 */
ASSERT_CRITICAL (gst_vorbis_tag_add (list, "key", "v\777lue"));
ASSERT_CRITICAL (gst_vorbis_tag_add (list, "k\777y", "value"));
/* key can't have a '=' in it */
ASSERT_CRITICAL (gst_vorbis_tag_add (list, "k=y", "value"));
ASSERT_CRITICAL (gst_vorbis_tag_add (list, "key=", "value"));
/* should be allowed in values though */
gst_vorbis_tag_add (list, "keeey", "va=ue");
/* add some tags */
gst_vorbis_tag_add (list, "TITLE", "Too");
gst_vorbis_tag_add (list, "ALBUM", "Aoo");
gst_vorbis_tag_add (list, "ARTIST", "Alboo");
gst_vorbis_tag_add (list, "PERFORMER", "Perfoo");
gst_vorbis_tag_add (list, "COPYRIGHT", "Copyfoo");
gst_vorbis_tag_add (list, "DESCRIPTION", "Descoo");
gst_vorbis_tag_add (list, "LICENSE", "Licoo");
gst_vorbis_tag_add (list, "ORGANIZATION", "Orgoo");
gst_vorbis_tag_add (list, "GENRE", "Goo");
gst_vorbis_tag_add (list, "CONTACT", "Coo");
gst_vorbis_tag_add (list, "COMMENT", "Stroodle is good");
gst_vorbis_tag_add (list, "COMMENT", "Peroxysulfid stroodles the brain");
gst_vorbis_tag_add (list, "TRACKNUMBER", "5");
gst_vorbis_tag_add (list, "TRACKTOTAL", "77");
gst_vorbis_tag_add (list, "DISCNUMBER", "1");
gst_vorbis_tag_add (list, "DISCTOTAL", "2");
gst_vorbis_tag_add (list, "DATE", "1954-12-31");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_TITLE, "Too");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_ALBUM, "Aoo");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_ARTIST, "Alboo");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_PERFORMER, "Perfoo");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_COPYRIGHT, "Copyfoo");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_DESCRIPTION, "Descoo");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_LICENSE, "Licoo");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_ORGANIZATION, "Orgoo");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_GENRE, "Goo");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_CONTACT, "Coo");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_COMMENT,
"Peroxysulfid stroodles the brain");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_COMMENT, "Stroodle is good");
ASSERT_TAG_LIST_HAS_UINT (list, GST_TAG_TRACK_NUMBER, 5);
ASSERT_TAG_LIST_HAS_UINT (list, GST_TAG_TRACK_COUNT, 77);
ASSERT_TAG_LIST_HAS_UINT (list, GST_TAG_ALBUM_VOLUME_NUMBER, 1);
ASSERT_TAG_LIST_HAS_UINT (list, GST_TAG_ALBUM_VOLUME_COUNT, 2);
{
GDate *date = NULL;
fail_unless (gst_tag_list_get_date (list, GST_TAG_DATE, &date));
fail_unless (date != NULL);
fail_unless (g_date_get_day (date) == 31);
fail_unless (g_date_get_month (date) == G_DATE_DECEMBER);
fail_unless (g_date_get_year (date) == 1954);
g_date_free (date);
}
/* unknown vorbis comments should go into a GST_TAG_EXTENDED_COMMENT */
gst_vorbis_tag_add (list, "CoEdSub_ID", "98172AF-973-10-B");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_EXTENDED_COMMENT,
"CoEdSub_ID=98172AF-973-10-B");
gst_vorbis_tag_add (list, "RuBuWuHash", "1337BA42F91");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_EXTENDED_COMMENT,
"RuBuWuHash=1337BA42F91");
#if 0
/* TODO: test these as well */
{
GST_TAG_TRACK_GAIN, "REPLAYGAIN_TRACK_GAIN"}, {
GST_TAG_TRACK_PEAK, "REPLAYGAIN_TRACK_PEAK"}, {
GST_TAG_ALBUM_GAIN, "REPLAYGAIN_ALBUM_GAIN"}, {
GST_TAG_ALBUM_PEAK, "REPLAYGAIN_ALBUM_PEAK"}, {
GST_TAG_LANGUAGE_CODE, "LANGUAGE"},
#endif
/* make sure we can convert back and forth without loss */
{
GstTagList *new_list, *even_newer_list;
GstBuffer *buf, *buf2;
gchar *vendor_id = NULL;
buf = gst_tag_list_to_vorbiscomment_buffer (list,
(const guint8 *) "\003vorbis", 7, "libgstunittest");
fail_unless (buf != NULL);
new_list = gst_tag_list_from_vorbiscomment_buffer (buf,
(const guint8 *) "\003vorbis", 7, &vendor_id);
fail_unless (new_list != NULL);
fail_unless (vendor_id != NULL);
g_free (vendor_id);
vendor_id = NULL;
GST_LOG ("new_list = %" GST_PTR_FORMAT, new_list);
fail_unless (taglists_are_equal (list, new_list));
buf2 = gst_tag_list_to_vorbiscomment_buffer (new_list,
(const guint8 *) "\003vorbis", 7, "libgstunittest");
fail_unless (buf2 != NULL);
even_newer_list = gst_tag_list_from_vorbiscomment_buffer (buf2,
(const guint8 *) "\003vorbis", 7, &vendor_id);
fail_unless (even_newer_list != NULL);
fail_unless (vendor_id != NULL);
g_free (vendor_id);
vendor_id = NULL;
GST_LOG ("even_newer_list = %" GST_PTR_FORMAT, even_newer_list);
fail_unless (taglists_are_equal (new_list, even_newer_list));
gst_tag_list_free (new_list);
gst_tag_list_free (even_newer_list);
gst_buffer_unref (buf);
gst_buffer_unref (buf2);
}
/* there can only be one language per taglist ... */
gst_tag_list_free (list);
list = gst_tag_list_new ();
gst_vorbis_tag_add (list, "LANGUAGE", "fr");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_LANGUAGE_CODE, "fr");
gst_tag_list_free (list);
list = gst_tag_list_new ();
gst_vorbis_tag_add (list, "LANGUAGE", "[fr]");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_LANGUAGE_CODE, "fr");
gst_tag_list_free (list);
list = gst_tag_list_new ();
gst_vorbis_tag_add (list, "LANGUAGE", "French [fr]");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_LANGUAGE_CODE, "fr");
gst_tag_list_free (list);
list = gst_tag_list_new ();
gst_vorbis_tag_add (list, "LANGUAGE", "[eng] English");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_LANGUAGE_CODE, "eng");
gst_tag_list_free (list);
list = gst_tag_list_new ();
gst_vorbis_tag_add (list, "LANGUAGE", "eng");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_LANGUAGE_CODE, "eng");
gst_tag_list_free (list);
list = gst_tag_list_new ();
gst_vorbis_tag_add (list, "LANGUAGE", "[eng]");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_LANGUAGE_CODE, "eng");
/* free-form *sigh* */
gst_tag_list_free (list);
list = gst_tag_list_new ();
gst_vorbis_tag_add (list, "LANGUAGE", "English");
ASSERT_TAG_LIST_HAS_STRING (list, GST_TAG_LANGUAGE_CODE, "English");
gst_tag_list_free (list);
}
GST_END_TEST;
GST_START_TEST (test_id3_tags)
{
guint i;
fail_unless (gst_tag_id3_genre_count () > 0);
for (i = 0; i < gst_tag_id3_genre_count (); ++i) {
const gchar *genre;
genre = gst_tag_id3_genre_get (i);
fail_unless (genre != NULL);
}
{
/* TODO: GstTagList *gst_tag_list_new_from_id3v1 (const guint8 *data) */
}
/* gst_tag_from_id3_tag */
fail_unless (gst_tag_from_id3_tag ("TALB") != NULL);
ASSERT_CRITICAL (gst_tag_from_id3_tag (NULL));
fail_unless (gst_tag_from_id3_tag ("R2D2") == NULL);
/* gst_tag_from_id3_user_tag */
ASSERT_CRITICAL (gst_tag_from_id3_user_tag (NULL, "foo"));
ASSERT_CRITICAL (gst_tag_from_id3_user_tag ("foo", NULL));
fail_unless (gst_tag_from_id3_user_tag ("R2D2", "R2D2") == NULL);
/* gst_tag_to_id3_tag */
ASSERT_CRITICAL (gst_tag_to_id3_tag (NULL));
fail_unless (gst_tag_to_id3_tag ("R2D2") == NULL);
fail_unless (gst_tag_to_id3_tag (GST_TAG_ARTIST) != NULL);
fail_unless (GST_TYPE_TAG_IMAGE_TYPE != 0);
fail_unless (g_type_name (GST_TYPE_TAG_IMAGE_TYPE) != NULL);
}
GST_END_TEST;
static Suite * static Suite *
tag_suite (void) tag_suite (void)
{ {
@ -140,8 +431,10 @@ tag_suite (void)
TCase *tc_chain = tcase_create ("general"); TCase *tc_chain = tcase_create ("general");
suite_add_tcase (s, tc_chain); suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_muscibrainz_tag_registration);
tcase_add_test (tc_chain, test_parse_extended_comment); tcase_add_test (tc_chain, test_parse_extended_comment);
tcase_add_test (tc_chain, test_vorbis_tags);
tcase_add_test (tc_chain, test_id3_tags);
return s; return s;
} }