--- gst-plugins-0.8.11/gst/subparse/gstsubparse.h~	2005-09-23 01:13:34.011522000 +0900
+++ gst-plugins-0.8.11/gst/subparse/gstsubparse.h	2005-09-24 16:52:28.504901000 +0900
@@ -69,6 +69,12 @@
       GString *buf;
       guint64 time;
     } mpsub;
+    struct {
+      int state;
+      GMarkupParseContext *context;
+      GString *outbuf, *resultbuf;
+      guint64 time1, time2;
+    } sami;
   } state;
 
   /* seek */
--- gst-plugins-0.8.11/gst/subparse/gstsubparse.c~	2005-09-23 01:13:38.127779250 +0900
+++ gst-plugins-0.8.11/gst/subparse/gstsubparse.c	2005-09-24 16:52:31.957116750 +0900
@@ -38,7 +38,8 @@
   GST_SUB_PARSE_FORMAT_UNKNOWN = 0,
   GST_SUB_PARSE_FORMAT_MDVDSUB = 1,
   GST_SUB_PARSE_FORMAT_SUBRIP = 2,
-  GST_SUB_PARSE_FORMAT_MPSUB = 3
+  GST_SUB_PARSE_FORMAT_MPSUB = 3,
+  GST_SUB_PARSE_FORMAT_SAMI = 4
 } GstSubParseFormat;
 
 static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
