2 * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
4 * gstid3tag.c: plugin for reading / modifying id3 tags
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
26 #include "gsttageditingprivate.h"
30 static const gchar *genres[] = {
167 "Christian Gangsta Rap",
171 "Contemporary Christian",
181 static GstTagEntryMatch tag_matches[] = {
182 {GST_TAG_TITLE, "TIT2"},
183 {GST_TAG_ALBUM, "TALB"},
184 {GST_TAG_TRACK_NUMBER, "TRCK"},
185 {GST_TAG_ARTIST, "TPE1"},
186 {GST_TAG_COPYRIGHT, "TCOP"},
187 {GST_TAG_GENRE, "TCON"},
188 {GST_TAG_DATE, "TDRC"},
189 {GST_TAG_COMMENT, "COMM"},
190 {GST_TAG_ALBUM_VOLUME_NUMBER, "TPOS"},
191 {GST_TAG_DURATION, "TLEN"},
196 * gst_tag_from_id3_tag:
197 * @id3_tag: ID3v2 tag to convert to GStreamer tag
199 * Looks up the GStreamer tag for a ID3v2 tag.
201 * Returns: The corresponding GStreamer tag or NULL if none exists.
203 G_CONST_RETURN gchar *
204 gst_tag_from_id3_tag (const gchar * id3_tag)
208 g_return_val_if_fail (id3_tag != NULL, NULL);
210 while (tag_matches[i].gstreamer_tag != NULL) {
211 if (strncmp (id3_tag, tag_matches[i].original_tag, 5) == 0) {
212 return tag_matches[i].gstreamer_tag;
217 GST_INFO ("Cannot map ID3v2 tag '%c%c%c%c' to GStreamer tag",
218 id3_tag[0], id3_tag[1], id3_tag[2], id3_tag[3]);
224 * gst_tag_to_id3_tag:
225 * @gst_tag: GStreamer tag to convert to vorbiscomment tag
227 * Looks up the ID3v2 tag for a GStreamer tag.
229 * Returns: The corresponding ID3v2 tag or NULL if none exists.
231 G_CONST_RETURN gchar *
232 gst_tag_to_id3_tag (const gchar * gst_tag)
236 g_return_val_if_fail (gst_tag != NULL, NULL);
238 while (tag_matches[i].gstreamer_tag != NULL) {
239 if (strcmp (gst_tag, tag_matches[i].gstreamer_tag) == 0) {
240 return tag_matches[i].original_tag;
248 gst_tag_extract_id3v1_string (GstTagList * list, const gchar * tag,
249 const gchar * start, const guint size)
255 /* Should we try the charsets specified
256 * via environment variables FIRST ? */
257 if (g_utf8_validate (start, size, NULL)) {
258 utf8 = g_strndup (start, size);
262 env = g_getenv ("GST_ID3V1_TAG_ENCODING");
263 if (!env || *env == '\0')
264 env = g_getenv ("GST_ID3_TAG_ENCODING");
265 if (!env || *env == '\0')
266 env = g_getenv ("GST_TAG_ENCODING");
268 /* Try charsets specified via the environment */
269 if (env && *env != '\0') {
272 csets = g_strsplit (env, G_SEARCHPATH_SEPARATOR_S, -1);
274 for (c = csets; c && *c; ++c) {
276 g_convert (start, size, "UTF-8", *c, &bytes_read, NULL, NULL))) {
277 if (bytes_read == size) {
286 /* Try current locale (if not UTF-8) */
287 if (!g_get_charset (&env)) {
288 if ((utf8 = g_locale_to_utf8 (start, size, &bytes_read, NULL, NULL))) {
289 if (bytes_read == size) {
299 g_convert (start, size, "UTF-8", "ISO-8859-1", &bytes_read, NULL, NULL);
300 if (utf8 != NULL && bytes_read == size) {
310 if (utf8 && utf8[0] != '\0') {
311 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, tag, utf8, NULL);
318 * gst_tag_list_new_from_id3v1:
319 * @data: 128 bytes of data containing the ID3v1 tag
321 * Parses the data containing an ID3v1 tag and returns a #GstTagList from the
324 * Returns: A new tag list or NULL if the data was not an ID3v1 tag.
327 gst_tag_list_new_from_id3v1 (const guint8 * data)
333 g_return_val_if_fail (data != NULL, NULL);
335 if (data[0] != 'T' || data[1] != 'A' || data[2] != 'G')
337 list = gst_tag_list_new ();
338 gst_tag_extract_id3v1_string (list, GST_TAG_TITLE, (gchar *) & data[3], 30);
339 gst_tag_extract_id3v1_string (list, GST_TAG_ARTIST, (gchar *) & data[33], 30);
340 gst_tag_extract_id3v1_string (list, GST_TAG_ALBUM, (gchar *) & data[63], 30);
341 ystr = g_strndup ((gchar *) & data[93], 4);
342 year = strtoul (ystr, NULL, 10);
345 GDate *date = g_date_new_dmy (1, 1, year);
347 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_DATE, date, NULL);
350 if (data[125] == 0) {
351 gst_tag_extract_id3v1_string (list, GST_TAG_COMMENT, (gchar *) & data[97],
353 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_TRACK_NUMBER,
354 (guint) data[126], NULL);
356 gst_tag_extract_id3v1_string (list, GST_TAG_COMMENT, (gchar *) & data[97],
359 if (data[127] < gst_tag_id3_genre_count ()) {
360 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_GENRE,
361 gst_tag_id3_genre_get (data[127]), NULL);
368 * gst_tag_id3_genre_count:
370 * Gets the number of ID3v1 genres that can be identified. Winamp genres are
373 * Returns: the number of ID3v1 genres that can be identified
376 gst_tag_id3_genre_count (void)
378 return G_N_ELEMENTS (genres);
382 * gst_tag_id3_genre_get:
383 * @id: ID of genre to query
385 * Gets the ID3v1 genre name for a given ID.
387 * Returns: the genre or NULL if no genre is associated with that ID.
389 G_CONST_RETURN gchar *
390 gst_tag_id3_genre_get (const guint id)
392 if (id >= G_N_ELEMENTS (genres))