Index: gst/id3demux/gstid3demux.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/gst/id3demux/gstid3demux.c,v
retrieving revision 1.27
diff -u -r1.27 gstid3demux.c
--- gst/id3demux/gstid3demux.c	12 Mar 2007 17:24:23 -0000	1.27
+++ gst/id3demux/gstid3demux.c	11 Apr 2007 16:33:36 -0000
@@ -60,7 +60,8 @@
 enum
 {
   ARG_0,
-  ARG_PREFER_V1
+  ARG_PREFER_V1,
+  ARG_PREFER_CHARSET
 };
 
 /* Require at least 4kB of data before we attempt typefind. 
@@ -70,6 +71,8 @@
 #define ID3_TYPE_FIND_MIN_SIZE 4096
 #define ID3_TYPE_FIND_MAX_SIZE 40960
 
+#define DEFAULT_PROP_TAG_CHARSET NULL
+
 GST_DEBUG_CATEGORY (id3demux_debug);
 #define GST_CAT_DEFAULT (id3demux_debug)
 
@@ -178,6 +181,11 @@
           "Prefer tags from ID3v1 tag at end of file when both ID3v1 "
           "and ID3v2 tags are present", FALSE,
           G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+  g_object_class_install_property (gobject_class, ARG_PREFER_CHARSET,
+      g_param_spec_string ("prefer-charset", "Prefer charset encoding",
+          "Prefer charset encoding ",
+          DEFAULT_PROP_TAG_CHARSET, G_PARAM_READWRITE));
+
 }
 
 static void
@@ -191,6 +199,9 @@
   id3demux->upstream_size = -1;
   id3demux->state = GST_ID3DEMUX_READID3V2;
   id3demux->send_tag_event = FALSE;
+  if (id3demux->prefer_charset)
+    g_free (id3demux->prefer_charset);
+  id3demux->prefer_charset = NULL;
 
   gst_buffer_replace (buffer_p, NULL);
   gst_caps_replace (caps_p, NULL);
@@ -225,6 +236,7 @@
   gst_element_add_pad (GST_ELEMENT (id3demux), id3demux->sinkpad);
 
   id3demux->prefer_v1 = FALSE;
+  id3demux->prefer_charset = NULL;
   gst_id3demux_reset (id3demux);
 }
 
@@ -441,7 +453,8 @@
         ID3TagsResult tag_result;
 
         tag_result = id3demux_read_id3v2_tag (id3demux->collect,
-            &id3demux->strip_start, &id3demux->parsed_tags);
+            &id3demux->strip_start, &id3demux->parsed_tags,
+            id3demux->prefer_charset);
         if (tag_result == ID3TAGS_MORE_DATA)
           break;                /* Go get more data and try again */
         else if (tag_result == ID3TAGS_BROKEN_TAG)
@@ -600,6 +613,11 @@
     case ARG_PREFER_V1:
       id3demux->prefer_v1 = g_value_get_boolean (value);
       break;
+    case ARG_PREFER_CHARSET:
+      if (id3demux->prefer_charset)
+        g_free (id3demux->prefer_charset);
+      id3demux->prefer_charset = g_value_dup_string (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -619,6 +637,9 @@
     case ARG_PREFER_V1:
       g_value_set_boolean (value, id3demux->prefer_v1);
       break;
+    case ARG_PREFER_CHARSET:
+      g_value_set_string (value, id3demux->prefer_charset);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -749,7 +770,8 @@
     goto beach;
   }
 
