subparse: support multi track smi. sync with tizen2.4
authorEunhae Choi <eunhae1.choi@samsung.com>
Fri, 8 Jan 2016 08:07:16 +0000 (17:07 +0900)
committerEunhae Choi <eunhae1.choi@samsung.com>
Fri, 8 Jan 2016 08:07:22 +0000 (17:07 +0900)
Change-Id: Ifaa7e183fd0354e29734fe64fbf7958dbd82116a

gst/subparse/gstsubparse.c
gst/subparse/gstsubparse.h
gst/subparse/samiparse.c
gst/subparse/samiparse.h
packaging/gst-plugins-base.spec

index e306939..4496abf 100644 (file)
@@ -40,11 +40,17 @@ GST_DEBUG_CATEGORY (sub_parse_debug);
 
 #define DEFAULT_ENCODING   NULL
 
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+#define DEFAULT_CURRENT_LANGUAGE   NULL
+#endif
 enum
 {
   PROP_0,
   PROP_ENCODING,
-  PROP_VIDEOFPS
+  PROP_VIDEOFPS,
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+  PROP_EXTSUB_CURRENT_LANGUAGE
+#endif
 };
 
 static void
@@ -114,6 +120,12 @@ gst_sub_parse_dispose (GObject * object)
     subparse->textbuf = NULL;
   }
 
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+  if (subparse->state.current_language) {
+    g_free (subparse->state.current_language);
+    subparse->state.current_language = NULL;
+  }
+#endif
   GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
 }
 
@@ -154,6 +166,13 @@ gst_sub_parse_class_init (GstSubParseClass * klass)
           "and the subtitle format requires it subtitles may be out of sync.",
           0, 1, G_MAXINT, 1, 24000, 1001,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+  g_object_class_install_property (object_class, PROP_EXTSUB_CURRENT_LANGUAGE,
+      g_param_spec_string ("current-language", "Current language",
+            "Current language of the subtitle in external subtitle case.",
+            DEFAULT_CURRENT_LANGUAGE,
+            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+#endif
 }
 
 static void
@@ -184,6 +203,11 @@ gst_sub_parse_init (GstSubParse * subparse)
 
   subparse->fps_n = 24000;
   subparse->fps_d = 1001;
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+  subparse->state.language_list = NULL;
+  subparse->state.current_language = NULL;
+  subparse->state.langlist_msg_posted = FALSE;
+#endif
 }
 
 /*
@@ -324,6 +348,17 @@ gst_sub_parse_set_property (GObject * object, guint prop_id,
       }
       break;
     }
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+    case PROP_EXTSUB_CURRENT_LANGUAGE:
+      if (subparse->state.current_language)
+        g_free(subparse->state.current_language);
+
+      subparse->state.current_language = g_value_dup_string (value);
+      GST_LOG_OBJECT (subparse, "subtitle current language set to %s",
+                      GST_STR_NULL (subparse->state.current_language));
+      sami_context_change_language(&subparse->state);
+      break;
+#endif
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -345,6 +380,11 @@ gst_sub_parse_get_property (GObject * object, guint prop_id,
     case PROP_VIDEOFPS:
       gst_value_set_fraction (value, subparse->fps_n, subparse->fps_d);
       break;
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+    case PROP_EXTSUB_CURRENT_LANGUAGE:
+      g_value_set_string (value, subparse->state.current_language);
+      break;
+#endif
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1179,6 +1219,12 @@ parser_state_init (ParserState * state)
   state->max_duration = 0;      /* no limit */
   state->state = 0;
   state->segment = NULL;
+
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+  state->language_list = NULL;
+  state->current_language = NULL;
+  state->langlist_msg_posted = FALSE;
+#endif
 }
 
 static void