@@ -229,7 +230,7 @@
 convert_encoding (GstSubparse * self, const gchar * str, gsize len)
 {
   gsize bytes_read, bytes_written;
-  gchar *rv;
+  gchar *rv, *enc;
   GString *converted;
 
   converted = g_string_new (NULL);
@@ -241,7 +242,11 @@
     g_free (dbg);
 #endif
 
-    rv = g_locale_to_utf8 (str, len, &bytes_read, &bytes_written, NULL);
+     if((enc = getenv("GST_SUBTITLE_ENCODING"))) {
+       rv = g_convert_with_fallback(str, len, "UTF-8", enc, "?", &bytes_read, &bytes_written, NULL);
+     }else {
+       rv = g_locale_to_utf8 (str, len, &bytes_read, &bytes_written, NULL);
+     }
     if (rv) {
       g_string_append_len (converted, rv, bytes_written);
       g_free (rv);
@@ -545,6 +550,228 @@
   self->parser.parse = parse_mpsub;
 }
 
+static GString * 
+make_valid_sami(gchar *line)
+{
+  int i, state = 0;
+  GString * ostr = g_string_new(NULL);
+  gchar *c;
+
+  for( i = 0; i < strlen(line); i++){
+    c = line + i;
+    if(*c == '<') {
+      /* in most case, <br> tags are not closed. */
+      if(!strncasecmp(c, "<br>", 4)) {
+        ostr = g_string_append(ostr, "<br/>");
+        i += 3;
+        continue;
+	   }
+      /* open tag */
+      state |= (1<<0);
+    }else if(*c == '>') {
+      if (state&(1<<1)) {
+        /* add " in attribute value end point */
+        ostr = g_string_append_c(ostr, '"');
+        state &= ~(1<<1);
+      }
+      /* close tag */
+      state &= ~(1<<0);
+    }else if(*c == '=') {
+      if(state&(1<<0)) {
+        if ((i+1 < strlen(line)) && (*(c+1) != '"')) {
+          /* add " in attribute value start point */
+          ostr = g_string_append_c(ostr, *c);
+          ostr = g_string_append_c(ostr, '"');
+          state |= (1<<1);
+          continue;
+        }
+      }
+    }else if(*c == '&') {
+      /* g_markup function can't parse &nbsp; */
+      if(!strncasecmp(c, "&nbsp;", 6)) {
+        ostr = g_string_append_c(ostr, ' ');
+        i += 5;
+        continue;
+      }
+    }
+
+    if (state&(1<<0)) {
+      *c = g_ascii_toupper(*c);
+    }
+    ostr = g_string_append_c(ostr, *c);
+  }
+  return ostr;
+}
+
+static void
+start_element_handler  (GMarkupParseContext *context,
+                        const gchar         *element_name,
+                        const gchar        **attribute_names,
+                        const gchar        **attribute_values,
+                        gpointer             user_data,
+                        GError             **error)
+{
+  int i;
+  GstSubparse * self = (GstSubparse*) user_data;
+  GString * outbuf = self->state.sami.outbuf;
+
+  if (!g_strncasecmp(element_name, "sync", 4)) {
+    for ( i = 0; attribute_names[i]; i++) {
+      if (!g_strncasecmp(attribute_names[i], "start", 5)) {
+        self->state.sami.time1 = self->state.sami.time2;
+        self->state.sami.time2 = atoi (attribute_values[i]) * GST_MSECOND;
+        self->state.sami.state |= (1<<1);
+        if (self->state.sami.state&(1<<2)) {
+          outbuf = g_string_append(outbuf, "</span>");
+          self->state.sami.state &= ~(1<<2); /* close span tag */
+        }
+        g_assert(self->state.sami.resultbuf == NULL);
+        self->state.sami.resultbuf = g_string_new(outbuf->str);
+        g_string_truncate (outbuf, 0);
+      }
+    }
+  }else if (!g_strncasecmp(element_name, "font", 4)) {
+    if (self->state.sami.state&(1<<2)) {
+      outbuf = g_string_append(outbuf, "</span>");
+    }
+    self->state.sami.state |= (1<<2);
+    for ( i = 0; attribute_names[i]; i++) {
+      if (!g_strncasecmp(attribute_names[i], "color", 5)) {
+        char *r;
+        const char *color = attribute_values[i];
+        outbuf = g_string_append(outbuf, "<span foreground=\"");
+        if ((*color == '#') && (7 == strlen(color))) {
+           outbuf = g_string_append(outbuf, attribute_values[i]);
+        }else{
+           strtol((char*)color, &r, 16); /* trying convert hex */
+           if ((r == (color+6)) && (6 == strlen(color))) {
+             outbuf = g_string_append_c(outbuf, '#');
+             outbuf = g_string_append(outbuf, color);
+           }else {
+             outbuf = g_string_append(outbuf, color);
+           }
+        }
+        outbuf = g_string_append(outbuf, "\">");
+      }
+    }
+  }else if (!g_strncasecmp(element_name, "br", 2)) {
+    outbuf = g_string_append(outbuf, "\n");
+  }else if (!g_strncasecmp(element_name, "body", 4)) {
+    self->state.sami.state |= (1<<0);
+  }
+  self->state.sami.outbuf = outbuf;
+}
+
+static void
+end_element_handler    (GMarkupParseContext *context,
+                        const gchar         *element_name,
+                        gpointer             user_data,
+                        GError             **error)
+{
+  GstSubparse * self = (GstSubparse*) user_data;
+  GString *outbuf = self->state.sami.outbuf;
+
+  if (!g_strncasecmp(element_name, "sync", 4)) {
+    self->state.sami.state &= ~(1<<1);
+  }else if (!g_strncasecmp(element_name, "font", 4)) {
+    if (self->state.sami.state&(1<<2)) {
+      outbuf = g_string_append(outbuf, "</span>");
+    }
+    self->state.sami.state &= ~(1<<2);
+  }else if (!g_strncasecmp(element_name, "body", 4)) {
+    self->state.sami.state &= ~(1<<0);
+  }
+  self->state.sami.outbuf = outbuf;
+}
+
+static void
+text_handler           (GMarkupParseContext *context,
+                        const gchar         *text,
+                        gsize                text_len,
+                        gpointer             user_data,
+                        GError             **error)
+{
+  GstSubparse * self = (GstSubparse*) user_data;
+  GString *outbuf = self->state.sami.outbuf;
+
+  if( self->state.sami.state &(1<<0)) {
+    gchar * escaped = g_markup_escape_text(text, text_len);
+    outbuf = g_string_append(outbuf, escaped);
+    g_free(escaped);
+  }
+  self->state.sami.outbuf = outbuf;
+}
+
+static const GMarkupParser sami_markup_parser = {
+  start_element_handler,
+  end_element_handler,
+  text_handler,
+  NULL,
+  NULL
+};
+
+static gchar *
+parse_sami (GstSubparse * self, guint64 * out_start_time,
+	    guint64 * out_end_time, gboolean after_seek)
+{
+  gchar *line;
+  GString *tmpbuf = NULL;
+  GError *err = NULL;
+
+  line = get_next_line (self);
+
+  if(!line) {
+     return NULL;
+  }
+
+  if (self->state.sami.state&(1<<4)) {
+     /* parser context failed */
+     return NULL;
+  }
+
+  /* most sami subtitles are not valid markup format */
+  tmpbuf = make_valid_sami(line);
+
+  if (!g_markup_parse_context_parse (self->state.sami.context,
+      tmpbuf->str, tmpbuf->len, &err)){
+    g_print("error in \"%s\"\n", tmpbuf->str);
+    g_print("error: %s\n",err->message);
+    self->state.sami.state |= (1<<4);
+  }else{
+	 if (self->state.sami.resultbuf) {
+       gchar * retval = self->state.sami.resultbuf->str;
+       g_string_free(self->state.sami.resultbuf, FALSE);
+       self->state.sami.resultbuf = NULL;
+       self->state.sami.state &= ~(1<<1);
+       *out_start_time = self->state.sami.time1;
+       *out_end_time = self->state.sami.time2;
+       return retval;
+    }
+  }
+  g_string_free(tmpbuf, TRUE);
+  g_free (line);
+  return NULL;
+}
+
+static void
+parse_sami_deinit (GstSubparse * self)
+{
+  g_markup_parse_context_free (self->state.sami.context);
+  g_string_free (self->state.sami.outbuf, TRUE);
+}
+
+static void
+parse_sami_init (GstSubparse * self)
+{
+  self->state.sami.state = 0;
+  self->state.sami.outbuf = g_string_new (NULL);
+  self->state.sami.context = g_markup_parse_context_new (&sami_markup_parser,
+      0, self, NULL);
+  self->parser.deinit = parse_sami_deinit;
+  self->parser.parse = parse_sami;
+}
+
+
 /*
  * FIXME: maybe we should pass along a second argument, the preceding
  * text buffer, because that is how this originally worked, even though
@@ -597,6 +824,11 @@
     g_free (match_str);
     return GST_SUB_PARSE_FORMAT_MPSUB;
   }
+  if (strstr (match_str, "<SAMI>")) {
+    GST_LOG ("subparse: SAMI (time based) format detected");
+    g_free (match_str);
+    return GST_SUB_PARSE_FORMAT_SAMI;
+  }
 
   GST_WARNING ("subparse: subtitle format autodetection failed!");
   g_free (match_str);
@@ -646,6 +878,12 @@
       res = gst_pad_set_explicit_caps (self->srcpad,
           gst_caps_new_simple ("text/plain", NULL));
       break;
+    case GST_SUB_PARSE_FORMAT_SAMI:
+      GST_DEBUG ("SAMI format detected");
+      parse_sami_init (self);
+      res = gst_pad_set_explicit_caps (self->srcpad,
+          gst_caps_new_simple ("text/x-pango-markup", NULL));
+      break;
     case GST_SUB_PARSE_FORMAT_UNKNOWN:
     default:
       GST_DEBUG ("no subtitle format detected");
@@ -783,6 +1021,9 @@
     case GST_SUB_PARSE_FORMAT_MPSUB:
       GST_DEBUG ("SubRip format detected");
       break;
+    case GST_SUB_PARSE_FORMAT_SAMI:
+      GST_DEBUG ("SAMI format detected");
+      break;
     case GST_SUB_PARSE_FORMAT_UNKNOWN:
       GST_DEBUG ("no subtitle format detected");
       return;
@@ -795,7 +1036,7 @@
 static gboolean
 plugin_init (GstPlugin * plugin)
 {
-  static gchar *sub_exts[] = { "srt", "sub", "mpsub", "mdvd", NULL };
+  static gchar *sub_exts[] = { "srt", "sub", "mpsub", "mdvd", "smi", NULL };
 
   GST_DEBUG_CATEGORY_INIT (subparse_debug, "subparse", 0, ".sub parser");
 
