tizen 2.3 release
[framework/multimedia/gst-plugins-ext0.10.git] / submux / src / gstsubmux.c
1 /*
2  * SLP2.0
3  * Copyright (c) 2011 Samsung Electronics, Inc.
4  * All rights reserved.
5  *
6  * This software is a confidential and proprietary information
7  * of Samsung Electronics, Inc. ("Confidential Information").  You
8  * shall not disclose such Confidential Information and shall use
9  * it only in accordance with the terms of the license agreement
10  * you entered into with Samsung Electronics.
11  */
12
13 /*
14  * @file        gstsubmux.c
15  * @author      Deepak Singh (deep.singh@samsung.com)
16  * @version     1.0
17  * @brief       This source code implements the gstreamer plugin for subtitle muxing requirement in media player.
18  *
19  */
20
21 /*! Revision History:
22  *! ---------------------------------------------------------------------------
23  *!     DATE     |         AUTHOR               |             COMMENTS
24  *! ---------------------------------------------------------------------------
25  *! 1-4-2014        deep.singh@samsung.com                   created.
26  */
27
28 #include "config.h"
29 #include "gstsubmux.h"
30 #include <gst/base/gstadapter.h>
31 #include <glib/gstdio.h>
32 #include <gst/gst.h>
33 #include <gst/app/gstappsink.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <gst/tag/tag.h>
38 #include <fcntl.h>
39 #include <unistd.h>
40 #include <gst/gst.h>
41 static const GstElementDetails gst_submux_plugin_details = GST_ELEMENT_DETAILS(
42     "submux",
43     "Codec/Parser/Subtitle",
44     "muxing of different subtitle stream",
45     "Samsung Electronics <www.samsung.com>"
46 );
47 static GstStaticPadTemplate gst_submux_sink_template = GST_STATIC_PAD_TEMPLATE(
48     "sink%d",
49     GST_PAD_SINK,
50     GST_PAD_REQUEST,
51     GST_STATIC_CAPS("video/x-dvd-subpicture; text/plain; application/x-subtitle; "
52                     "text/x-pango-markup;"
53                     "application/x-usf; subpicture/x-pgs; subtitle/x-kate; application/x-subtitle; "
54                     "application/x-subtitle-sami; application/x-subtitle-tmplayer; "
55                     "application/x-subtitle-mpl2; application/x-subtitle-dks; "
56                     "application/x-subtitle-qttext")
57 );
58 static GstStaticPadTemplate gst_submux_src_template = GST_STATIC_PAD_TEMPLATE(
59     "src",
60     GST_PAD_SRC,
61     GST_PAD_ALWAYS,
62     GST_STATIC_CAPS ("text/plain; text/x-pango-markup")
63 );
64 enum
65 {
66   PROP_0,
67   PROP_ENCODING,
68   PROP_VIDEOFPS,
69   PROP_EXTSUB_CURRENT_LANGUAGE,
70   PROP_IS_INTERNAL,
71   PROP_LANG_LIST
72
73 };
74
75 GST_DEBUG_CATEGORY_STATIC (gst_submux_debug);
76 #define GST_CAT_DEFAULT gst_submux_debug
77 #define _do_init(bla) \
78     GST_DEBUG_CATEGORY_INIT (gst_submux_debug, "submux", 0, "submux");
79 ////////////////////////////////////////////////////////
80 //        Gstreamer Base Prototype                    //
81 ////////////////////////////////////////////////////////
82
83 GST_BOILERPLATE_FULL(Gstsubmux, gst_submux, GstElement, GST_TYPE_ELEMENT, _do_init);
84
85 #define GST_SUBMUX_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_SUBMUX, GstsubmuxPrivate))
86 #define MAX_LANGUAGE 10
87 static gint gst_submux_buffer_list_sorting (gconstpointer a, gconstpointer b);
88 static gboolean gst_submux_create_pipelines(Gstsubmux *self,GstPad * pad);
89 static GstPad*  gst_submux_request_new_pad (GstElement * element,
90        GstPadTemplate * templ, const gchar * req_name);
91 static void gst_submux_release_pad (GstElement * element, GstPad * pad);
92 static gchar* gst_submux_extract_data (Gstsubmux *submux);
93 static gboolean gst_create_own_language_list (Gstsubmux *submux) ;
94 static GstSubMuxFormat gst_submux_data_format_autodetect (gchar * match_str);
95 static gpointer gst_submux_data_format_autodetect_regex_once (GstSubMuxRegex regtype);
96 static gboolean gst_submux_format_autodetect (Gstsubmux * self);
97 static void gst_submux_base_init(gpointer klass);
98 static void gst_submux_class_init(GstsubmuxClass *klass);
99 static GstStateChangeReturn gst_submux_change_state (GstElement * element, GstStateChange transition);
100 static void gst_submux_init(Gstsubmux *submux, GstsubmuxClass *klass);
101 static gboolean gst_submux_setcaps(GstPad *pad, GstCaps *caps);
102 static GstFlowReturn gst_submux_chain (GstPad *pad, GstBuffer *buffer);
103 static void gst_submux_dispose(GObject *object);
104 static void gst_submux_loop (Gstsubmux * submux);
105 static gboolean gst_submux_stream_init(GstSubmuxStream * stream);
106 static void gst_submux_stream_deinit(GstSubmuxStream * stream,Gstsubmux * submux);
107 static void gst_submux_on_new_buffer (GstElement *appsink, void *data);
108 static gboolean gst_submux_handle_src_event (GstPad * pad, GstEvent * event);
109
110 static gboolean gst_submux_handle_sink_event (GstPad * pad, GstEvent * event);
111 ////////////////////////////////////////////////////////
112 //        Plugin Utility Prototype                    //
113 ////////////////////////////////////////////////////////
114 static void gst_submux_set_property (GObject * object, guint prop_id,
115     const GValue * value, GParamSpec * pspec);
116 static void gst_submux_get_property (GObject * object, guint prop_id,
117     GValue * value, GParamSpec * pspec);
118 static gboolean gst_submux_deinit_private_values(Gstsubmux *submux);
119 static gchar *convert_to_utf8 (const gchar * str, gsize len, const gchar * encoding,
120     gsize * consumed, GError ** err, Gstsubmux * self);
121 #define DEFAULT_ENCODING           NULL
122 #define DEFAULT_CURRENT_LANGUAGE   NULL
123
124 ////////////////////////////////////////////////////////
125 //        Gstreamer Base Functions                    //
126 ////////////////////////////////////////////////////////
127
128 /*
129 **
130 **  Description : base init
131 **  Params      : (1) instance of gclass
132 **  return      : none
133 **  Comments    : The following code registers templates for src and sink pad.
134 **
135 */
136 static void
137 gst_submux_base_init(gpointer g_class)
138 {
139     GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
140     gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&gst_submux_sink_template));
141     gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&gst_submux_src_template));
142     gst_element_class_set_details(element_class, &gst_submux_plugin_details);
143 }
144
145 /*
146 **
147 **  Description    : Initilizes the Gstsubmux's class
148 **  Params        : @ klass instance of submux plugin's class
149 **  return        : None
150 **  Comments    : Declaring properties and over-writing function pointers
151 **
152 */
153 static void
154 gst_submux_class_init(GstsubmuxClass *klass)
155 {
156     GstElementClass *gstelement_class = GST_ELEMENT_CLASS(klass);
157     GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
158     g_type_class_add_private (klass, sizeof (GstsubmuxPrivate));
159     gobject_class->set_property = gst_submux_set_property;
160     gobject_class->get_property = gst_submux_get_property;
161     g_object_class_install_property (gobject_class, PROP_ENCODING,
162         g_param_spec_string ("subtitle-encoding", "subtitle charset encoding",
163             "Encoding to assume if input subtitles are not in UTF-8 or any other "
164             "Unicode encoding. If not set, the GST_SUBTITLE_ENCODING environment "
165             "variable will be checked for an encoding to use. If that is not set "
166             "either, ISO-8859-15 will be assumed.", DEFAULT_ENCODING,
167             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
168
169     g_object_class_install_property (gobject_class, PROP_VIDEOFPS,
170         gst_param_spec_fraction ("video-fps", "Video framerate",
171             "Framerate of the video stream. This is needed by some subtitle "
172             "formats to synchronize subtitles and video properly. If not set "
173             "and the subtitle format requires it subtitles may be out of sync.",
174             0, 1, G_MAXINT, 1, 24000, 1001,
175             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
176     g_object_class_install_property (gobject_class, PROP_EXTSUB_CURRENT_LANGUAGE,
177           g_param_spec_string ("current-language", "Current language",
178                 "Current language of the subtitle in external subtitle case.",
179                 DEFAULT_CURRENT_LANGUAGE,
180                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
181     g_object_class_install_property (gobject_class, PROP_IS_INTERNAL,
182           g_param_spec_boolean ("is-internal", "is internal",
183               "TRUE for internal subtitle case",
184               FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
185     g_object_class_install_property (gobject_class, PROP_LANG_LIST,
186           g_param_spec_pointer ("lang-list", "language list", "List of languages selected/not selected",
187                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
188     parent_class = g_type_class_peek_parent (klass);
189     gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR(gst_submux_request_new_pad);
190     gobject_class->dispose = GST_DEBUG_FUNCPTR(gst_submux_dispose);
191     gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_submux_change_state);
192     gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_submux_release_pad);
193 }
194
195 /*
196 **
197 **  Description    : Initilizes the submux element
198 **  Params        : (1)instance of submux (2) instance of submux class
199 **  return        : None
200 **  Comments    : instantiate pads and add them to element, set pad calback functions
201 **
202 */
203 static void
204 gst_submux_init(Gstsubmux *submux, GstsubmuxClass *klass)
205 {
206   GST_DEBUG_OBJECT (submux, "Entering in init");
207   submux->priv = GST_SUBMUX_GET_PRIVATE(submux);
208   submux->srcpad = gst_pad_new_from_static_template(&gst_submux_src_template, "src");
209   gst_pad_set_event_function (submux->srcpad,
210             GST_DEBUG_FUNCPTR (gst_submux_handle_src_event));
211   submux->priv->first_buffer = FALSE;
212   gst_segment_init (&submux->segment, GST_FORMAT_TIME);
213   submux->flushing = FALSE;
214   submux->msl_streams = NULL;
215   submux->stop_loop = FALSE;
216   submux->need_segment = TRUE;
217   submux->pipeline_made = FALSE;
218   submux->external_sinkpad = FALSE;
219   submux->detected_encoding = NULL;
220   submux->encoding = NULL;
221   submux->seek_came = FALSE;
222   submux->sinkpads_count = 0;
223   submux->langlist_msg_posted = FALSE;
224   submux->cur_buf_array = NULL;
225   GST_DEBUG_OBJECT (submux, "Making flushing FALSE");
226   submux->priv->is_internal = FALSE;
227   submux->external_filepath = NULL;
228   gst_element_add_pad (GST_ELEMENT (submux), submux->srcpad);
229   GST_DEBUG_OBJECT (submux, "Exiting in init");
230 }
231
232 /*
233 **
234 **  Description    : for setting the property of submux
235 **  return        : None
236 **  Comments    : To set the various properties of submux
237 **
238 */
239 static void
240 gst_submux_set_property (GObject * object, guint prop_id,
241     const GValue * value, GParamSpec * pspec)
242 {
243   Gstsubmux *submux = GST_SUBMUX (object);
244   guint length = 0;
245   gint i = 0;
246   GstLangStruct *cur_language=NULL;
247   GstSubmuxStream *cur_stream = NULL;
248   GST_OBJECT_LOCK (submux);
249   length = g_list_length(submux->priv->lang_list);
250   switch (prop_id) {
251     case PROP_ENCODING:
252       g_free (submux->encoding);
253       submux->encoding = g_value_dup_string (value);
254       GST_DEBUG_OBJECT (submux, "subtitle encoding set to %s",
255           GST_STR_NULL (submux->encoding));
256       for(i = 0;i < length;i++) {
257         cur_stream = g_list_nth_data(submux->streams,i);
258         GST_DEBUG_OBJECT (submux, "setting the subtitle-encoding to %s", submux->encoding);
259         g_object_set (G_OBJECT (cur_stream->pipe_struc.parser), "subtitle-encoding", submux->encoding, NULL);
260       }
261       break;
262     case PROP_VIDEOFPS:
263     {
264       submux->fps_n = gst_value_get_fraction_numerator (value);
265       submux->fps_d = gst_value_get_fraction_denominator (value);
266       GST_DEBUG_OBJECT (submux, "video framerate set to %d/%d", submux->fps_n, submux->fps_d);
267       break;
268     }
269     case PROP_EXTSUB_CURRENT_LANGUAGE: {
270       for (i = 0; i < length; i++) {
271         cur_stream = g_list_nth_data(submux->streams, i);
272         cur_language = g_list_nth_data(submux->priv->lang_list, i);
273         GST_DEBUG_OBJECT (submux, "value of current-language key is %s", cur_language->language_key);
274         g_object_set (G_OBJECT (cur_stream->pipe_struc.parser), "current-language",
275                       cur_language->language_key, NULL);
276       }
277       gchar *dup = g_value_dup_string (value);
278       GST_DEBUG_OBJECT (submux, "Setting property to %s", dup);
279       g_free(dup);
280     }
281     break;
282     case PROP_IS_INTERNAL: {
283       submux->priv->is_internal = g_value_get_boolean (value);
284       GST_DEBUG_OBJECT (submux, "Setting the is_internal prop to %d", submux->priv->is_internal);
285       break;
286     }
287     case PROP_LANG_LIST: {
288       submux->priv->lang_list = (GList*) g_value_get_pointer (value);
289       GST_DEBUG_OBJECT (submux, "updating the languages list and length is %d", g_list_length (submux->priv->lang_list));
290       submux->msl_streams = g_list_copy (submux->priv->lang_list);
291
292       break;
293     }
294     default:
295       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
296       break;
297   }
298   GST_OBJECT_UNLOCK (submux);
299 }
300
301 /*
302 **
303 **  Description    : for getting the property of submux
304 **  return        : None
305 **  Comments    : To get the various properties of submux in case called by MSL
306 **
307 */
308 static void
309 gst_submux_get_property (GObject * object, guint prop_id,
310     GValue * value, GParamSpec * pspec)
311 {
312   Gstsubmux *submux = GST_SUBMUX (object);
313
314   GST_OBJECT_LOCK (submux);
315   switch (prop_id) {
316     case PROP_ENCODING:
317       g_value_set_string (value, submux->encoding);
318       break;
319     case PROP_VIDEOFPS:
320       gst_value_set_fraction (value, submux->fps_n, submux->fps_d);
321       break;
322     case PROP_EXTSUB_CURRENT_LANGUAGE:
323       GST_DEBUG_OBJECT (submux, "Getting the current language");
324       break;
325     case PROP_IS_INTERNAL: {
326       g_value_set_boolean(value,submux->priv->is_internal);
327       break;
328     }
329     case PROP_LANG_LIST: {
330       g_value_set_pointer(value,(gpointer)(submux->priv->lang_list));
331       break;
332     }
333     default:
334       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
335       break;
336   }
337   GST_OBJECT_UNLOCK (submux);
338 }
339
340 static void
341 gst_submux_dispose (GObject *object)
342 {
343   Gstsubmux *submux = GST_SUBMUX(object);
344   int i = 0;
345   gchar *pad_name = gst_pad_get_name (submux->srcpad);
346   if (submux && GST_PAD_TASK(submux->srcpad)) {
347     GST_INFO_OBJECT (submux, "Stopping pad task : %s", pad_name);
348     GST_DEBUG_OBJECT (submux, "Stopping pad task : on src pad %p", submux->srcpad);
349     gst_pad_stop_task (submux->srcpad);
350     GST_INFO_OBJECT (submux, "stopped pad task : %s", pad_name);
351   }
352   g_free(pad_name);
353   if (submux->srcpad) {
354     gst_element_remove_pad (GST_ELEMENT_CAST (submux), submux->srcpad);
355     submux->srcpad = NULL;
356   }
357   if (submux->priv->is_internal) {
358     for (i = 0; i < (submux->sinkpads_count); i++){
359       gst_submux_stream_deinit (g_list_nth_data (submux->streams, i), submux);
360     }
361   } else {
362     for (i = 0; i < g_list_length (submux->priv->lang_list); i++) {
363       gst_submux_stream_deinit (g_list_nth_data (submux->streams, i), submux);
364     }
365   }
366   gst_submux_deinit_private_values (submux);
367
368   GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
369   GST_DEBUG_OBJECT (submux, "Returning from finalize");
370 }
371
372 static void
373 gst_submux_stop (Gstsubmux* submux)
374 {
375   GstSubmuxStream *new_stream = NULL;
376   guint i = 0;
377   submux->stop_loop = TRUE;
378   GST_INFO_OBJECT (submux, "stopping the loop");
379   if (submux->priv->is_internal) {
380     for (i = 0; i < (submux->sinkpads_count); i++) {
381       new_stream =  g_list_nth_data (submux->streams, i);
382       if (new_stream) {
383         g_mutex_lock (new_stream->queue_lock);
384         g_cond_signal (new_stream->queue_empty);
385         g_mutex_unlock (new_stream->queue_lock);
386       }
387     }
388   } else {
389     for (i = 0; i < g_list_length (submux->priv->lang_list); i++) {
390       new_stream =  g_list_nth_data (submux->streams, i);
391       if (new_stream) {
392         g_mutex_lock (new_stream->queue_lock);
393         g_cond_signal (new_stream->queue_empty);
394         g_mutex_unlock (new_stream->queue_lock);
395       }
396     }
397   }
398 }
399
400 static GstStateChangeReturn
401 gst_submux_change_state (GstElement * element, GstStateChange transition)
402 {
403   GstStateChangeReturn ret;
404   Gstsubmux *submux = GST_SUBMUX (element);
405   gboolean bret = FALSE;
406
407   switch (transition) {
408     case GST_STATE_CHANGE_READY_TO_PAUSED:
409       break;
410     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
411       GST_INFO_OBJECT (submux,"PAUSED->PLAYING");
412       break;
413     case GST_STATE_CHANGE_PAUSED_TO_READY:
414       GST_INFO_OBJECT (submux,"PAUSED->READY");
415       gst_submux_stop (submux);
416       break;
417     default:
418       break;
419   }
420
421   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
422
423   switch (transition) {
424     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
425       GST_INFO_OBJECT (submux,"PLAYING->PAUSED");
426       break;
427     case GST_STATE_CHANGE_PAUSED_TO_READY:
428       GST_INFO_OBJECT (submux,"PAUSED->READY");
429       if(submux->msl_streams) {
430         g_list_free(submux->msl_streams);
431         submux->msl_streams = NULL;
432       }
433       if (submux->priv->lang_list && !submux->priv->is_internal) {
434         g_list_free (submux->priv->lang_list);
435         submux->priv->lang_list = NULL;
436       }
437       if (submux->external_filepath) {
438         g_free (submux->external_filepath);
439         submux->external_filepath = NULL;
440       }
441       GST_WARNING_OBJECT(submux,"stopping has been called ...Moved after change_state");
442       break;
443     case GST_STATE_CHANGE_READY_TO_NULL:
444       GST_INFO_OBJECT (submux,"READY->NULL");
445       break;
446     default:
447       break;
448   }
449   return ret;
450 }
451
452 /*
453 **
454 **  Description    : Setting the caps on sink pad based on upstream element's src pad
455 **  Params        : (1) GstPad to set the capabilities of
456 **                   (2) caps to be set
457 **  return        : TRUE on success
458 **  Comments    : this function handles the link with other elements
459 **
460 */
461 static gboolean
462 gst_submux_setcaps (GstPad *pad, GstCaps *caps)
463 {
464   return TRUE;
465 }
466
467 /*extracting data for file format detection*/
468 static gchar* gst_submux_extract_data (Gstsubmux *submux){
469   gchar * file_path_type = NULL;
470   gchar * file_path = NULL;
471   gchar * temp_path = NULL;
472   gchar  *line = NULL;
473   gboolean is_converted = FALSE;
474   gchar *converted = NULL;
475   FILE  * fp = NULL;
476   guint charCount = 0;
477   GError *err = NULL;
478   gsize * consumed = NULL;
479
480   GstQuery *cquery;
481   GstStructure *structure;
482   const GValue *value;
483   GstPad *sinkpad = (GstPad *)g_list_nth_data (submux->sinkpad, 0);
484   structure = gst_structure_new ("FileSrcURI",
485                                  "file-uri", G_TYPE_STRING, NULL, NULL);
486
487   cquery = gst_query_new_application (GST_QUERY_CUSTOM, structure);
488
489   if (!gst_pad_peer_query (sinkpad, cquery))
490   {
491     GST_ERROR_OBJECT (submux, "Failed to query SMI file path");
492     gst_query_unref (cquery);
493     return NULL;
494   }
495   structure = gst_query_get_structure (cquery);
496   value = gst_structure_get_value (structure, "file-uri");
497   file_path = g_strdup (g_value_get_string (value));
498
499   if (file_path == NULL){
500     GST_ERROR_OBJECT (submux, "Could not parse the SMI file path");
501     gst_query_unref (cquery);
502     return NULL;
503   }
504
505   gst_query_unref (cquery);
506   temp_path = file_path;
507   GST_INFO_OBJECT (submux, "File path comes as %s", file_path);
508
509   file_path_type = g_strndup ((gchar *) file_path, 4);
510   GST_INFO_OBJECT (submux, "Received file path by query = %s, %s", file_path, file_path_type);
511   if (!g_strcmp0(file_path_type, "file")){
512     file_path += 7;
513     GST_INFO_OBJECT (submux, "File path comes as %s", file_path);
514
515     fp = fopen (file_path, "r");
516     if (!fp){
517       GST_ERROR_OBJECT (submux, "Failed to open file");
518       g_free(file_path_type);
519       g_free(temp_path);
520       return NULL;
521     }
522   } else {
523     GST_ERROR_OBJECT (submux, "File is not local");
524     g_free(file_path_type);
525     g_free(temp_path);
526     return NULL;
527   }
528   line = (gchar*)g_malloc (2049);
529   charCount = fread (line, sizeof(char), 2048, fp);
530   line[charCount] = '\0';
531   if (submux->encoding && strcmp (submux->encoding, "UTF-8"))
532     converted = convert_to_utf8 (line, charCount, submux->encoding, consumed, &err, submux);
533
534   if (converted)
535   {
536     GST_INFO("returned from conversion and length of converted string is[%d]", strlen(converted));
537     is_converted = TRUE;
538   }
539   if (!charCount) {
540     GST_WARNING_OBJECT (submux, "fread returned zero bytes");
541     fclose (fp);
542     g_free(file_path_type);
543     g_free(temp_path);
544     if(is_converted) {
545       g_free(converted);
546     }
547     g_free(line);
548     return NULL;
549   }
550   g_free(file_path_type);
551   g_free(temp_path);
552   fclose (fp);
553   if(is_converted) {
554     return converted;
555   }
556   return line;
557 }
558
559 static gpointer
560 gst_submux_data_format_autodetect_regex_once (GstSubMuxRegex regtype)
561 {
562   gpointer result = NULL;
563   GError *gerr = NULL;
564   switch (regtype) {
565     case GST_SUB_PARSE_REGEX_MDVDSUB:
566       result =
567           (gpointer) g_regex_new ("^\\{[0-9]+\\}\\{[0-9]+\\}",
568           G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, &gerr);
569       if (result == NULL) {
570         g_warning ("Compilation of mdvd regex failed: %s", gerr->message);
571         g_error_free (gerr);
572       }
573       break;
574     case GST_SUB_PARSE_REGEX_SUBRIP:
575       result = (gpointer) g_regex_new ("^ {0,3}[ 0-9]{1,4}\\s*(\x0d)?\x0a"
576           " ?[0-9]{1,2}: ?[0-9]{1,2}: ?[0-9]{1,2}[,.] {0,2}[0-9]{1,3}"
577           " +--> +[0-9]{1,2}: ?[0-9]{1,2}: ?[0-9]{1,2}[,.] {0,2}[0-9]{1,2}",
578           G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, &gerr);
579       if (result == NULL) {
580         g_warning ("Compilation of subrip regex failed: %s", gerr->message);
581         g_error_free (gerr);
582       }
583       break;
584     case GST_SUB_PARSE_REGEX_DKS:
585       result = (gpointer) g_regex_new ("^\\[[0-9]+:[0-9]+:[0-9]+\\].*",
586           G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, &gerr);
587       if (result == NULL) {
588         g_warning ("Compilation of dks regex failed: %s", gerr->message);
589         g_error_free (gerr);
590       }
591       break;
592     default:
593       GST_WARNING ("Trying to allocate regex of unknown type %u", regtype);
594   }
595   return result;
596 }
597
598 static GstSubMuxFormat
599 gst_submux_data_format_autodetect (gchar * match_str)
600 {
601   guint n1, n2, n3;
602
603   static GOnce mdvd_rx_once = G_ONCE_INIT;
604   static GOnce subrip_rx_once = G_ONCE_INIT;
605   static GOnce dks_rx_once = G_ONCE_INIT;
606
607   GRegex *mdvd_grx;
608   GRegex *subrip_grx;
609   GRegex *dks_grx;
610
611   g_once (&mdvd_rx_once,
612       (GThreadFunc) gst_submux_data_format_autodetect_regex_once,
613       (gpointer) GST_SUB_PARSE_REGEX_MDVDSUB);
614   g_once (&subrip_rx_once,
615       (GThreadFunc) gst_submux_data_format_autodetect_regex_once,
616       (gpointer) GST_SUB_PARSE_REGEX_SUBRIP);
617   g_once (&dks_rx_once,
618       (GThreadFunc) gst_submux_data_format_autodetect_regex_once,
619       (gpointer) GST_SUB_PARSE_REGEX_DKS);
620
621   mdvd_grx = (GRegex *) mdvd_rx_once.retval;
622   subrip_grx = (GRegex *) subrip_rx_once.retval;
623   dks_grx = (GRegex *) dks_rx_once.retval;
624
625   if (g_regex_match (mdvd_grx, match_str, 0, NULL) == TRUE) {
626     GST_LOG ("MicroDVD (frame based) format detected");
627     return GST_SUB_PARSE_FORMAT_MDVDSUB;
628   }
629   if (g_regex_match (subrip_grx, match_str, 0, NULL) == TRUE) {
630     GST_LOG ("SubRip (time based) format detected");
631     return GST_SUB_PARSE_FORMAT_SUBRIP;
632   }
633   if (g_regex_match (dks_grx, match_str, 0, NULL) == TRUE) {
634     GST_LOG ("DKS (time based) format detected");
635     return GST_SUB_PARSE_FORMAT_DKS;
636   }
637
638   if (!strncmp (match_str, "FORMAT=TIME", 11)) {
639     GST_LOG ("MPSub (time based) format detected");
640     return GST_SUB_PARSE_FORMAT_MPSUB;
641   }
642   if (strstr (match_str, "<SAMI>") != NULL ||
643       strstr (match_str, "<sami>") != NULL) {
644     GST_LOG ("SAMI (time based) format detected");
645     return GST_SUB_PARSE_FORMAT_SAMI;
646   }
647   /* we're boldly assuming the first subtitle appears within the first hour */
648   if (sscanf (match_str, "0:%02u:%02u:", &n1, &n2) == 2 ||
649       sscanf (match_str, "0:%02u:%02u=", &n1, &n2) == 2 ||
650       sscanf (match_str, "00:%02u:%02u:", &n1, &n2) == 2 ||
651       sscanf (match_str, "00:%02u:%02u=", &n1, &n2) == 2 ||
652       sscanf (match_str, "00:%02u:%02u,%u=", &n1, &n2, &n3) == 3) {
653     GST_LOG ("TMPlayer (time based) format detected");
654     return GST_SUB_PARSE_FORMAT_TMPLAYER;
655   }
656   if (sscanf (match_str, "[%u][%u]", &n1, &n2) == 2) {
657     GST_LOG ("MPL2 (time based) format detected");
658     return GST_SUB_PARSE_FORMAT_MPL2;
659   }
660   if (strstr (match_str, "[INFORMATION]") != NULL) {
661     GST_LOG ("SubViewer (time based) format detected");
662     return GST_SUB_PARSE_FORMAT_SUBVIEWER;
663   }
664   if (strstr (match_str, "{QTtext}") != NULL) {
665     GST_LOG ("QTtext (time based) format detected");
666     return GST_SUB_PARSE_FORMAT_QTTEXT;
667   }
668
669   GST_WARNING ("no subtitle format detected");
670   return GST_SUB_PARSE_FORMAT_UNKNOWN;
671 }
672
673 /*checking the type of subtitle*/
674 static gboolean
675 gst_submux_format_autodetect (Gstsubmux *self)
676 {
677   gchar *data;
678   GstSubMuxFormat format;
679   gchar * line = NULL;
680   if (self->priv->is_internal) {
681     GST_DEBUG_OBJECT (self, "File is of internal type");
682     return TRUE;
683   }
684   line = gst_submux_extract_data (self);
685   if (!line)
686     return FALSE;
687   if (strlen (line) < 30) {
688     GST_WARNING_OBJECT (self, "File too small to be a subtitles file");
689     g_free(line);
690     return FALSE;
691   }
692
693   data = g_strndup (line, 35);
694   format = gst_submux_data_format_autodetect (data);
695   g_free (data);
696
697   self->priv->parser_type = format;
698   g_free(line);
699
700   return TRUE;
701 }
702
703 /*to validate the number of languages in case of sami files*/
704 static gboolean
705 gst_calculate_number_languages(Gstsubmux *self) {
706   gchar* text=NULL;
707   gchar *start = NULL;
708   gchar *end = NULL;
709   gint count = 0;
710   gchar* found = NULL;
711   gchar * name_temp = NULL;
712   int i = 0, j = 0;
713
714   GST_DEBUG_OBJECT (self, "Entering in language number");
715
716   if ((self->priv->parser_type != GST_SUB_PARSE_FORMAT_SAMI) || self->priv->is_internal)
717     return TRUE;
718
719   text = gst_submux_extract_data (self);
720   start = g_strstr_len (text, strlen (text), "!--");
721   if (!start) {
722     GST_ERROR_OBJECT (self, "Could not found the language start code in smi file");
723     return gst_create_own_language_list(self);
724   }
725   end =  g_strstr_len (start, strlen (start), "-->");
726   if (!end){
727     GST_ERROR_OBJECT (self, "Could not found the language end code in smi file");
728     goto error;
729   }
730
731   found = start + 1;
732
733   while (TRUE) {
734     found = (gchar*)strcasestr (found, "lang");
735     if (!found)
736        break;
737     found++;
738     count++;
739   }
740
741   if (!count)
742   {
743     return gst_create_own_language_list(self);
744   }
745
746   for (i = 0; i < count; i++) {
747     gchar *attr_name = NULL, *attr_value = NULL;
748     GstLangStruct *new = NULL;
749
750     start = (gchar*)strcasestr (start, "lang:");
751     attr_value = (gchar*)malloc (3);
752     if (!attr_value) {
753       GST_ERROR_OBJECT (self, "memory could not be allocated through malloc call");
754       goto error;
755     }
756     start = start + 5;
757     strncpy (attr_value, start, 2);
758     attr_value[2] = '\0';
759     GST_DEBUG_OBJECT (self, "Language value comes as %s", attr_value);
760     name_temp = start;
761     while (TRUE) {
762       if (*name_temp == '{') {
763         int character_count = 0;
764         while (TRUE) {
765           name_temp--;
766
767           if (*name_temp == '.') {
768             attr_name = (gchar*) malloc (character_count + 1);
769             break;
770           } else if (*name_temp != ' ')
771              character_count++;
772         }
773         break;
774       }
775       name_temp--;
776     }
777     if (!attr_name) {
778       GST_ERROR_OBJECT (self, "Could not find the languages field in the file");
779       free(attr_value);
780       goto error;
781     }
782     name_temp++;
783     for (j = 0; *(name_temp + j) != ' '; j++) {
784       attr_name[j] = *(name_temp + j);
785     }
786     attr_name[j] = '\0';
787     new = g_new0 (GstLangStruct, 1);
788     new->language_code = (gchar*) malloc (strlen (attr_value) + 1);
789     if (new->language_code && attr_value)
790       strcpy (new->language_code, attr_value);
791     new->language_key = (gchar*) malloc (strlen (attr_name) + 1);
792     if (new->language_key && attr_name)
793       strcpy (new->language_key, attr_name);
794     free (attr_name);
795     free (attr_value);
796     self->priv->lang_list = g_list_append (self->priv->lang_list, new);
797   }
798   g_free(text);
799   return TRUE;
800 error:
801   g_free(text);
802   return FALSE;
803 }
804
805 /*to initialize stream*/
806 static gboolean gst_submux_stream_init(GstSubmuxStream * stream)
807 {
808   stream->duration = 0;
809   stream->need_segment = TRUE;
810   stream->flushing = FALSE;
811   stream->eos_sent = FALSE;
812   stream->eos_came = FALSE;
813   stream->discont_came = FALSE;
814   stream->eos_ts = -1;
815   stream->last_ts = -1;
816   stream->queue = g_queue_new ();
817   stream->queue_empty = g_cond_new ();
818   stream->queue_lock = g_mutex_new ();
819   stream->flush_done = FALSE;
820   return TRUE;
821 }
822
823 /*to create pipelines according to internal and external subtitle*/
824 gboolean gst_submux_create_pipelines(Gstsubmux *self, GstPad * pad)
825 {
826   int i = 0;
827   GstStateChangeReturn ret;
828   GstSubmuxStream *new_stream;
829   guint length = 0;
830
831   if (!self->priv->is_internal) {
832     GstLangStruct *cur_language=NULL;
833
834     GST_DEBUG_OBJECT (self, "creating the pipeline for external pipeline");
835     if (self->priv->parser_type == GST_SUB_PARSE_FORMAT_SAMI) {
836       if (!self->priv->lang_list) {
837         GST_ERROR_OBJECT(self, "failed to get the lang list");
838         return FALSE;
839       }
840       length = g_list_length (self->priv->lang_list);
841     } else {
842       length = 1;
843     }
844
845     GST_DEBUG_OBJECT (self, "number of tentative languages present are %d", length);
846
847     for (i = 0; i < length; i++) {
848       new_stream = g_new0 (GstSubmuxStream, 1);
849       if (!gst_submux_stream_init(new_stream)) {
850         GST_ERROR_OBJECT (self, "stream init is failed");
851         return FALSE;
852       }
853       GST_DEBUG_OBJECT (self, "stream init has been done for stream[%d]", i);
854
855       new_stream->pipe_struc.pipe = gst_pipeline_new ("subtitle-pipeline");
856       if (!new_stream->pipe_struc.pipe) {
857         GST_ERROR_OBJECT (self, "failed to create pipeline");
858         return FALSE;
859       }
860       GST_DEBUG_OBJECT (self, "creating appsrc");
861
862       /* creating source element */
863       new_stream->pipe_struc.appsrc = gst_element_factory_make ("appsrc", "pipe_appsrc");
864       if (!new_stream->pipe_struc.appsrc) {
865         GST_ERROR_OBJECT (self, "failed to create appsrc");
866         return FALSE;
867       }
868
869       g_object_set (G_OBJECT (new_stream->pipe_struc.appsrc), "block", 1, NULL);
870       g_object_set (G_OBJECT (new_stream->pipe_struc.appsrc), "max-bytes", (guint64)1, NULL);
871       /* create sink element */
872       new_stream->pipe_struc.appsink =  gst_element_factory_make ("appsink", "pipe_appsink");
873       if (!new_stream->pipe_struc.appsink) {
874         GST_ERROR_OBJECT (self, "failed to create appsink");
875         return FALSE;
876       }
877       g_object_set (G_OBJECT (new_stream->pipe_struc.appsink), "sync", FALSE, "emit-signals", TRUE, NULL);
878       g_object_set(G_OBJECT (new_stream->pipe_struc.appsrc),"emit-signals", TRUE, NULL);
879
880
881       /* create parsing element */
882       new_stream->pipe_struc.parser = gst_element_factory_make("subparse","pipe_parser");
883       if (!new_stream->pipe_struc.parser) {
884         GST_ERROR_OBJECT (self, "failed to create parser");
885         return FALSE;
886       }
887       if (self->priv->parser_type == GST_SUB_PARSE_FORMAT_SAMI) {
888         cur_language = g_list_nth_data(self->priv->lang_list, i);
889         g_object_set (G_OBJECT (new_stream->pipe_struc.parser), "current-language",
890                               cur_language->language_key, NULL);
891       }
892       GST_DEBUG_OBJECT (self, "value of subtitle-encoding  is %s", self->encoding);
893       g_object_set (G_OBJECT (new_stream->pipe_struc.parser), "subtitle-encoding", self->encoding, NULL);
894       g_object_set (G_OBJECT (new_stream->pipe_struc.appsrc), "stream-type",0,"format",GST_FORMAT_TIME, NULL);
895       gst_bin_add_many (GST_BIN ( new_stream->pipe_struc.pipe), new_stream->pipe_struc.appsink, new_stream->pipe_struc.appsrc,new_stream->pipe_struc.parser, NULL);
896       if (!gst_element_link_many (new_stream->pipe_struc.appsrc, new_stream->pipe_struc.parser,new_stream->pipe_struc.appsink, NULL)) {
897         GST_ERROR_OBJECT (self, "failed to link elements");
898         return FALSE;
899       }
900
901       GST_DEBUG_OBJECT (self, "reached here and linking successful");
902
903       ret = gst_element_set_state (new_stream->pipe_struc.pipe, GST_STATE_PLAYING);
904       if (ret == GST_STATE_CHANGE_FAILURE) {
905         GST_ERROR_OBJECT (self, "set_state failed...");
906         return FALSE;
907       }
908       GST_DEBUG_OBJECT (self, "state has been changed succesfully");
909       self->streams = g_list_append(self->streams, new_stream);
910       self->priv->stream_count++;
911       g_signal_connect (new_stream->pipe_struc.appsink, "new-buffer",  G_CALLBACK (gst_submux_on_new_buffer), g_list_nth_data(self->streams,i) );
912     }
913   } else {
914     length = self->sinkpads_count;
915     for (i = 0; i < length; i++) {
916       new_stream = g_new0 (GstSubmuxStream, 1);
917       if (!gst_submux_stream_init (new_stream)) {
918         GST_ERROR_OBJECT (self, "stream init is failed");
919         return FALSE;
920      }
921
922       self->streams=g_list_append(self->streams,new_stream);
923       self->priv->stream_count++;
924     }
925     self->pipeline_made  = TRUE;
926   }
927
928   self->cur_buf_array = g_malloc0 (self->priv->stream_count * (sizeof (GstBuffer *)));
929   if (!self->cur_buf_array) {
930     GST_ERROR_OBJECT (self, "failed to allocate memory..");
931     return FALSE;
932   }
933   return TRUE;
934 }
935
936 /* call back on recieving the new buffer in appsink pad */
937 static void
938 gst_submux_on_new_buffer (GstElement *appsink, void *data)
939 {
940   GstSubmuxStream *stream = (GstSubmuxStream  *)data;
941   GstBuffer *inbuf = NULL;
942
943   if (!stream) {
944     GST_WARNING("Stream not available...");
945     return;
946   }
947   g_mutex_lock (stream->queue_lock);
948   inbuf = gst_app_sink_pull_buffer ((GstAppSink *)appsink);
949   if (!inbuf) {
950     GST_WARNING_OBJECT (stream, "Input buffer not available...");
951     g_mutex_unlock (stream->queue_lock);
952     return;
953   }
954   if(stream->eos_ts == -1) {
955     if (!strcmp ((const char*)GST_BUFFER_DATA (inbuf), "eos") && GST_BUFFER_FLAG_IS_SET(inbuf,GST_BUFFER_FLAG_GAP)){
956       stream->eos_ts = stream->last_ts;
957       if (stream->eos_ts <= stream->seek_ts) {
958         g_queue_push_tail (stream->queue, inbuf);
959         g_cond_signal (stream->queue_empty);
960         g_mutex_unlock (stream->queue_lock);
961         GST_INFO_OBJECT (stream, "signaling queue empty signal as we are seeking beyond last subtitle");
962         return;
963       }
964       gst_buffer_unref(inbuf);
965     } else {
966       stream->last_ts = GST_BUFFER_DURATION(inbuf) + GST_BUFFER_TIMESTAMP(inbuf);
967     }
968   } else if (stream->eos_ts <= stream->seek_ts) {
969     gst_buffer_unref(inbuf);
970     GstBuffer *buf = gst_buffer_new_and_alloc (3 + 1);
971     GST_DEBUG_OBJECT(stream, "sending EOS buffer to chain\n");
972     GST_DEBUG_OBJECT (stream, "EOS. Pushing remaining text (if any)");
973     GST_BUFFER_DATA (buf)[0] = 'e';
974     GST_BUFFER_DATA (buf)[1] = 'o';
975     GST_BUFFER_DATA (buf)[2] = 's';
976     GST_BUFFER_DATA (buf)[3] = '\0';
977     /* play it safe */
978     GST_BUFFER_SIZE (buf) = 3;
979     GST_BUFFER_FLAG_SET(buf,GST_BUFFER_FLAG_GAP);
980     g_queue_push_tail (stream->queue, buf);
981     g_cond_signal (stream->queue_empty);
982     g_mutex_unlock (stream->queue_lock);
983     GST_INFO_OBJECT (stream,"signaling queue empty signal as we are seeking beyond last subtitle");
984     return;
985   }
986   if (!stream->discont_came) {
987     stream->discont_came = GST_BUFFER_IS_DISCONT (inbuf);
988     if (stream->discont_came) {
989       GST_DEBUG_OBJECT (stream, "first buffer with discont on new_buffer for stream with ts = %"
990                         GST_TIME_FORMAT", dur = %"GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(inbuf)),
991                         GST_TIME_ARGS(GST_BUFFER_DURATION(inbuf)));
992     }
993   }
994
995   if (!stream->discont_came) {
996     GST_DEBUG_OBJECT (stream, "rejecting the buffer in appsink on new_buffer for stream with ts = %"
997                       GST_TIME_FORMAT", dur = %"GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(inbuf)),
998                       GST_TIME_ARGS(GST_BUFFER_DURATION(inbuf)));
999     gst_buffer_unref(inbuf);
1000     g_mutex_unlock (stream->queue_lock);
1001     return;
1002   }
1003   g_queue_push_tail (stream->queue, inbuf);
1004   g_cond_signal (stream->queue_empty);
1005   g_mutex_unlock (stream->queue_lock);
1006   GST_DEBUG_OBJECT (stream, "signaling queue empty signal");
1007   return;
1008 }
1009
1010 gchar *
1011 convert_to_utf8 (const gchar * str, gsize len, const gchar * encoding,
1012     gsize * consumed, GError ** err, Gstsubmux * self)
1013 {
1014   gchar *ret = NULL;
1015
1016   /* The char cast is necessary in glib < 2.24 */
1017   ret =
1018       g_convert_with_fallback (str, len, "UTF-8", encoding, (char *) "*",
1019       consumed, NULL, err);
1020
1021   if (ret == NULL)
1022   {
1023     GST_DEBUG_OBJECT (self, "g_convert_with_fallback returns NULL");
1024     return ret;
1025   }
1026
1027   /* + 3 to skip UTF-8 BOM if it was added */
1028   len = strlen (ret);
1029   if (len >= 3 && (guint8) ret[0] == 0xEF && (guint8) ret[1] == 0xBB
1030       && (guint8) ret[2] == 0xBF)
1031     g_memmove (ret, ret + 3, len + 1 - 3);
1032
1033   return ret;
1034 }
1035
1036 static gchar *
1037 detect_encoding (const gchar * str, gsize len)
1038 {
1039   if (len >= 3 && (guint8) str[0] == 0xEF && (guint8) str[1] == 0xBB
1040       && (guint8) str[2] == 0xBF)
1041     return g_strdup ("UTF-8");
1042
1043   if (len >= 2 && (guint8) str[0] == 0xFE && (guint8) str[1] == 0xFF)
1044     return g_strdup ("UTF-16BE");
1045
1046   if (len >= 2 && (guint8) str[0] == 0xFF && (guint8) str[1] == 0xFE)
1047     return g_strdup ("UTF-16LE");
1048
1049   if (len >= 4 && (guint8) str[0] == 0x00 && (guint8) str[1] == 0x00
1050       && (guint8) str[2] == 0xFE && (guint8) str[3] == 0xFF)
1051     return g_strdup ("UTF-32BE");
1052
1053   if (len >= 4 && (guint8) str[0] == 0xFF && (guint8) str[1] == 0xFE
1054       && (guint8) str[2] == 0x00 && (guint8) str[3] == 0x00)
1055     return g_strdup ("UTF-32LE");
1056
1057   return NULL;
1058 }
1059
1060 /* If language list is not present in smi file, check the body and create our own list */
1061 static gboolean
1062 gst_create_own_language_list (Gstsubmux *self)
1063 {
1064   gchar * file_path_type = NULL;
1065   gchar * temp_path = NULL;
1066   gchar * file_path = NULL;
1067   gsize * consumed = NULL;
1068   guint keyCount = 0;
1069   GError *err = NULL;
1070   GstPad *sinkpad = (GstPad *) g_list_nth_data(self->sinkpad, 0);
1071   GstQuery *cquery;
1072   GstStructure *structure;
1073   const GValue *value;
1074   gchar* langkey[MAX_LANG];
1075   gint langKey_length[MAX_LANG];
1076   FILE *fp=NULL;
1077   gint i=0;
1078   structure = gst_structure_new ("FileSrcURI", "file-uri", G_TYPE_STRING, NULL, NULL);
1079
1080   cquery = gst_query_new_application (GST_QUERY_CUSTOM, structure);
1081
1082   if (!gst_pad_peer_query (sinkpad, cquery)) {
1083     GST_ERROR_OBJECT (self, "Failed to query SMI file path");
1084     gst_query_unref (cquery);
1085     return FALSE;
1086   }
1087   structure = gst_query_get_structure (cquery);
1088   value = gst_structure_get_value (structure, "file-uri");
1089   file_path = g_strdup (g_value_get_string (value));
1090
1091   if (file_path == NULL){
1092     GST_ERROR_OBJECT (self, "Could not parse the SMI file path");
1093     gst_query_unref (cquery);
1094     return FALSE;
1095   }
1096   gst_query_unref (cquery);
1097   temp_path = file_path;
1098   GST_INFO_OBJECT (self, "File path comes as %s", file_path);
1099
1100   file_path_type = g_strndup ((gchar *) file_path, 4);
1101   GST_INFO_OBJECT (self, "Received file path by query = %s, %s", file_path, file_path_type);
1102   if (!g_strcmp0(file_path_type, "file")){
1103     file_path += 7;
1104     GST_INFO_OBJECT (self, "File path comes as %s", file_path);
1105
1106     fp = fopen (file_path, "r");
1107     if (!fp){
1108       GST_ERROR_OBJECT (self, "Failed to open file");
1109       g_free(temp_path);
1110       g_free(file_path_type);
1111       return FALSE;
1112     }
1113   }
1114   for( i=0;i<MAX_LANG;i++){
1115     langkey[i]=NULL;
1116     langKey_length[i]=0;
1117   }
1118   gboolean lang_found= FALSE;
1119   while (!feof (fp) ){
1120     gchar line[1025];
1121     guint charCount = 0;
1122     gboolean conversion = TRUE;
1123     gchar *result = NULL;
1124     gchar *con_temp = NULL;
1125     gchar *delimiter = NULL;
1126     gchar *temp = NULL;
1127     guint keyLength = 0;
1128
1129     charCount = fread (line, sizeof(char), 1024, fp);
1130     line[charCount] = '\0';
1131     if (!charCount) {
1132       GST_WARNING_OBJECT (self, "fread returned zero bytes");
1133       continue;
1134     }
1135     GST_DEBUG_OBJECT (self, " Read charCount %d bytes Successfully",charCount);
1136     GST_DEBUG_OBJECT (self, "value of detected encoding is %s and self encoding is %s",
1137         self->detected_encoding,self->encoding);
1138     if (self->detected_encoding && strcmp (self->detected_encoding, "UTF-8") && conversion){
1139       result = convert_to_utf8 (line, charCount, self->detected_encoding, consumed, &err, self);
1140       GST_DEBUG_OBJECT (self, " Converted convert_to_utf8  result %d ",result);
1141     }
1142     if (result == NULL) {
1143       result = line;
1144       conversion =  FALSE;
1145     }
1146     con_temp =  result;
1147     temp = con_temp;
1148
1149     while (con_temp){
1150       gchar* tempKey = NULL;
1151       guint i = 0;
1152
1153       con_temp =  strcasestr(con_temp,"class=");
1154       if(con_temp)
1155         delimiter =  strcasestr(con_temp, ">");
1156       GST_DEBUG_OBJECT (self, " Delimiter ...Entering if %s",con_temp);
1157       if (con_temp && (delimiter!=NULL)){
1158         gchar* tempChar = con_temp + 6;
1159         GST_DEBUG_OBJECT (self, "Has class= reading string %s",tempChar);
1160         GST_DEBUG_OBJECT (self, "Has class= ");
1161         while (*tempChar != '>'){
1162           keyLength++;
1163           tempChar++;
1164           GST_DEBUG_OBJECT (self, " keyLength %d tempChar %c",keyLength,*tempChar);
1165         }
1166         GST_DEBUG_OBJECT (self, " keyLength  %d",keyLength);
1167         tempChar -= keyLength;
1168         tempKey = (gchar*) g_malloc (keyLength + 1);
1169         if(!tempKey){
1170           GST_DEBUG_OBJECT (self, "Error 1");
1171           goto error;
1172         }
1173         gchar* temp1 =tempKey;
1174         GST_DEBUG_OBJECT (self, "tempChar %s  keyLength  %d",tempChar,keyLength);
1175         while (*tempChar != '>'){
1176           *tempKey = *tempChar;
1177           tempKey++;
1178           tempChar++;
1179         }
1180         tempKey =temp1;
1181         tempKey[keyLength]='\0';
1182         GST_DEBUG_OBJECT (self, "tempKey %s  keyLength %d keyCount %d",tempKey,keyLength,keyCount);
1183         int k =0;
1184         for (k = 0; k < keyCount; k++){
1185           if(langkey[k]){
1186             if (!strcasecmp (tempKey,langkey[k]))
1187             {
1188               GST_DEBUG_OBJECT (self, "Has the key already so breaking..Entry %d tempKey %s langkey[i] %s ",k,tempKey,langkey[k]);
1189               lang_found = TRUE;
1190               break;
1191             }
1192           }
1193         }
1194         if(lang_found == FALSE){
1195           langkey[keyCount] = (gchar*) g_malloc (keyLength);
1196           if(! langkey[keyCount])
1197             goto error;
1198           strcpy(langkey[keyCount],tempKey);
1199           langKey_length[keyCount]=keyLength;
1200           keyCount++;
1201         }
1202         lang_found =FALSE;
1203         keyLength =0;
1204         if(tempKey){
1205           g_free(tempKey);
1206           tempKey=NULL;
1207         }
1208       } else {
1209         keyLength =0;
1210         lang_found =FALSE;
1211         break;
1212       }
1213       con_temp+=6;
1214       GST_DEBUG_OBJECT (self, " ..increment con_temp %s",con_temp);
1215     }
1216   }
1217   GST_DEBUG_OBJECT (self, " At end keyCount no of langs is %d ",keyCount);
1218   for(i=0;i<keyCount;i++) {
1219     if(langkey[i]) {
1220       GstLangStruct *new = g_new0 (GstLangStruct, 1);
1221       GST_DEBUG_OBJECT (self, "Adding ign case to the langKey keyCount %d and lang %s ",i, langkey[i]);
1222       new->language_code = (gchar*)malloc (3);
1223       if(!(new->language_code)){
1224         GST_DEBUG_OBJECT (self, " .Error 2");
1225         goto error;
1226       }
1227       gchar *attr_val=new->language_code ;
1228       strcpy (attr_val, "un");
1229       attr_val[2]='\0';
1230
1231       new->language_key = (gchar*) malloc (langKey_length[i] + 1);
1232       if(!(new->language_key)){
1233         GST_DEBUG_OBJECT (self, " ..Error 3");
1234         goto error;
1235       }
1236       strcpy (new->language_key, langkey[i]);
1237       self->priv->lang_list = g_list_append (self->priv->lang_list, new);
1238       GST_DEBUG_OBJECT (self, " new...Successfull");
1239       g_free(langkey[i]);
1240     }
1241   }
1242   if (fp) {
1243     g_free(temp_path);
1244     g_free(file_path_type);
1245     fclose(fp);
1246   }
1247   return TRUE;
1248 error:
1249   GST_DEBUG_OBJECT (self, " In Error");
1250   if (fp) {
1251     g_free(temp_path);
1252     g_free(file_path_type);
1253     fclose(fp);
1254   }
1255   return FALSE;
1256 }
1257
1258 gboolean
1259 validate_langlist_body(GList * lang_list, Gstsubmux * self){
1260   gchar * file_path_type = NULL;
1261   gchar * file_path = NULL;
1262   gchar   line[1025];
1263   FILE  * fp = NULL;
1264   guint i = 0, found_count = 0,k = 0;
1265   const guint list_len = g_list_length(lang_list);
1266   gboolean counter[MAX_LANGUAGE];
1267   GstPad  *sinkpad = NULL;
1268   struct LangStruct
1269   {
1270       gchar *language_code;
1271       gchar *language_key;
1272   } * lang;
1273   sinkpad = (GstPad *) g_list_nth_data(self->sinkpad, 0);
1274   GstQuery *cquery;
1275   GstStructure *structure;
1276   const GValue *value;
1277   structure = gst_structure_new ("FileSrcURI", "file-uri", G_TYPE_STRING, NULL, NULL);
1278
1279   cquery = gst_query_new_application (GST_QUERY_CUSTOM, structure);
1280
1281   if (!gst_pad_peer_query (sinkpad, cquery)) {
1282     GST_ERROR_OBJECT (self, "Failed to query SMI file path");
1283     gst_query_unref (cquery);
1284     return FALSE;
1285   }
1286   structure = gst_query_get_structure (cquery);
1287   value = gst_structure_get_value (structure, "file-uri");
1288   file_path = g_strdup (g_value_get_string (value));
1289
1290   if (file_path == NULL){
1291     GST_ERROR_OBJECT (self, "Could not parse the SMI file path");
1292     gst_query_unref (cquery);
1293     return FALSE;
1294   }
1295
1296   if (self->external_filepath == NULL) {
1297     self->external_filepath = file_path;
1298   }
1299   else {
1300     if (!g_strcmp0 (file_path, self->external_filepath)) {
1301       GST_INFO_OBJECT (self, "Same external file URI, no need to parse again");
1302       gst_query_unref (cquery);
1303       g_free(file_path);
1304       return TRUE;
1305     }
1306     else {
1307       g_free (self->external_filepath);
1308       self->external_filepath = NULL;
1309       self->external_filepath = file_path;
1310     }
1311   }
1312
1313   gst_query_unref (cquery);
1314   GST_INFO_OBJECT (self, "File path comes as %s", file_path);
1315
1316   file_path_type = g_strndup ((gchar *) file_path, 4);
1317   GST_INFO_OBJECT (self, "Received file path by query = %s, %s", file_path, file_path_type);
1318   if (!g_strcmp0(file_path_type, "file")){
1319     file_path += 7;
1320     GST_INFO_OBJECT (self, "File path comes as %s", file_path);
1321
1322     fp = fopen (file_path, "r");
1323     if (!fp){
1324       GST_ERROR_OBJECT (self, "Failed to open file");
1325       g_free(file_path_type);
1326       return FALSE;
1327     }
1328
1329     for (i = 0; i < list_len; i++){
1330       counter[i] = FALSE;
1331     }
1332
1333     while (!feof (fp) && found_count < list_len){
1334       GError *err = NULL;
1335       gsize * consumed = NULL;
1336       gint gap = 0;
1337       guint charCount = 0;
1338       gchar* result = NULL;
1339       gchar* temp = NULL;
1340       gchar* temp_lang = NULL;
1341       gchar* con_temp_end = NULL;
1342       gchar* con_temp_start = NULL;
1343       gchar* new_key = NULL;
1344       gint new_key_length = 0;
1345       gboolean new_key_found = FALSE;
1346       gchar * temp1 = NULL;
1347       gchar *con_temp_lang = NULL;
1348       gchar *con_temp = NULL;
1349       gboolean conversion = TRUE;
1350       charCount = fread (line, sizeof(char), 1024, fp);
1351       line[charCount] = '\0';
1352       if (!charCount) {
1353         GST_WARNING_OBJECT (self, "fread returned zero bytes");
1354         continue;
1355       }
1356
1357       GST_DEBUG_OBJECT (self, "value of detected encoding is %s and self encoding is %s",
1358                              self->detected_encoding,self->encoding);
1359       if (self->detected_encoding && strcmp (self->detected_encoding, "UTF-8") && conversion){
1360         result = convert_to_utf8 (line, charCount, self->detected_encoding, consumed, &err, self);
1361       }
1362       if (result == NULL) {
1363          result = line;
1364          conversion =  FALSE;
1365       }
1366       con_temp = g_utf8_strdown (result, strlen (result));
1367       temp = con_temp;
1368       while (con_temp) {
1369         con_temp = g_strstr_len(con_temp, strlen (con_temp), "class=");
1370         if (con_temp) {
1371           temp1 = g_strstr_len(con_temp+1, strlen (con_temp), "class=");
1372         }
1373         if (temp1 && con_temp){
1374           gap = strlen (con_temp) - strlen (temp1);
1375         } else if (con_temp) {
1376           gap = strlen (con_temp);
1377         } else {
1378           continue;
1379         }
1380         if (con_temp){
1381           for (i = 0; i < list_len; i++){
1382             if (counter[i] == TRUE) {
1383               con_temp = con_temp + 1;
1384               continue;
1385             }
1386             lang = (struct LangStruct *) g_list_nth_data (lang_list, i);
1387             if (lang) {
1388               temp_lang = (gchar*)g_malloc (strlen (lang->language_key) + 1);
1389               strcpy (temp_lang, lang->language_key);
1390               con_temp_lang = g_utf8_strdown (temp_lang, strlen (temp_lang));
1391               if (g_strstr_len (con_temp, gap, con_temp_lang)) {
1392                 found_count++;
1393                 counter[i] = TRUE;
1394                 GST_INFO_OBJECT (self, "Valid Language in list : [%s]", lang->language_key);
1395                 con_temp = con_temp + 1;
1396               }
1397 /* Fix Me: Cases where there is no body for a specific language
1398  * inside a single language .smi file */
1399 #if 0
1400               else {
1401                 con_temp_start = con_temp;
1402                 con_temp_end = con_temp;
1403                 while(con_temp_end) {
1404                   if(*con_temp_end == '=') {
1405                     con_temp_start = con_temp_end+1;
1406                     con_temp_end++;
1407                   }else if(*con_temp_end == '>') {
1408                     con_temp_end = con_temp_end;
1409                     new_key_found = TRUE;
1410                     break;
1411                   }else {
1412                     con_temp_end++;
1413                     new_key_found = FALSE;
1414                   }
1415                 }
1416                 if(new_key_found) {
1417                   new_key_length = strlen(con_temp_start)-strlen(con_temp_end);
1418                   new_key = g_malloc(new_key_length +1);
1419                   for(k=0;k<new_key_length;k++){
1420                     *(new_key+k)=*(con_temp_start+k);
1421                   }
1422                   *(new_key+new_key_length)='\0';
1423                   GST_INFO("new lang key is %s",lang->language_key);
1424                   g_free(new_key);
1425                   found_count++;
1426                   counter[i] = TRUE;
1427                   con_temp = con_temp + 1;
1428                 }
1429               }
1430 #endif
1431               g_free (temp_lang);
1432               g_free (con_temp_lang);
1433             }
1434           }
1435         }
1436       }
1437       if (conversion)
1438         g_free (result);
1439       if (temp)
1440         g_free (temp);
1441     }
1442
1443     if (found_count < list_len) {
1444       for (i = 0; i < list_len; i++) {
1445         if (counter[i] == FALSE)
1446           lang_list = g_list_delete_link (lang_list, g_list_nth (lang_list, i));
1447       }
1448     }
1449   } else {
1450     GST_ERROR_OBJECT (self, "File is not a local file");
1451     g_free(file_path_type);
1452     return FALSE;
1453   }
1454   fclose (fp);
1455   g_free(file_path_type);
1456   return TRUE;
1457 }
1458
1459 /*
1460 **
1461 **  Description    : Chain function used to push the subtitle buffer to internal pipelines of submux element
1462 **  Params        : (1) sink pad on which buffer is arriving (2) the buffer itself
1463 **  return        : GST_FLOW_OK on successfully pushing subtitle buffer to next element
1464 **
1465 */
1466 static GstFlowReturn
1467 gst_submux_chain(GstPad *pad, GstBuffer *buffer)
1468 {
1469   guint length = 0;
1470   guint i=0;
1471   GstPad *checkpad = NULL;
1472   Gstsubmux *submux = GST_SUBMUX(GST_PAD_PARENT(pad));
1473   gboolean ret = FALSE;
1474   GstFlowReturn fret = GST_FLOW_ERROR;
1475   GstSubmuxStream *stream = NULL;
1476   GstMessage *m = NULL;
1477
1478   if (GST_BUFFER_IS_DISCONT (buffer))
1479     GST_DEBUG_OBJECT(submux, "Discont buffer came in chain function");
1480   GST_DEBUG_OBJECT (submux, "^^^^^entering in chain^^^^^^");
1481   if (!submux->priv->is_internal) {
1482     if (!submux->priv->first_buffer) {
1483       submux->detected_encoding = detect_encoding ((gchar*)GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
1484     }
1485     if (!submux->langlist_msg_posted && submux->priv->lang_list) {
1486       if (!validate_langlist_body (submux->priv->lang_list, submux)){
1487         GST_WARNING_OBJECT(submux, "Error occured while validating language list. Posting without validation");
1488       }
1489       if (submux->priv->lang_list) {
1490         GList* temp_list_to_post = NULL;
1491         temp_list_to_post = g_list_copy (submux->priv->lang_list);
1492         m = gst_message_new_element (GST_OBJECT_CAST (submux), gst_structure_new("Ext_Sub_Language_List",
1493                                     "lang_list", G_TYPE_POINTER, temp_list_to_post, NULL));
1494
1495         gst_element_post_message (GST_ELEMENT_CAST (submux), m);
1496         submux->langlist_msg_posted = TRUE;
1497       }
1498       GST_DEBUG_OBJECT (submux, "LANGLIST POSTED");
1499     }
1500     if (submux->need_segment) {
1501       ret = gst_pad_push_event (submux->srcpad, gst_event_new_new_segment (FALSE, submux->segment.rate,
1502                                 submux->segment.format, submux->segment.start, submux->segment.stop,
1503                                 submux->segment.time));
1504       GST_DEBUG_OBJECT (submux, "pushing newsegment event with %" GST_SEGMENT_FORMAT, &submux->segment);
1505       if (!ret) {
1506         GST_ERROR_OBJECT (submux, "Sending newsegment to next element is failed");
1507         return GST_FLOW_ERROR;
1508       }
1509       GST_DEBUG_OBJECT (submux, "Starting the loop again");
1510       if (!gst_pad_start_task (submux->srcpad, (GstTaskFunction) gst_submux_loop, submux)) {
1511          GST_ERROR_OBJECT (submux, "failed to start srcpad task...");
1512          GST_ELEMENT_ERROR (submux, RESOURCE, FAILED, ("failed to create  push loop"), (NULL));
1513          return GST_FLOW_ERROR;
1514       }
1515       submux->need_segment = FALSE;
1516     }
1517     GST_DEBUG_OBJECT (submux, "before pushing buffer to each apprsrc");
1518     if (!submux->priv->lang_list && submux->priv->parser_type == GST_SUB_PARSE_FORMAT_SAMI) {
1519       GST_ERROR_OBJECT (submux, "lang list is not there");
1520       return GST_FLOW_ERROR;
1521     }
1522     if (submux->priv->parser_type == GST_SUB_PARSE_FORMAT_SAMI)
1523       length = g_list_length (submux->priv->lang_list);
1524     else
1525       length = 1;
1526
1527     for (i = 0; i < length; i++) {
1528       stream = g_list_nth_data(submux->streams, i);
1529       if ((submux->priv->parser_type == GST_SUB_PARSE_FORMAT_SAMI) && !submux->priv->first_buffer){
1530         GstLangStruct *lang = g_list_nth_data(submux->priv->lang_list, i);
1531         if(submux->msl_streams){
1532            GstLangStruct *lang1 = g_list_nth_data(submux->msl_streams, i);
1533            lang->active = lang1->active;
1534         } else {
1535           if (i == 0)
1536             lang->active = TRUE;
1537           else
1538             lang->active = FALSE;
1539         }
1540       }
1541       GST_DEBUG_OBJECT (submux, "making stream need segment false");
1542       stream->need_segment = FALSE;
1543     }
1544
1545     for (i = 0; i < length; i++) {
1546       stream = g_list_nth_data(submux->streams, i);
1547       if (!stream){
1548         GST_ERROR_OBJECT (submux, "stream not found");
1549         return GST_FLOW_ERROR;
1550       }
1551
1552       if (!stream->pipe_struc.appsrc) {
1553         GST_ERROR_OBJECT (submux, "appsrc not found");
1554         return GST_FLOW_ERROR;
1555       }
1556       if (i < (length - 1))
1557         gst_buffer_ref (buffer);
1558
1559       fret = gst_app_src_push_buffer ((GstAppSrc*)stream->pipe_struc.appsrc, buffer);
1560
1561       if (fret != GST_FLOW_OK) {
1562         GST_ERROR_OBJECT (submux, "push buffer failed with fret is %d", fret);
1563         return fret;
1564       }
1565       GST_DEBUG_OBJECT (submux, "pad_push successfull to appsrc %p buffer", buffer);
1566     }
1567   } else {
1568     length = submux->sinkpads_count;
1569     checkpad = (GstPad *) g_list_nth_data (submux->sinkpad, 0);
1570     if (checkpad == pad) {
1571       if (submux->need_segment) {
1572         ret = gst_pad_push_event (submux->srcpad, gst_event_new_new_segment (FALSE, submux->segment.rate,
1573                                   submux->segment.format, submux->segment.start, submux->segment.stop,
1574                                   submux->segment.time));
1575         GST_DEBUG_OBJECT (submux, "pushing newsegment event with %" GST_SEGMENT_FORMAT, &submux->segment);
1576         if (!ret) {
1577           GST_ERROR_OBJECT (submux, "Sending newsegment to next element is failed");
1578           return GST_FLOW_ERROR;
1579         }
1580         GST_DEBUG_OBJECT (submux, "Starting the loop again");
1581         if (!gst_pad_start_task (submux->srcpad, (GstTaskFunction) gst_submux_loop, submux)) {
1582           GST_ERROR_OBJECT (submux, "failed to start srcpad task...");
1583           GST_ELEMENT_ERROR (submux, RESOURCE, FAILED, ("failed to create  push loop"), (NULL));
1584           return GST_FLOW_ERROR;
1585         }
1586         submux->need_segment = FALSE;
1587       }
1588     }
1589     for (i = 0; i < length; i++) {
1590       checkpad = (GstPad *) g_list_nth_data(submux->sinkpad, i);
1591       if (checkpad == pad) {
1592         stream = g_list_nth_data (submux->streams, i);
1593         if (!stream) {
1594           GST_ERROR_OBJECT (submux, "Stream not available...");
1595           return GST_FLOW_ERROR;
1596         }
1597         if (stream->flushing){
1598           GST_DEBUG_OBJECT (submux, "flushing going on in appsink");
1599           return GST_FLOW_OK ;
1600         }
1601
1602         g_mutex_lock (stream->queue_lock);
1603         g_queue_push_tail (stream->queue, buffer);
1604         g_cond_signal (stream->queue_empty);
1605         g_mutex_unlock (stream->queue_lock);
1606         fret = GST_FLOW_OK;
1607         GST_DEBUG_OBJECT (submux, "push buffer success to appsrc with fret is %d for stream[%d]", fret, i);
1608         break;
1609       }
1610     }
1611   }
1612
1613   if (!submux->priv->first_buffer) {
1614     GST_DEBUG_OBJECT (submux, "got the first buffer");
1615     submux->priv->first_buffer = TRUE;
1616     if (submux->priv->parser_type == GST_SUB_PARSE_FORMAT_SAMI) {
1617
1618     }
1619   }
1620   GST_DEBUG_OBJECT (submux, "^^^^^exiting in chain^^^^^^");
1621   return fret;
1622 }
1623
1624 /* stream_denit */
1625 static void
1626 gst_submux_stream_deinit (GstSubmuxStream *stream,Gstsubmux *submux)
1627 {
1628   GstBuffer *buf = NULL;
1629
1630   if (stream) {
1631     if (stream->queue) {
1632       while (!g_queue_is_empty (stream->queue)) {
1633         buf = g_queue_pop_head (stream->queue);
1634         gst_buffer_unref (buf);
1635         buf = NULL;
1636       }
1637       g_queue_free (stream->queue);
1638       stream->queue = NULL;
1639     }
1640
1641     if (stream->pipe_struc.pipe) {
1642       gst_element_set_state (stream->pipe_struc.pipe, GST_STATE_NULL);
1643       gst_element_get_state (stream->pipe_struc.pipe, NULL, NULL, GST_CLOCK_TIME_NONE);
1644       gst_object_unref(GST_OBJECT(stream->pipe_struc.appsrc));
1645       gst_object_unref(GST_OBJECT(stream->pipe_struc.appsink));
1646       gst_object_unref (stream->pipe_struc.pipe);
1647     }
1648
1649     if (stream->queue_lock) {
1650       g_cond_broadcast(stream->queue_empty);
1651       g_mutex_free (stream->queue_lock);
1652       stream->queue_lock = NULL;
1653     }
1654
1655     if (stream->queue_empty) {
1656       g_cond_free (stream->queue_empty);
1657       stream->queue_empty= NULL;
1658     }
1659
1660     g_free (stream);
1661     GST_DEBUG_OBJECT (submux, "stream deinit completed");
1662   }
1663 }
1664
1665 /* releasing the requested pad */
1666 static void
1667 gst_submux_release_pad (GstElement * element, GstPad * pad)
1668 {
1669   Gstsubmux *submux = GST_SUBMUX_CAST (element);
1670   GstPad *check_pad;
1671   int i=0;
1672   guint length;
1673   GST_INFO_OBJECT(element,"entering in the release pad");
1674   length = g_list_length(submux->sinkpad);
1675   GST_DEBUG_OBJECT (element, "Releasing %s:%s", GST_DEBUG_PAD_NAME (pad));
1676
1677   for (i=1;i<=length;i++) {
1678           check_pad = (struct GstPad *) g_list_nth_data(submux->sinkpad,i);
1679     if (check_pad == pad) {
1680       /* this is it, remove */
1681       submux->sinkpad = g_list_remove_link (submux->sinkpad, pad);
1682       gst_element_remove_pad (element, pad);
1683       break;
1684     }
1685   }
1686 }
1687
1688 /* request new pad */
1689 static GstPad *
1690 gst_submux_request_new_pad (GstElement * element,
1691     GstPadTemplate * templ, const gchar * req_name)
1692 {
1693   GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
1694   Gstsubmux *submux = GST_SUBMUX_CAST (element);
1695   GstPad *newpad = NULL;
1696   gchar *name = NULL;
1697
1698   if (templ->direction != GST_PAD_SINK) {
1699     GST_ERROR_OBJECT (submux, "templ direction is not sinkpad, returning from here");
1700     goto wrong_direction;
1701   }
1702
1703   if (templ == gst_element_class_get_pad_template (klass, "sink%d")) {
1704     name = g_strdup_printf ("sink%d", submux->sinkpads_count++);
1705   }
1706
1707   GST_DEBUG_OBJECT (submux, "Requested pad: %s", name);
1708   newpad = (GstPad*)g_new0 (GstPad*, 1);
1709   /* create pad and add to collections */
1710   newpad = gst_pad_new_from_template (templ, name);
1711   g_free (name);
1712   if(!submux->priv->is_internal) {
1713     submux->external_sinkpad = TRUE;
1714   }
1715   submux->sinkpad = g_list_append (submux->sinkpad, newpad);
1716   /* set up pad */
1717
1718   /* set up pad functions */
1719   gst_pad_set_setcaps_function (newpad, GST_DEBUG_FUNCPTR (gst_submux_setcaps));
1720   gst_pad_set_event_function (newpad, GST_DEBUG_FUNCPTR (gst_submux_handle_sink_event));
1721   gst_pad_set_chain_function(newpad, GST_DEBUG_FUNCPTR (gst_submux_chain));
1722   gst_pad_set_active (newpad, TRUE);
1723   gst_element_add_pad (element, newpad);
1724
1725   return newpad;
1726
1727 /* ERRORS */
1728 wrong_direction:
1729   GST_WARNING_OBJECT (submux, "Request pad that is not a SINK pad.");
1730   return NULL;
1731 }
1732
1733 static gboolean
1734 gst_submux_handle_src_event (GstPad * pad, GstEvent * event)
1735 {
1736   Gstsubmux *submux = GST_SUBMUX(GST_PAD_PARENT(pad));
1737   gboolean ret = FALSE;
1738   guint length = 0;
1739   gint i = 0;
1740   gboolean update;
1741   GstSubmuxStream *cur_stream = NULL;
1742
1743   GST_DEBUG_OBJECT (submux, "Handling %s event", GST_EVENT_TYPE_NAME (event));
1744   length = g_list_length(submux->streams);
1745
1746   switch (GST_EVENT_TYPE (event)) {
1747     /* this event indicates speed change or seek */
1748     case GST_EVENT_SEEK: {
1749       GstFormat format;
1750       GstSeekType start_type, stop_type;
1751       gint64 start, stop;
1752       gdouble rate;
1753       GstPad *sinkpad = (GstPad *) g_list_nth_data (submux->sinkpad, 0);
1754       gst_event_parse_seek (event, &rate, &format, &submux->segment_flags,
1755                              &start_type, &start, &stop_type, &stop);
1756       gst_segment_set_seek (&submux->segment, rate, format, submux->segment_flags,
1757                              start_type, start, stop_type, stop, &update);
1758       if (submux->priv->is_internal || submux->priv->parser_type != GST_SUB_PARSE_FORMAT_SAMI) {
1759         length = g_list_length (submux->sinkpad);
1760       } else {
1761         length = g_list_length(submux->streams);
1762       }
1763       if (!submux->priv->is_internal) {
1764         ret = gst_pad_push_event (sinkpad, gst_event_new_seek (rate, GST_FORMAT_BYTES, submux->segment_flags,
1765                                   GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, 0));
1766         gst_event_unref (event);
1767       } else {
1768         GST_DEBUG_OBJECT (submux, "handling seek in case of internal");
1769         ret = gst_pad_event_default (pad, event);
1770       }
1771
1772       if (!ret) {
1773         GST_ERROR_OBJECT (submux, "sending seek event to sink pad failed");
1774         break;
1775       }
1776       GST_DEBUG_OBJECT (submux, "sending seek event to sink pad passed");
1777
1778       break;
1779     }
1780
1781     default: {
1782       ret = gst_pad_event_default (pad, event);
1783       break;
1784     }
1785   }
1786
1787   return ret;
1788 }
1789
1790 static gboolean
1791 gst_submux_handle_sink_event (GstPad * pad, GstEvent * event)
1792 {
1793   Gstsubmux *submux = GST_SUBMUX (GST_PAD_PARENT (pad));
1794   gboolean ret = FALSE;
1795   guint length = 0;
1796   GstBuffer *buf = NULL;
1797   GstPad *checkpad = NULL;
1798   gint i = 0;
1799   GstSubmuxStream *cur_stream = NULL;
1800
1801   GST_DEBUG_OBJECT (submux, "Handling %s event", GST_EVENT_TYPE_NAME (event));
1802
1803   switch (GST_EVENT_TYPE (event)) {
1804     case GST_EVENT_EOS:{
1805       length = g_list_length (submux->sinkpad);
1806       GST_OBJECT_LOCK (submux);
1807       for (i = 0; i < length; i++) {
1808         GST_DEBUG_OBJECT(submux, "inside the handling of EOS event");
1809         cur_stream = g_list_nth_data(submux->streams,i);
1810         if (!cur_stream->eos_sent) {
1811           GstBuffer *buf = gst_buffer_new_and_alloc (3 + 1);
1812           GST_DEBUG_OBJECT(submux, "sending EOS buffer to chain\n");
1813           GST_DEBUG_OBJECT (submux, "EOS. Pushing remaining text (if any)");
1814           GST_BUFFER_DATA (buf)[0] = 'e';
1815           GST_BUFFER_DATA (buf)[1] = 'o';
1816           GST_BUFFER_DATA (buf)[2] = 's';
1817           GST_BUFFER_DATA (buf)[3] = '\0';
1818           /* play it safe */
1819           GST_BUFFER_SIZE (buf) = 3;
1820           GST_BUFFER_FLAG_SET(buf,GST_BUFFER_FLAG_GAP);
1821           gst_submux_chain (g_list_nth_data(submux->sinkpad,i), buf);//
1822           cur_stream->eos_sent = TRUE;
1823         }
1824       }
1825       GST_OBJECT_UNLOCK (submux);
1826       gst_event_unref(event);
1827       ret = TRUE;
1828       break;
1829     }
1830     case GST_EVENT_NEWSEGMENT: {
1831       GstFormat format;
1832       gdouble rate,arate;
1833       gint64 start, stop, time;
1834       gboolean update;
1835       GST_OBJECT_LOCK (submux);
1836       if (!submux->pipeline_made) {
1837         if (!gst_submux_format_autodetect (submux)) {
1838           GST_ERROR_OBJECT (submux, "auto detect function failed");
1839           return FALSE;
1840         }
1841         if (!gst_calculate_number_languages(submux)) {
1842           GST_ERROR_OBJECT (submux, "failed to calculate number of languages");
1843           return FALSE;
1844         }
1845         if (!gst_submux_create_pipelines (submux, pad)) {
1846           GST_ERROR_OBJECT (submux, "failed to create pipelines");
1847           return FALSE;
1848         }
1849      }
1850
1851       if (!submux->priv->is_internal) {
1852         gst_event_unref(event);
1853         length = g_list_length(submux->streams);
1854         for (i = 0; i < length; i++) {
1855           GST_DEBUG_OBJECT (submux, "inside the handling of new_segment event");
1856           cur_stream = g_list_nth_data(submux->streams,i);
1857           GST_DEBUG_OBJECT (submux, "pushing newsegment event with %" GST_SEGMENT_FORMAT, &submux->segment);
1858           if (!cur_stream->pipe_struc.pipe) {
1859             GST_ERROR_OBJECT (submux, "pipeline is null");
1860             return FALSE;
1861           }
1862           cur_stream = g_list_nth_data(submux->streams,i);
1863           cur_stream->seek_ts = submux->segment.start;
1864           ret = gst_element_send_event (cur_stream->pipe_struc.pipe, gst_event_new_new_segment (FALSE,
1865                                         submux->segment.rate, submux->segment.format,
1866                                         submux->segment.start, submux->segment.stop, submux->segment.time));
1867           if (!ret){
1868             GST_ERROR_OBJECT(submux, "sending newsegment event to stream[%d] failed", i);
1869             break;
1870           }
1871         }
1872         submux->need_segment = TRUE;
1873       } else {
1874         length = g_list_length (submux->sinkpad);
1875         if (length ==  g_list_length (submux->streams) && submux->need_segment) {
1876           for (i = 0; i < length; i++) {
1877             GST_DEBUG_OBJECT (submux, "inside the handling of new_segment event");
1878             cur_stream = g_list_nth_data(submux->streams, i);
1879             if (cur_stream->need_segment) {
1880               gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, &start, &stop, &time);
1881               gst_segment_set_newsegment_full (&submux->segment, update, rate, arate, format, start, stop, time);
1882               GST_DEBUG_OBJECT (submux, "pushing newsegment event with %" GST_SEGMENT_FORMAT, &submux->segment);
1883               ret = TRUE;
1884               cur_stream->need_segment = FALSE;
1885             }
1886           }
1887           submux->need_segment = TRUE;
1888           gst_event_unref(event);
1889         }
1890       }
1891       GST_OBJECT_UNLOCK (submux);
1892       break;
1893     }
1894     case GST_EVENT_FLUSH_START: {
1895       length = g_list_length(submux->streams);
1896       if (!submux->priv->is_internal) {
1897         gst_event_unref(event);
1898         ret = gst_pad_event_default (pad, gst_event_new_flush_start ());
1899         for (i = 0;i < length;i++) {
1900           cur_stream = g_list_nth_data(submux->streams,i);
1901           cur_stream->flushing = TRUE;
1902           cur_stream->discont_came = FALSE;
1903           GST_DEBUG_OBJECT (submux, "making discont false");
1904           GST_DEBUG_OBJECT (submux, "making flushing TRUE");
1905           cur_stream->eos_came = FALSE;
1906           cur_stream->eos_sent = FALSE;
1907           GST_DEBUG_OBJECT (submux, "making eos_came and eos_sent FALSE");
1908         }
1909         for (i = 0; i < length; i++) {
1910           cur_stream = g_list_nth_data(submux->streams,i);
1911           ret= gst_element_send_event(cur_stream->pipe_struc.appsrc,gst_event_new_flush_start ());
1912           ret= gst_element_send_event(cur_stream->pipe_struc.appsrc,gst_event_new_flush_stop ());
1913           ret = gst_element_send_event(cur_stream->pipe_struc.appsrc,gst_event_new_eos ());
1914           GST_INFO_OBJECT(cur_stream,"flush stop and start  and eos is done with ret %d",ret);
1915           submux->flushing =TRUE;
1916           g_mutex_lock (cur_stream->queue_lock);
1917           g_cond_signal (cur_stream->queue_empty);
1918           g_mutex_unlock(cur_stream->queue_lock);
1919           cur_stream->flush_done = TRUE;
1920           GST_DEBUG_OBJECT (cur_stream, "signaling queue empty signal from flush start");
1921           ret = TRUE;
1922           GST_DEBUG_OBJECT (submux, "sending flush start event to stream[%d] success", i);
1923         }
1924
1925         if (!ret){
1926           GST_ERROR_OBJECT (submux, "sending flush start event to srcpad pad failed");
1927           break;
1928         }
1929
1930         if (submux && GST_PAD_TASK(submux->srcpad)) {
1931           GST_INFO_OBJECT (submux, "trying acquire srcpad lock");
1932           GST_PAD_STREAM_LOCK (submux->srcpad);
1933           GST_INFO_OBJECT (submux, "acquired stream lock");
1934           GST_PAD_STREAM_UNLOCK (submux->srcpad);
1935         }
1936         /*changes for new design*/
1937         for (i = 0;i < length;i++) {
1938           cur_stream = g_list_nth_data(submux->streams,i);
1939           gst_submux_stream_deinit(cur_stream,submux);
1940         }
1941         g_list_free(submux->streams);
1942         submux->streams = NULL;
1943         gst_submux_deinit_private_values (submux);
1944
1945         submux->stop_loop = FALSE;
1946         submux->need_segment = TRUE;
1947         submux->langlist_msg_posted = FALSE;
1948         GST_DEBUG_OBJECT (submux, "flush start successfully send to next element");
1949       } else {
1950         GST_DEBUG_OBJECT(submux, "flusht start in case of internal subtitle");
1951         gst_event_unref (event);
1952         submux->flushing = TRUE;
1953         checkpad = (GstPad *) g_list_nth_data (submux->sinkpad, length - 1);
1954         if (checkpad == pad) {
1955           ret = gst_pad_event_default (pad, gst_event_new_flush_start ());
1956           for (i = 0; i < length; i++) {
1957             cur_stream = g_list_nth_data(submux->streams, i);
1958             cur_stream->flushing = TRUE;
1959             GST_DEBUG_OBJECT (submux, "in case of internal making discont unchanged");
1960             GST_DEBUG_OBJECT (submux, "making flushing TRUE");
1961           }
1962           for (i = 0; i < length; i++) {
1963             cur_stream = g_list_nth_data(submux->streams, i);
1964             submux->flushing = TRUE;
1965             g_mutex_lock (cur_stream->queue_lock);
1966             while (!g_queue_is_empty (cur_stream->queue)) {
1967               buf = g_queue_pop_head (cur_stream->queue);
1968               gst_buffer_unref (buf);
1969             }
1970             GST_DEBUG_OBJECT (submux, "cleared stream cur_stream->queue");
1971             g_queue_clear (cur_stream->queue);
1972             g_cond_signal (cur_stream->queue_empty);
1973             g_mutex_unlock(cur_stream->queue_lock);
1974             GST_DEBUG_OBJECT (cur_stream, "signaling queue empty signal from flush start");
1975             cur_stream->eos_came = FALSE;
1976             cur_stream->eos_sent = FALSE;
1977             GST_DEBUG_OBJECT (submux, "making eos_came and eos_sent FALSE");
1978             ret = TRUE;
1979             GST_DEBUG_OBJECT (submux, "sending flush start event to stream[%d] success", i);
1980           }
1981           if (!ret){
1982             GST_ERROR_OBJECT (submux, "sending flush start event to srcpad pad failed");
1983             break;
1984           }
1985
1986           if (submux && GST_PAD_TASK (submux->srcpad)) {
1987             GST_INFO_OBJECT (submux, "trying acquire srcpad lock");
1988             GST_PAD_STREAM_LOCK (submux->srcpad);
1989             GST_INFO_OBJECT (submux, "acquired srcpad lock");
1990             GST_PAD_STREAM_UNLOCK (submux->srcpad);
1991           }
1992           GST_DEBUG_OBJECT(submux, "flush start successfully send to next element");
1993          }
1994       }
1995       break;
1996     }
1997     case GST_EVENT_FLUSH_STOP: {
1998       gst_event_unref(event);
1999       if (!submux->priv->is_internal) {
2000         guint idx = 0;
2001         submux->flushing = FALSE;
2002         ret = gst_pad_event_default (pad, gst_event_new_flush_stop ());
2003         if (!ret){
2004           GST_ERROR_OBJECT (submux, "sending flush-stop event to srcpad pad failed");
2005           break;
2006         }
2007         for (idx = 0; idx < submux->priv->stream_count; idx++) {
2008           submux->cur_buf_array[idx] = NULL;
2009         }
2010         GST_DEBUG_OBJECT (submux, "flush stop successfully send to next element");
2011       } else {
2012         length = g_list_length(submux->streams);
2013         GST_DEBUG_OBJECT (submux, "flusht stop in case of internal subtitle");
2014         checkpad = (GstPad *) g_list_nth_data (submux->sinkpad, length - 1);
2015         if (checkpad == pad) {
2016           for (i = 0; i < length; i++) {
2017             cur_stream = g_list_nth_data(submux->streams, i);
2018             cur_stream->need_segment = TRUE;
2019             submux->cur_buf_array[i] = NULL;
2020             submux->need_segment = TRUE;
2021             GST_DEBUG_OBJECT (submux, "making need_segment true");
2022             submux->flushing = FALSE;
2023             cur_stream->flushing = FALSE;
2024             GST_DEBUG_OBJECT (submux, "making flushing FALSE");
2025             ret = TRUE;
2026             GST_DEBUG_OBJECT (submux, "sending %s event to stream[%d] success", GST_EVENT_TYPE_NAME (event), i);
2027           }
2028           ret = gst_pad_event_default (pad, gst_event_new_flush_stop ());
2029           if (!ret){
2030             GST_ERROR_OBJECT (submux, "sending flush-stop event to srcpad pad failed");
2031             break;
2032           }
2033           GST_DEBUG_OBJECT (submux, "flush stop successfully send to next element");
2034         }
2035       }
2036       break;
2037     }
2038     default:{
2039       if (!submux->priv->is_internal) {
2040         ret = gst_pad_event_default (pad, event);
2041       } else {
2042         checkpad = (GstPad *) g_list_nth_data (submux->sinkpad, length - 1);
2043         if (checkpad == pad) {
2044           ret = gst_pad_event_default (pad, event);
2045         } else {
2046           ret = TRUE;
2047         }
2048       }
2049       if (!ret){
2050         GST_ERROR_OBJECT (submux, "sending %s event to srcpad pad failed", GST_EVENT_TYPE_NAME (event));
2051         break;
2052       }
2053       break;
2054     }
2055   }
2056   return ret;
2057 }
2058
2059 static gint gst_submux_buffer_list_sorting (gconstpointer a, gconstpointer b)
2060 {
2061   GstBuffer *buf_a = (GstBuffer *) a;
2062   GstBuffer *buf_b = (GstBuffer *) b;
2063   if (GST_BUFFER_TIMESTAMP(buf_a)>GST_BUFFER_TIMESTAMP(buf_b))
2064     return -1;
2065   else if(GST_BUFFER_TIMESTAMP(buf_a)<GST_BUFFER_TIMESTAMP(buf_b))
2066     return 1;
2067   else
2068     return 0;
2069 }
2070
2071 static gboolean
2072 gst_submux_is_muxing_needed (GstBuffer *ref_buffer, GstBuffer *cur_buf)
2073 {
2074   GstClockTime ref_start = GST_BUFFER_TIMESTAMP(ref_buffer);
2075   GstClockTime ref_stop = GST_BUFFER_TIMESTAMP(ref_buffer) + GST_BUFFER_DURATION(ref_buffer);
2076   GstClockTime start = GST_BUFFER_TIMESTAMP(cur_buf);
2077   GstClockTime stop = GST_BUFFER_TIMESTAMP(cur_buf) + GST_BUFFER_DURATION(cur_buf);
2078
2079   /* if we have a stop position and a valid start and start is bigger,
2080    * we're outside of the segment */
2081   if (G_UNLIKELY (ref_stop != -1 && start != -1 && start >= ref_stop))
2082     return FALSE;
2083
2084   /* if a stop position is given and is before the segment start,
2085    * we're outside of the segment. Special case is were start
2086    * and stop are equal to the segment start. In that case we
2087    * are inside the segment. */
2088   if (G_UNLIKELY (stop != -1 && (stop < ref_start || (start != stop && stop == ref_start))))
2089     return FALSE;
2090
2091   return TRUE;
2092 }
2093
2094 /* This function do the actual muxing of buffer on the basis of timestamps */
2095 static GList*
2096 gst_submux_muxing (Gstsubmux *submux)
2097 {
2098   GstClockTime min_timestamp = 0;
2099   int min_stream = 0;
2100   int overlap = 0;
2101   GstClockTime next_min_time = 0;
2102   int idx = 0;
2103   GList *push_list = NULL;
2104
2105   /* Finding least timestamp of all streams and their stream ID */
2106   for (idx = 0; idx < submux->priv->stream_count; idx++) {
2107     if(submux->cur_buf_array[idx] && !min_timestamp) {
2108       min_timestamp = GST_BUFFER_TIMESTAMP(submux->cur_buf_array[idx]);
2109       min_stream = idx;
2110     }
2111     if(submux->cur_buf_array[idx] && (GST_BUFFER_TIMESTAMP(submux->cur_buf_array[idx]) < min_timestamp)) {
2112       min_timestamp = GST_BUFFER_TIMESTAMP(submux->cur_buf_array[idx]);
2113       min_stream = idx;
2114     }
2115   }
2116
2117   GST_DEBUG_OBJECT (submux, "Identified least timestamp: %"GST_TIME_FORMAT" for stream: %d",
2118     GST_TIME_ARGS(min_timestamp), min_stream);
2119
2120   /* Finding overlap buffers and next least timestamp */
2121   for (idx = 0; idx < submux->priv->stream_count; idx++) {
2122     if(submux->cur_buf_array[idx] && (idx != min_stream) && (!next_min_time)) {
2123       next_min_time = GST_BUFFER_TIMESTAMP(submux->cur_buf_array[idx]);
2124     }
2125     if(submux->cur_buf_array[idx] && (idx != min_stream)) {
2126       if(gst_submux_is_muxing_needed (submux->cur_buf_array[min_stream], submux->cur_buf_array[idx])) {
2127         overlap = overlap | (1<<idx);      // bit setting of overlap variable with stream ID
2128         GST_DEBUG_OBJECT (submux, "overlapped with stream = %d", idx);
2129         if(GST_BUFFER_TIMESTAMP(submux->cur_buf_array[idx]) < next_min_time)
2130           next_min_time = GST_BUFFER_TIMESTAMP(submux->cur_buf_array[idx]);
2131       }
2132     }
2133   }
2134
2135   GST_DEBUG_OBJECT (submux, "Identified overlap: %d next least timestamp: %"GST_TIME_FORMAT" ", overlap, GST_TIME_ARGS(next_min_time));
2136
2137   /* If no overlap send buffer as it is */
2138   if(!overlap) {
2139      GST_DEBUG_OBJECT (submux, "pushing string: %s....", (gchar*)GST_BUFFER_DATA(submux->cur_buf_array[min_stream]));
2140      push_list = g_list_append(push_list, submux->cur_buf_array[min_stream]);
2141      GST_DEBUG_OBJECT (submux, "No overlap found pushing buffer of ts = %"GST_TIME_FORMAT", dur = %"GST_TIME_FORMAT,
2142               GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(submux->cur_buf_array[min_stream])), GST_TIME_ARGS(GST_BUFFER_DURATION(submux->cur_buf_array[min_stream])));
2143      submux->cur_buf_array[min_stream] = NULL;
2144   } else {
2145     GstBuffer *push_buf = NULL;
2146     GstClockTime stop_time = 0;
2147     int stop_idx = 0;
2148     GstBuffer *overlap_buf = NULL;
2149     guint overlap_buf_length = 0;
2150     GString *overlap_text = NULL;
2151     gchar *text = NULL;
2152
2153     if(next_min_time > GST_BUFFER_TIMESTAMP(submux->cur_buf_array[min_stream])) {
2154     GST_DEBUG_OBJECT (submux, "Before duration change ts = %"GST_TIME_FORMAT", dur = %"GST_TIME_FORMAT,
2155              GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(submux->cur_buf_array[min_stream])), GST_TIME_ARGS(GST_BUFFER_DURATION(submux->cur_buf_array[min_stream])));
2156       push_buf = gst_buffer_copy (submux->cur_buf_array[min_stream]);
2157       push_buf->duration = next_min_time - GST_BUFFER_TIMESTAMP(submux->cur_buf_array[min_stream]);
2158       GST_BUFFER_TIMESTAMP(submux->cur_buf_array[min_stream]) = next_min_time;
2159       GST_BUFFER_DURATION(submux->cur_buf_array[min_stream]) -= push_buf->duration;
2160       GST_DEBUG_OBJECT (submux, "After duration change ts = %"GST_TIME_FORMAT", dur = %"GST_TIME_FORMAT,
2161              GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(submux->cur_buf_array[min_stream])), GST_TIME_ARGS(GST_BUFFER_DURATION(submux->cur_buf_array[min_stream])));
2162
2163       min_timestamp = next_min_time;
2164       GST_INFO_OBJECT (submux, "pushing string: %s...", (gchar*)GST_BUFFER_DATA(push_buf));
2165       push_list = g_list_append(push_list, push_buf);
2166       GST_DEBUG_OBJECT (submux, "Overlap found pushing initial partial buffer of ts = %"GST_TIME_FORMAT", dur = %"GST_TIME_FORMAT,
2167               GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(push_buf)), GST_TIME_ARGS(GST_BUFFER_DURATION(push_buf)));
2168     }
2169
2170     for (idx = 0; idx < submux->priv->stream_count; idx++) {
2171       if(submux->cur_buf_array[idx] && !stop_time) {
2172         stop_time = GST_BUFFER_TIMESTAMP(submux->cur_buf_array[idx]) + GST_BUFFER_DURATION(submux->cur_buf_array[idx]);
2173         stop_idx = idx;
2174       }
2175       if(submux->cur_buf_array[idx] &&
2176           ((GST_BUFFER_TIMESTAMP(submux->cur_buf_array[idx])+ GST_BUFFER_DURATION(submux->cur_buf_array[idx])) < stop_time)) {
2177         stop_time = GST_BUFFER_TIMESTAMP(submux->cur_buf_array[idx]) + GST_BUFFER_DURATION(submux->cur_buf_array[idx]);
2178         stop_idx = idx;
2179       }
2180     }
2181     GST_DEBUG_OBJECT (submux, "Identified least stop timestamp: %"GST_TIME_FORMAT" for stream: %d",
2182             GST_TIME_ARGS(stop_time), stop_idx);
2183
2184     overlap_text = g_string_new ("");
2185     overlap = overlap | (1<<min_stream);
2186     for (idx = 0; idx < submux->priv->stream_count; idx++) {
2187       int finder = 1<<idx;
2188       if(overlap & finder) {
2189         GST_DEBUG_OBJECT (submux, "append string: %s....", (gchar*)GST_BUFFER_DATA(submux->cur_buf_array[idx]));
2190         g_string_append (overlap_text, (gchar*)GST_BUFFER_DATA (submux->cur_buf_array[idx]));
2191         GST_BUFFER_TIMESTAMP(submux->cur_buf_array[idx])+= (stop_time - min_timestamp);
2192         GST_BUFFER_DURATION(submux->cur_buf_array[idx])-= (stop_time - min_timestamp);
2193         if(overlap > (1<<(idx+1))) g_string_append_c (overlap_text, '\n');
2194       }
2195     }
2196     text = g_string_free (overlap_text, FALSE);
2197     overlap_buf_length = strlen(text);
2198     overlap_buf = gst_buffer_new_and_alloc (overlap_buf_length + 1);
2199     memcpy (GST_BUFFER_DATA (overlap_buf), text, overlap_buf_length + 1);
2200     overlap_buf->timestamp = min_timestamp;
2201     overlap_buf->duration = stop_time - min_timestamp;
2202     g_free (text);
2203     text = NULL;
2204     submux->cur_buf_array[stop_idx] = NULL;
2205     GST_DEBUG_OBJECT (submux, "pushing string: %s....", (gchar*)GST_BUFFER_DATA(overlap_buf));
2206     push_list = g_list_append(push_list, overlap_buf);
2207     GST_DEBUG_OBJECT (submux, "Overlap found pushing merged buffer of ts = %"GST_TIME_FORMAT", dur = %"GST_TIME_FORMAT,
2208           GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(overlap_buf)), GST_TIME_ARGS(GST_BUFFER_DURATION(overlap_buf)));
2209     GST_DEBUG_OBJECT (submux, "request for new buffer for stream %d", stop_idx);
2210     for (idx = 0; idx < submux->priv->stream_count; idx++) {
2211       if(submux->cur_buf_array[idx] &&
2212            ((GST_BUFFER_TIMESTAMP(submux->cur_buf_array[idx])+ GST_BUFFER_DURATION(submux->cur_buf_array[idx])) <= stop_time)) {
2213         submux->cur_buf_array[idx] = NULL;
2214         GST_DEBUG_OBJECT (submux, "request for new buffer for stream %d", idx);
2215       }
2216     }
2217   }
2218   return push_list;
2219 }
2220
2221 static void gst_submux_loop (Gstsubmux *submux)
2222 {
2223   guint length = 0;
2224   GstBuffer *src_buffer = NULL;
2225   GstBuffer *temp_buffer = NULL;
2226   GstBuffer *check_buffer = NULL;
2227   GstSubmuxStream *cur_stream = NULL;
2228   GstSubmuxStream *check_stream = NULL;
2229   gboolean match = FALSE;
2230   GstFlowReturn fret = GST_FLOW_OK;
2231   GstClockTime cur_duration = 0 ;
2232   GstClockTime cur_ts = 0;
2233   gboolean eos = TRUE;
2234   guint i= 0,k = 0;
2235   GList *push_list = NULL;
2236   GstBuffer *push_buf = NULL;
2237
2238   if (!submux->priv->first_buffer) {
2239     GST_INFO_OBJECT (submux, "exiting from lopp");
2240     return;
2241   }
2242
2243   if (submux->priv->parser_type == GST_SUB_PARSE_FORMAT_SAMI) {
2244     length = g_list_length (submux->priv->lang_list);
2245   } else {
2246     length = submux->sinkpads_count;
2247   }
2248
2249   gboolean made = FALSE;
2250  // length = 2;
2251
2252   for (i = 0; i < length; i++) {
2253
2254 re_pop:
2255     cur_stream = g_list_nth_data (submux->streams, i);
2256     GST_DEBUG_OBJECT (submux, "Before lock acquired in loop stream[%d]", i);
2257     g_mutex_lock (cur_stream->queue_lock);
2258     GST_DEBUG_OBJECT (submux, "Lock acquired in loop stream[%d]", i);
2259
2260     if (g_queue_is_empty (cur_stream->queue) && !submux->flushing) {
2261       GST_DEBUG_OBJECT (submux, "Queue is empty, waiting for the condition signal stream[%d]", i);
2262       g_cond_wait (cur_stream->queue_empty, cur_stream->queue_lock);
2263     }
2264     GST_DEBUG_OBJECT (submux, "Got the queue condition signal stream[%d]", i);
2265
2266     if (submux->flushing || submux->stop_loop) {
2267       GST_DEBUG_OBJECT (submux, "Flushing going on in loop");
2268       GST_DEBUG_OBJECT (submux, "Got the condition signal");
2269       g_mutex_unlock (cur_stream->queue_lock);
2270       goto error;
2271     }
2272
2273     check_buffer = g_queue_peek_head (cur_stream->queue);
2274     if (!strcmp ((const char*)GST_BUFFER_DATA (check_buffer), "eos")){
2275       cur_stream->eos_came = TRUE;
2276       GST_DEBUG_OBJECT (submux, "Eos recieved for stream");
2277     }
2278     for (k = 0; k < length; k++)  {
2279       check_stream = g_list_nth_data(submux->streams, k);
2280       if (!check_stream->eos_came) {
2281         eos = FALSE;
2282         break;
2283       } else {
2284         eos = TRUE;
2285       }
2286     }
2287     if (eos) {
2288       GST_DEBUG_OBJECT (submux, "Sending EOS to submux srcpad");
2289       gst_pad_push_event(submux->srcpad, gst_event_new_eos ());
2290       g_mutex_unlock (cur_stream->queue_lock);
2291       goto eos_sent;
2292     }
2293
2294     if (!cur_stream->eos_came && (submux->priv->parser_type == GST_SUB_PARSE_FORMAT_SAMI ||
2295                                   submux->priv->is_internal)) {
2296       GstLangStruct *lang = NULL;
2297       if (submux->priv->lang_list) {
2298         if (submux->cur_buf_array[i] == NULL) {
2299           check_buffer = g_queue_pop_head (cur_stream->queue);
2300           lang = g_list_nth_data(submux->priv->lang_list, i);
2301           if (!lang->active) {
2302             if(check_buffer) {
2303               gst_buffer_unref(check_buffer);
2304               check_buffer = NULL;
2305               GST_DEBUG_OBJECT (submux, "unreffing the non-active stream[%d] buffer", i);
2306             }
2307             submux->cur_buf_array[i] = NULL;
2308             g_mutex_unlock (cur_stream->queue_lock);
2309             GST_DEBUG_OBJECT(submux,"rejecting not selected language");
2310             continue;
2311           } else {
2312             if (!check_buffer) {
2313               GST_WARNING_OBJECT (submux, "checkbuffer null.. repop");
2314               g_mutex_unlock (cur_stream->queue_lock);
2315               goto re_pop;
2316             }
2317             if (!GST_BUFFER_DURATION(check_buffer)) {
2318               GST_WARNING_OBJECT (submux, "duration of buffer is zero..re-pop");
2319               gst_buffer_unref (check_buffer);
2320               g_mutex_unlock (cur_stream->queue_lock);
2321               goto re_pop;
2322             }
2323             submux->cur_buf_array[i] = check_buffer;
2324             GST_DEBUG_OBJECT (submux, "consuming active stream [%d] buffer : ts = %"GST_TIME_FORMAT"and dur = %"GST_TIME_FORMAT,
2325               i, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (check_buffer)), GST_TIME_ARGS(GST_BUFFER_DURATION (check_buffer)));
2326           }
2327         }
2328       } else {
2329         g_mutex_unlock (cur_stream->queue_lock);
2330         GST_DEBUG_OBJECT(submux,"Coming to Else case lang submux->priv->lang_list %x ",submux->priv->lang_list);
2331         continue;
2332       }
2333     } else if (!cur_stream->eos_came) {
2334       /* External subtitle format other than smi */
2335       if (submux->sinkpad) {
2336         if (submux->cur_buf_array[i] == NULL) {
2337           check_buffer = g_queue_pop_head (cur_stream->queue);
2338           if (!check_buffer) {
2339             GST_WARNING_OBJECT (submux, "checkbuffer null.. repop");
2340             g_mutex_unlock (cur_stream->queue_lock);
2341             goto re_pop;
2342           }
2343           if (!GST_BUFFER_DURATION (check_buffer)) {
2344             GST_WARNING_OBJECT (submux, "duration of buffer is zero..re-pop");
2345             gst_buffer_unref (check_buffer);
2346             g_mutex_unlock (cur_stream->queue_lock);
2347             goto re_pop;
2348           }
2349           submux->cur_buf_array[i] = check_buffer;
2350           GST_DEBUG_OBJECT (submux, "consuming active stream [%d] buffer : ts = %"GST_TIME_FORMAT"and dur = %"GST_TIME_FORMAT,
2351             i, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (check_buffer)), GST_TIME_ARGS(GST_BUFFER_DURATION (check_buffer)));
2352         }
2353       } else {
2354         g_mutex_unlock (cur_stream->queue_lock);
2355         GST_DEBUG_OBJECT(submux,"Coming to Else case submux->sinkpad %x ",submux->sinkpad);
2356         continue;
2357       }
2358     } else {
2359       GST_DEBUG_OBJECT (submux, "already received EOS on this stream[%d] and cur_buf_array[idx] = NULL", i);
2360       submux->cur_buf_array[i] = NULL;
2361     }
2362
2363     g_mutex_unlock (cur_stream->queue_lock);
2364     GST_DEBUG_OBJECT (submux, "After unlocking in loop and signal queue full");
2365   }
2366
2367   push_list = gst_submux_muxing (submux);
2368   if (push_list) {
2369     guint idx = 0;
2370     GST_LOG_OBJECT (submux, "length of push list = %d", g_list_length (push_list));
2371
2372     for (idx = 0; idx < g_list_length (push_list); idx++) {
2373       push_buf = g_list_nth_data (push_list, idx);
2374
2375       if (push_buf) {
2376         GST_DEBUG_OBJECT (submux, "pushing buffer : ts = %"GST_TIME_FORMAT", "
2377             "dur = %"GST_TIME_FORMAT" and data %s ...",
2378         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (push_buf)),
2379         GST_TIME_ARGS (GST_BUFFER_DURATION (push_buf)), (gchar*)GST_BUFFER_DATA (push_buf));
2380
2381         fret = gst_pad_push (submux->srcpad, push_buf);
2382         if (fret != GST_FLOW_OK) {
2383           GST_ERROR_OBJECT (submux, "failed to push buffer. reason : %s", gst_flow_get_name (fret));
2384           /* clean any left buffers in push_list */
2385           idx++;
2386           for (; idx < g_list_length (push_list); idx++) {
2387             push_buf = g_list_nth_data (push_list, idx);
2388             gst_buffer_unref (push_buf);
2389           }
2390           g_list_free (push_list);
2391           goto error;
2392         }
2393       }
2394     }
2395
2396     g_list_free (push_list);
2397   }
2398
2399   GST_DEBUG_OBJECT (submux, "Exiting from lopp in last");
2400
2401   return;
2402
2403 eos_sent:
2404 error:
2405   GST_WARNING_OBJECT (submux->srcpad, "Pausing the push task...");
2406   if (fret < GST_FLOW_UNEXPECTED) {
2407     GST_ERROR_OBJECT (submux, "Crtical error in push loop....");
2408     GST_ELEMENT_ERROR (submux, CORE, PAD, ("failed to push. reason - %s", gst_flow_get_name (fret)), (NULL));
2409   }
2410   gst_pad_pause_task (submux->srcpad);
2411   GST_DEBUG_OBJECT (submux, "Exiting from lopp in last");
2412   return;
2413 }
2414
2415 ////////////////////////////////////////////////////////
2416 //        Plugin Utility Functions                    //
2417 ////////////////////////////////////////////////////////
2418 /*
2419 **
2420 **  Description    : De-Initializing the submux private structure
2421 **  Params        : (1) submux instance
2422 **  return        : TRUE
2423 **  Comments    :
2424 **
2425 */
2426 static gboolean
2427 gst_submux_deinit_private_values(Gstsubmux *submux)
2428 {
2429   guint idx = 0;
2430   GST_DEBUG_OBJECT (submux, "deinit priv values");
2431
2432   submux->priv->first_buffer = FALSE;
2433   submux->priv->parser_type = 0;
2434   if (submux->priv->lang_list && !submux->priv->is_internal) {
2435     g_list_free (submux->priv->lang_list);
2436     submux->priv->lang_list = NULL;
2437   }
2438   for (idx = 0; idx < submux->priv->stream_count; idx++) {
2439     submux->cur_buf_array[idx] = NULL;
2440   }
2441   if (submux->cur_buf_array) {
2442     g_free (submux->cur_buf_array);
2443     submux->cur_buf_array = NULL;
2444   }
2445
2446   submux->priv->is_internal = FALSE;
2447   submux->priv->stream_count = 0;
2448
2449   return TRUE;
2450 }
2451
2452 static gboolean
2453 gst_submux_plugin_init (GstPlugin * plugin)
2454 {
2455   return gst_element_register (plugin, "submux", GST_RANK_PRIMARY, GST_TYPE_SUBMUX);
2456 }
2457
2458 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,GST_VERSION_MINOR,"submux","submux",gst_submux_plugin_init,"0.10.36","Proprietary","Samsung Electronics Co","http://www.samsung.com")