@@ -1488,6 +1534,9 @@ handle_buffer (GstSubParse * self, GstBuffer * buf)
   GstCaps *caps = NULL;
   gchar *line, *subtitle;
   gboolean need_tags = FALSE;
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+  GstMessage *m = NULL;
+#endif
 
   if (self->first_buffer) {
     GstMapInfo map;
@@ -1544,7 +1593,16 @@ handle_buffer (GstSubParse * self, GstBuffer * buf)
     GST_LOG_OBJECT (self, "Parsing line '%s'", line + offset);
     subtitle = self->parse_line (&self->state, line + offset);
     g_free (line);
-
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+    if (!self->state.langlist_msg_posted && self->state.language_list) {
+      m = gst_message_new_element (GST_OBJECT_CAST (self), gst_structure_new("Ext_Sub_Language_List",
+                                 "lang_list", G_TYPE_POINTER, self->state.language_list, NULL));
+
+      gst_element_post_message (GST_ELEMENT_CAST (self), m);
+      self->state.langlist_msg_posted = TRUE;
+      GST_DEBUG_OBJECT (self, "curr lang as : %s ", GST_STR_NULL(self->state.current_language));
+    }
+#endif
     if (subtitle) {
       guint subtitle_len = strlen (subtitle);
 
index 012aee6..f4d5c92 100644 (file)
@@ -69,6 +69,11 @@ typedef struct {
   gpointer user_data;
   gboolean have_internal_fps; /* If TRUE don't overwrite fps by property */
   gint fps_n, fps_d;     /* used by frame based parsers */
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+  GList* language_list;
+  gchar* current_language;
+  gboolean langlist_msg_posted;
+#endif
 } ParserState;
 
 typedef gchar* (*Parser) (ParserState *state, const gchar *line);
@@ -92,11 +97,11 @@ struct _GstSubParse {
 
   /* seek */
   guint64 offset;
-  
+
   /* Segment */
   GstSegment    segment;
   gboolean      need_segment;
-  
+
   gboolean flushing;
   gboolean valid_utf8;
   gchar   *detected_encoding;
@@ -105,7 +110,7 @@ struct _GstSubParse {
   gboolean first_buffer;
 
   /* used by frame based parsers */
-  gint fps_n, fps_d;          
+  gint fps_n, fps_d;
 };
 
 struct _GstSubParseClass {
index 517e959..0f1bea3 100644 (file)
 typedef struct _HtmlParser HtmlParser;
 typedef struct _HtmlContext HtmlContext;
 typedef struct _GstSamiContext GstSamiContext;
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+typedef struct _LanguageStruct  GstLangStruct;
+struct _LanguageStruct
+{
+    gchar *language_code;
+    gchar *language_key;
+};
+#endif
 
 struct _GstSamiContext
 {
@@ -52,6 +60,14 @@ struct _GstSamiContext
                                  * content of the sync elements to buf */
   guint64 time1;                /* previous start attribute in sync tag */
   guint64 time2;                /* current start attribute in sync tag  */
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+  guint64 time3;                /* To store the last current time when language is changed */
+  GList *lang_list;             /* Language list for an external subtitle file */
+  gchar *current_language;      /* Current language parsed */
+  gchar *desired_language;      /* Language set by user */
+  gboolean language_changed;    /* language changed signal */
+  gboolean end_body;            /* </BODY> reached */
+#endif
 };
 
 struct _HtmlParser
@@ -470,6 +486,10 @@ html_context_handle_element (HtmlContext * ctxt,
   gint count = 0, i;
   gchar **attrs;
   const gchar *found, *next;
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+  const gchar *name_temp = NULL;
+  gint j = 0;
+#endif
 
   /* split element name and attributes */
   next = string_token (string, " ", &name);
@@ -511,7 +531,78 @@ html_context_handle_element (HtmlContext * ctxt,
     attrs[i] = attr_name;
     attrs[i + 1] = attr_value;
   }
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+  /* sometimes spaces can be there in between !-- and P
+   * that also we have to take care */
+  if (!g_ascii_strcasecmp("!--", name)) {
+    gchar* tempchar = (gchar*)(string + 3);
+    while (*tempchar == ' ') {
+      tempchar++;
+      if (*tempchar == 'P' || *tempchar == 'p') {
+        *(name + 3) = *tempchar;
+        *(name + 4) = '\0';
+        next = tempchar + 1;
+        break;
+      }
+    }
+  }
+  if (next && (!g_ascii_strcasecmp("!--P", name))) {
+    gint attrindex = 0;
+    count = 0;
+    /* count attributes */
+    found = next + 1;
+    while (TRUE) {
+      found = (gchar*)strcasestr (found, "lang:");
+      if (!found)
+        break;
+      found++;
+      count++;
+    }
+    g_strfreev (attrs);
+
+    attrs = g_new0 (gchar *, count * 2);
+
+    for (i = 0; i < count; i++) {
+      gchar *attr_name = NULL, *attr_value = NULL;
+
+      next = (gchar*)strcasestr (next, "lang:");
+      attr_value = (gchar*)malloc (3);
+      next = next + 5;
+      strncpy (attr_value, next, 2);
+      attr_value[2] = '\0';
+      GST_LOG ("Language value comes as %s", attr_value);
+      name_temp = next;
+      while (TRUE) {
+        if (*name_temp == '{') {
+          int character_count = 0;
+
+          while (TRUE) {
+            name_temp--;
+
+            if (*name_temp == '.') {
+              attr_name = (gchar*) malloc (character_count + 1);
+              break;
+            }
+            else if (*name_temp != ' ')
+              character_count++;
+          }
+          break;
+        }
+        name_temp--;
+      }
+      name_temp++;
+      for (j = 0; *(name_temp + j) != ' '; j++) {
+        attr_name[j] = *(name_temp + j);
+      }
+      attr_name[j] = '\0';
+      attrs[attrindex++] = attr_name;
+      attrs[attrindex++] = attr_value;
+    }
+  } else {
+    count = 0;
+  }
 
+#endif
   ctxt->parser->start_element (ctxt, name,
       (const gchar **) attrs, ctxt->user_data);
   if (must_close) {
@@ -658,6 +749,9 @@ handle_start_sync (GstSamiContext * sctx, const gchar ** atts)
           sctx->time1 = sctx->time2;
 
         sctx->time2 = atoi ((const char *) value) * GST_MSECOND;
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+        sctx->time3 = sctx->time2;
+#endif
         sctx->time2 = MAX (sctx->time2, sctx->time1);
         g_string_append (sctx->resultbuf, sctx->buf->str);
         sctx->has_result = (sctx->resultbuf->len != 0) ? TRUE : FALSE;
@@ -730,6 +824,88 @@ handle_start_font (GstSamiContext * sctx, const gchar ** atts)
     sami_context_push_state (sctx, SPAN_TAG);
   }
 }
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+static void
+handle_p (GstSamiContext * sctx, const gchar ** atts)
+{
+  int i;
+
+  if (atts != NULL) {
+    for (i = 0; (atts[i] != NULL); i += 2) {
+      const gchar *key, *value;
+
+      key = atts[i];
+      value = atts[i + 1];
+
+      if (sctx->current_language && value && strcmp(sctx->current_language, value)
+          && (sctx->time1 == sctx->time2))
+        sctx->language_changed = TRUE;
+      else if (!sctx->current_language)
+        sctx->current_language = (gchar*) malloc (128);
+
+      if (key && !g_ascii_strcasecmp ("class", key) && value) {
+        strcpy (sctx->current_language, value);
+        if (sctx->desired_language == NULL) {
+          sctx->desired_language = g_strdup(value);
+          GST_LOG("no language list was found and desired lang was set to %s", sctx->desired_language);
+        }
+      }
+      if (sctx->language_changed)
+      {
+         sctx->time1 = 0;
+         sctx->time2 = sctx->time3;
+         sctx->language_changed = FALSE;
+      }
+      if (!value)
+        continue;
+    }
+  }
+}
+
+static void
+handle_start_language_list (GstSamiContext * sctx, const gchar ** atts)
+{
+  int i = 0;
+  int attrIndex = 0;
+  GstLangStruct *new = NULL;
+  GstLangStruct *temp = NULL;
+
+  if (atts != NULL) {
+    if (g_list_length (sctx->lang_list)) {
+      GST_LOG ("We already got the language list");
+      return;
+    }
+    for (i = 0; (atts[attrIndex] != NULL); i++) {
+      const gchar *key, *value;
+
+      key = atts[attrIndex++];
+      value = atts[attrIndex++];
+
+      GST_LOG ("Inside handle_start_language_list key: %s, value: %s", key, value);
+
+      if (!value)
+        continue;
+
+      new = g_new0 (GstLangStruct, 1);
+      new->language_code = (gchar*) malloc (strlen(value) + 1);
+      if (new->language_code && value)
+        strcpy (new->language_code, value);
+      new->language_key = (gchar*) malloc (strlen(key) + 1);
+      if (new->language_key && key)
+        strcpy (new->language_key, key);
+      sctx->lang_list = g_list_append (sctx->lang_list, new);
+      temp = g_list_nth_data (sctx->lang_list, i);
+      if (sctx->desired_language == NULL && key){
+        sctx->desired_language = g_strdup(key);
+      }
+
+      if (temp)
+        GST_LOG ("Inside handle_start_language_list of glist key: %s, value: %s",
+                    temp->language_key, temp->language_code);
+    }
+  }
+}
+#endif
 
 static void
 handle_start_element (HtmlContext * ctx, const gchar * name,
@@ -747,6 +923,10 @@ handle_start_element (HtmlContext * ctx, const gchar * name,
   } else if (!g_ascii_strcasecmp ("ruby", name)) {
     sami_context_push_state (sctx, RUBY_TAG);
   } else if (!g_ascii_strcasecmp ("br", name)) {
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+  if (sctx->current_language && sctx->desired_language &&
+      !strcmp(sctx->current_language, sctx->desired_language))
+#endif
     g_string_append_c (sctx->buf, '\n');
     /* FIXME: support for furigana/ruby once implemented in pango */
   } else if (!g_ascii_strcasecmp ("rt", name)) {
@@ -756,9 +936,18 @@ handle_start_element (HtmlContext * ctx, const gchar * name,
     g_string_append (sctx->rubybuf, "<span size='xx-small' rise='-100'>");
     sami_context_push_state (sctx, RT_TAG);
   } else if (!g_ascii_strcasecmp ("i", name)) {
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+  if (sctx->current_language && sctx->desired_language &&
+      !strcmp(sctx->current_language, sctx->desired_language))
+#endif
     g_string_append (sctx->buf, "<i>");
     sami_context_push_state (sctx, ITALIC_TAG);
   } else if (!g_ascii_strcasecmp ("p", name)) {
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+    handle_p (sctx, atts);
+  } else if (!g_ascii_strcasecmp ("!--P", name)) {
+    handle_start_language_list (sctx, atts);
+#endif
   }
 }
 
@@ -775,6 +964,11 @@ handle_end_element (HtmlContext * ctx, const char *name, gpointer user_data)
       (!g_ascii_strcasecmp ("sami", name))) {
     /* We will usually have one buffer left when the body is closed
      * as we need the next sync to actually send it */
+
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+    sctx->end_body = TRUE;
+#endif
+
     if (sctx->buf->len != 0) {
       /* Only set a new start time if we don't have text pending */
       if (sctx->resultbuf->len == 0)
@@ -804,11 +998,20 @@ handle_text (HtmlContext * ctx, const gchar * text, gsize text_len,
   if (!sctx->in_sync)
     return;
 
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+  if (has_tag (sctx->state, RT_TAG) && (sctx->current_language && sctx->desired_language &&
+       !strcmp(sctx->current_language, sctx->desired_language))) {
+#else
   if (has_tag (sctx->state, RT_TAG)) {
+#endif
     g_string_append_c (sctx->rubybuf, ' ');
     g_string_append (sctx->rubybuf, text);
     g_string_append_c (sctx->rubybuf, ' ');
   } else {
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+    if (sctx->current_language && sctx->desired_language &&
+        !strcmp(sctx->current_language, sctx->desired_language))
+#endif
     g_string_append (sctx->buf, text);
   }
 }
@@ -833,6 +1036,35 @@ sami_context_init (ParserState * state)
   context->rubybuf = g_string_new ("");
   context->resultbuf = g_string_new ("");
   context->state = g_string_new ("");
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+  if (context->current_language)
+    free(context->current_language);
+  context->current_language = NULL;
+  if (context->desired_language)
+    free(context->desired_language);
+  context->desired_language = NULL;
+
+  if (context->lang_list) {
+    GstLangStruct *temp = NULL;
+    int i = 0;
+
+    while ((temp = g_list_nth_data (context->lang_list, i))) {
+      if (temp->language_code)
+        free (temp->language_code);
+      temp->language_code = NULL;
+      if (temp->language_key)
+        free (temp->language_key);
+      temp->language_key = NULL;
+      g_free (temp);
+      i++;
+    }
+    g_list_free (context->lang_list);
+  }
+  context->lang_list = NULL;
+
+  context->language_changed = FALSE;
+  context->end_body = FALSE;
+#endif
 
   state->user_data = context;
 }
@@ -841,6 +1073,10 @@ void
 sami_context_deinit (ParserState * state)
 {
   GstSamiContext *context = (GstSamiContext *) state->user_data;
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+  GstLangStruct *temp = NULL;
+  int i = 0;
+#endif
 
   if (context) {
     html_context_free (context->htmlctxt);
@@ -849,6 +1085,31 @@ sami_context_deinit (ParserState * state)
     g_string_free (context->rubybuf, TRUE);
     g_string_free (context->resultbuf, TRUE);
     g_string_free (context->state, TRUE);
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+    if (context->lang_list) {
+      while ((temp = g_list_nth_data (context->lang_list, i))) {
+        if (temp->language_code)
+          free (temp->language_code);
+        temp->language_code = NULL;
+        if (temp->language_key)
+          free (temp->language_key);
+        temp->language_key = NULL;
+        g_free (temp);
+        i++;
+      }
+      g_list_free (context->lang_list);
+    }
+    context->lang_list = NULL;
+
+    if (context->current_language)
+      free (context->current_language);
+    context->current_language = NULL;
+
+    if (context->desired_language)
+      free (context->desired_language);
+    context->desired_language = NULL;
+#endif
+
     g_free (context);
     state->user_data = NULL;
   }
@@ -871,6 +1132,22 @@ sami_context_reset (ParserState * state)
   }
 }
 
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+void
+sami_context_change_language (ParserState * state)
+{
+  GstSamiContext *context = (GstSamiContext *) state->user_data;
+  if (context->desired_language) {
+    GST_LOG ("desired language was %s", context->desired_language);
+    free (context->desired_language);
+  }
+  if(state->current_language) {
+    context->desired_language = g_strdup(state->current_language);
+  }
+  GST_LOG ("desired language changed to %s", GST_STR_NULL(context->desired_language));
+}
+#endif
+
 gchar *
 parse_sami (ParserState * state, const gchar * line)
 {
@@ -880,20 +1157,38 @@ parse_sami (ParserState * state, const gchar * line)
   gchar *unescaped = unescape_string (line);
   html_context_parse (context->htmlctxt, (gchar *) unescaped,
       strlen (unescaped));
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+  if (context->lang_list)
+    state->language_list = context->lang_list;
+
+  if (context->desired_language) {
+    if (state->current_language)
+      free (state->current_language);
+    state->current_language = g_strdup(context->desired_language);
+  }
+#endif
   g_free (unescaped);
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+  if (context->desired_language && context->current_language) {
+    if (!strcmp(context->current_language, context->desired_language)) {
+#endif
+      if (context->has_result) {
+        if (context->rubybuf->len) {
+          context->rubybuf = g_string_append_c (context->rubybuf, '\n');
+          g_string_prepend (context->resultbuf, context->rubybuf->str);
+          context->rubybuf = g_string_truncate (context->rubybuf, 0);
+        }
 
-  if (context->has_result) {
-    if (context->rubybuf->len) {
-      context->rubybuf = g_string_append_c (context->rubybuf, '\n');
-      g_string_prepend (context->resultbuf, context->rubybuf->str);
-      context->rubybuf = g_string_truncate (context->rubybuf, 0);
+        ret = g_string_free (context->resultbuf, FALSE);
+        context->resultbuf = g_string_new ("");
+        state->start_time = context->time1;
+        state->duration = context->time2 - context->time1;
+        context->has_result = FALSE;
+      }
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
     }
-
-    ret = g_string_free (context->resultbuf, FALSE);
-    context->resultbuf = g_string_new ("");
-    state->start_time = context->time1;
-    state->duration = context->time2 - context->time1;
-    context->has_result = FALSE;
   }
+#endif
+
   return ret;
 }
index 12f8c9e..7c1a578 100644 (file)
@@ -31,6 +31,9 @@ void    sami_context_init   (ParserState * state);
 void    sami_context_deinit (ParserState * state);
 
 void    sami_context_reset  (ParserState * state);
+#ifdef GST_TIZEN_SUBPARSE_MODIFICATION
+void    sami_context_change_language  (ParserState * state);
+#endif
 
 G_END_DECLS
 
index 11be718..f252e59 100644 (file)
@@ -5,7 +5,7 @@
 
 Name:           gst-plugins-base
 Version:        1.6.1
-Release:        3
+Release:        4
 License:        LGPL-2.0+
 Summary:        GStreamer Streaming-Media Framework Plug-Ins
 Url:            http://gstreamer.freedesktop.org/
@@ -77,6 +77,7 @@ export CFLAGS="%{optflags} -fno-strict-aliasing\
  -DGST_EXT_LINK_FIMCCONVERT\
  -DGST_EXT_MIME_TYPES\
  -DGST_TIZEN_MODIFICATION\
+ -DGST_TIZEN_SUBPARSE_MODIFICATION\
 %endif
  "
 %configure\