-  tag_res = id3demux_read_id3v1_tag (buffer, &id3demux->strip_end, tags);
+  tag_res = id3demux_read_id3v1_tag (buffer, &id3demux->strip_end, tags,
+      id3demux->prefer_charset);
   if (tag_res == ID3TAGS_READ_TAG) {
     GST_DEBUG_OBJECT (id3demux,
         "Read ID3v1 tag - trimming %d bytes from end of file",
@@ -789,7 +811,8 @@
     goto beach;
   }
 
-  tag_res = id3demux_read_id3v2_tag (buffer, &id3demux->strip_start, tags);
+  tag_res = id3demux_read_id3v2_tag (buffer, &id3demux->strip_start, tags,
+      id3demux->prefer_charset);
   if (tag_res == ID3TAGS_MORE_DATA) {
     /* Need more data to interpret the tag */
     if (buffer) {
@@ -807,7 +830,8 @@
           "Could not read data from start of file ret=%d", flow_ret);
       goto beach;
     }
-    tag_res = id3demux_read_id3v2_tag (buffer, &id3demux->strip_start, tags);
+    tag_res = id3demux_read_id3v2_tag (buffer, &id3demux->strip_start, tags,
+        id3demux->prefer_charset);
   }
 
   if (tag_res == ID3TAGS_READ_TAG) {
@@ -843,6 +867,15 @@
   GstID3Demux *id3demux = GST_ID3DEMUX (GST_PAD_PARENT (sinkpad));
   gboolean ret = FALSE;
   GstCaps *caps = NULL;
+  const gchar *env = NULL;
+
+  if (!id3demux->prefer_charset) {
+    env = g_getenv ("GST_ID3_TAG_ENCODING");
+    if (!env || *env == '\0')
+      env = g_getenv ("GST_TAG_ENCODING");
+    if (env && *env != '\0')
+      id3demux->prefer_charset = g_strdup (env);
+  }
 
   /* 1: */
   /* If we can activate pull_range upstream, then read any ID3v1 and ID3v2
Index: gst/id3demux/gstid3demux.h
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/gst/id3demux/gstid3demux.h,v
retrieving revision 1.3
diff -u -r1.3 gstid3demux.h
--- gst/id3demux/gstid3demux.h	1 Jun 2006 21:07:25 -0000	1.3
+++ gst/id3demux/gstid3demux.h	11 Apr 2007 16:33:36 -0000
@@ -65,6 +65,7 @@
   GstTagList *event_tags;
   GstTagList *parsed_tags;
   gboolean send_tag_event;
+  gchar *prefer_charset;
 };
 
 struct _GstID3DemuxClass 
Index: gst/id3demux/id3tags.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/gst/id3demux/id3tags.c,v
retrieving revision 1.13
diff -u -r1.13 id3tags.c
--- gst/id3demux/id3tags.c	6 Mar 2007 18:16:49 -0000	1.13
+++ gst/id3demux/id3tags.c	11 Apr 2007 16:33:36 -0000
@@ -64,7 +64,7 @@
 
 ID3TagsResult
 id3demux_read_id3v1_tag (GstBuffer * buffer, guint * id3v1_size,
-    GstTagList ** tags)
+    GstTagList ** tags, gchar * prefer_charset)
 {
   GstTagList *new_tags;
 
@@ -108,7 +108,7 @@
 
 ID3TagsResult
 id3demux_read_id3v2_tag (GstBuffer * buffer, guint * id3v2_size,
-    GstTagList ** tags)
+    GstTagList ** tags, gchar * prefer_charset)
 {
   guint8 *data;
   guint read_size;
@@ -191,6 +191,7 @@
     work.hdr.frame_data_size = read_size - ID3V2_HDR_SIZE - 10;
   else
     work.hdr.frame_data_size = read_size - ID3V2_HDR_SIZE;
+  work.prefer_charset = prefer_charset;
 
   result = id3demux_id3v2_frames_to_tag_list (&work, read_size);
 
Index: gst/id3demux/id3tags.h
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/gst/id3demux/id3tags.h,v
retrieving revision 1.4
diff -u -r1.4 id3tags.h
--- gst/id3demux/id3tags.h	6 Mar 2007 18:16:49 -0000	1.4
+++ gst/id3demux/id3tags.h	11 Apr 2007 16:33:36 -0000
@@ -39,9 +39,9 @@
 
 /* From id3tags.c */
 ID3TagsResult id3demux_read_id3v1_tag (GstBuffer *buffer, guint *id3v1_size,
-  GstTagList **tags);
+  GstTagList **tags, gchar *prefer_charset);
 ID3TagsResult id3demux_read_id3v2_tag (GstBuffer *buffer, guint *id3v2_size,
-  GstTagList **tags);
+  GstTagList **tags, gchar *prefer_charset);
 G_END_DECLS
 
 /* Things shared by id3tags.c and id3v2frames.c */
@@ -82,6 +82,9 @@
   /* To collect day/month from obsolete TDAT frame if it exists */
   guint pending_month;
   guint pending_day;
+
+  gchar *prefer_charset;
+
 } ID3TagsWorking;
 
 enum {
Index: gst/id3demux/id3v2frames.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/gst/id3demux/id3v2frames.c,v
retrieving revision 1.29
diff -u -r1.29 id3v2frames.c
--- gst/id3demux/id3v2frames.c	12 Mar 2007 13:28:29 -0000	1.29
+++ gst/id3demux/id3v2frames.c	11 Apr 2007 16:33:37 -0000
@@ -49,7 +49,7 @@
     const gchar * tag_name, const gchar * tag_str);
 /* Parse a single string into an array of gchar* */
 static void parse_split_strings (guint8 encoding, gchar * data, gint data_size,
-    GArray ** out_fields);
+    GArray ** out_fields, gchar * prefer_charset);
 static void free_tag_strings (GArray * fields);
 static gboolean
 id3v2_genre_fields_to_taglist (ID3TagsWorking * work, const gchar * tag_name,
@@ -228,7 +228,7 @@
   language[3] = 0;
 
   parse_split_strings (encoding, (gchar *) work->parse_data + 4,
-      work->parse_size - 4, &fields);
+      work->parse_size - 4, &fields, work->prefer_charset);
 
   if (fields == NULL || fields->len < 2) {
     GST_WARNING ("Failed to decode comment frame");
@@ -284,7 +284,7 @@
 
   encoding = work->parse_data[0];
   parse_split_strings (encoding, (gchar *) work->parse_data + 1,
-      work->parse_size - 1, &fields);
+      work->parse_size - 1, &fields, work->prefer_charset);
   if (fields) {
     if (fields->len > 0) {
       GST_LOG ("Read %d fields from Text ID frame of size %d with encoding %d"
@@ -315,7 +315,7 @@
   encoding = work->parse_data[0];
 
   parse_split_strings (encoding, (gchar *) work->parse_data + 1,
-      work->parse_size - 1, &fields);
+      work->parse_size - 1, &fields, work->prefer_charset);
 
   if (fields == NULL)
     return NULL;
@@ -929,7 +929,7 @@
 
 static void
 parse_insert_string_field (guint8 encoding, gchar * data, gint data_size,
-    GArray * fields)
+    GArray * fields, gchar * prefer_charset)
 {
   gchar *field = NULL;
 
@@ -964,14 +964,17 @@
 
       break;
     case ID3V2_ENCODING_ISO8859:
+    default:
       if (g_utf8_validate (data, data_size, NULL))
         field = g_strndup (data, data_size);
-      else
-        field = g_convert (data, data_size, "UTF-8", "ISO-8859-1",
-            NULL, NULL, NULL);
-      break;
-    default:
-      field = g_strndup (data, data_size);
+      else {
+        field = g_convert (data, data_size, "UTF-8",
+            prefer_charset, NULL, NULL, NULL);
+        if (!field) {
+          field = g_convert (data, data_size, "UTF-8",
+              "ISO-8859-1", NULL, NULL, NULL);
+        }
+      }
       break;
   }
 
@@ -989,7 +992,7 @@
 
 static void
 parse_split_strings (guint8 encoding, gchar * data, gint data_size,
-    GArray ** out_fields)
+    GArray ** out_fields, gchar * prefer_charset)
 {
   GArray *fields = g_array_new (FALSE, TRUE, sizeof (gchar *));
   gint text_pos;
@@ -1002,13 +1005,13 @@
       for (text_pos = 0; text_pos < data_size; text_pos++) {
         if (data[text_pos] == 0) {
           parse_insert_string_field (encoding, data + prev,
-              text_pos - prev + 1, fields);
+              text_pos - prev + 1, fields, prefer_charset);
           prev = text_pos + 1;
         }
       }
       if (data_size - prev > 0 && data[prev] != 0x00) {
         parse_insert_string_field (encoding, data + prev,
-            data_size - prev, fields);
+            data_size - prev, fields, prefer_charset);
       }
 
       break;
@@ -1016,13 +1019,13 @@
       for (prev = 0, text_pos = 0; text_pos < data_size; text_pos++) {
         if (data[text_pos] == '\0') {
           parse_insert_string_field (encoding, data + prev,
-              text_pos - prev + 1, fields);
+              text_pos - prev + 1, fields, prefer_charset);
           prev = text_pos + 1;
         }
       }
       if (data_size - prev > 0 && data[prev] != 0x00) {
         parse_insert_string_field (encoding, data + prev,
-            data_size - prev, fields);
+            data_size - prev, fields, prefer_charset);
       }
       break;
     case ID3V2_ENCODING_UTF16:
@@ -1033,7 +1036,7 @@
         if (data[text_pos] == '\0' && data[text_pos + 1] == '\0') {
           /* found a delimiter */
           parse_insert_string_field (encoding, data + prev,
-              text_pos - prev + 2, fields);
+              text_pos - prev + 2, fields, prefer_charset);
           text_pos++;           /* Advance to the 2nd NULL terminator */
           prev = text_pos + 1;
           break;
@@ -1043,7 +1046,7 @@
           (data[prev] != 0x00 || data[prev + 1] != 0x00)) {
         /* There were 2 or more non-null chars left, convert those too */
         parse_insert_string_field (encoding, data + prev,
-            data_size - prev, fields);
+            data_size - prev, fields, prefer_charset);
       }
       break;
     }
