tizen 2.3.1 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     if (attr_value) {
789       new->language_code = g_strdup(attr_value);
790     }
791     if (attr_name) {
792       new->language_key = g_strdup(attr_name);
793     }
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] = g_strdup (tempKey);
1196           langKey_length[keyCount]=keyLength;
1197           keyCount++;
1198         }
1199         lang_found =FALSE;
1200         keyLength =0;
1201         if(tempKey){
1202           g_free(tempKey);
1203           tempKey=NULL;
1204         }
1205       } else {
1206         keyLength =0;
1207         lang_found =FALSE;
1208         break;
1209       }
1210       con_temp+=6;
1211       GST_DEBUG_OBJECT (self, " ..increment con_temp %s",con_temp);
1212     }
1213   }
1214   GST_DEBUG_OBJECT (self, " At end keyCount no of langs is %d ",keyCount);
1215   for(i=0;i<keyCount;i++) {
1216     if(langkey[i]) {
1217       GstLangStruct *new = g_new0 (GstLangStruct, 1);
1218       GST_DEBUG_OBJECT (self, "Adding ign case to the langKey keyCount %d and lang %s ",i, langkey[i]);
1219       new->language_code = (gchar*)malloc (3);
1220       if(!(new->language_code)){
1221         GST_DEBUG_OBJECT (self, " .Error 2");
1222         goto error;
1223       }
1224       gchar *attr_val=new->language_code ;
1225       strncpy (attr_val, "un", 2);
1226       attr_val[2]='\0';
1227
1228       new->language_key = g_strdup(langKey_length[i]);
1229       self->priv->lang_list = g_list_append (self->priv->lang_list, new);
1230       GST_DEBUG_OBJECT (self, " new...Successfull");
1231       g_free(langkey[i]);
1232     }
1233   }
1234   if (fp) {
1235     g_free(temp_path);
1236     g_free(file_path_type);
1237     fclose(fp);
1238     fp = NULL;
1239   }
1240   return TRUE;
1241 error:
1242   GST_DEBUG_OBJECT (self, " In Error");
1243   if (fp) {
1244     g_free(temp_path);
1245     g_free(file_path_type);
1246     fclose(fp);
1247     fp = NULL;
1248   }
1249   return FALSE;
1250 }
1251
1252 gboolean
1253 validate_langlist_body(GList * lang_list, Gstsubmux * self){
1254   gchar * file_path_type = NULL;
1255   gchar * file_path = NULL;
1256   gchar   line[1025];
1257   FILE  * fp = NULL;
1258   guint i = 0, found_count = 0,k = 0;
1259   const guint list_len = g_list_length(lang_list);
1260   gboolean counter[MAX_LANGUAGE];
1261   GstPad  *sinkpad = NULL;
1262   struct LangStruct
1263   {
1264       gchar *language_code;
1265       gchar *language_key;
1266   } * lang;
1267   sinkpad = (GstPad *) g_list_nth_data(self->sinkpad, 0);
1268   GstQuery *cquery;
1269   GstStructure *structure;
1270   const GValue *value;
1271   structure = gst_structure_new ("FileSrcURI", "file-uri", G_TYPE_STRING, NULL, NULL);
1272
1273   cquery = gst_query_new_application (GST_QUERY_CUSTOM, structure);
1274
1275   if (!gst_pad_peer_query (sinkpad, cquery)) {
1276     GST_ERROR_OBJECT (self, "Failed to query SMI file path");
1277     gst_query_unref (cquery);
1278     return FALSE;
1279   }
1280   structure = gst_query_get_structure (cquery);
1281   value = gst_structure_get_value (structure, "file-uri");
1282   file_path = g_strdup (g_value_get_string (value));
1283
1284   if (file_path == NULL){
1285     GST_ERROR_OBJECT (self, "Could not parse the SMI file path");
1286     gst_query_unref (cquery);
1287     return FALSE;
1288   }
1289
1290   if (self->external_filepath == NULL) {
1291     self->external_filepath = file_path;
1292   }
1293   else {
1294     if (!g_strcmp0 (file_path, self->external_filepath)) {
1295       GST_INFO_OBJECT (self, "Same external file URI, no need to parse again");
1296       gst_query_unref (cquery);
1297       g_free(file_path);
1298       return TRUE;
1299     }
1300     else {
1301       g_free (self->external_filepath);
1302       self->external_filepath = NULL;
1303       self->external_filepath = file_path;
1304     }
1305   }
1306
1307   gst_query_unref (cquery);
1308   GST_INFO_OBJECT (self, "File path comes as %s", file_path);
1309
1310   file_path_type = g_strndup ((gchar *) file_path, 4);
1311   GST_INFO_OBJECT (self, "Received file path by query = %s, %s", file_path, file_path_type);
1312   if (!g_strcmp0(file_path_type, "file")){
1313     file_path += 7;
1314     GST_INFO_OBJECT (self, "File path comes as %s", file_path);
1315
1316     fp = fopen (file_path, "r");
1317     if (!fp){
1318       GST_ERROR_OBJECT (self, "Failed to open file");
1319       g_free(file_path_type);
1320       return FALSE;
1321     }
1322
1323     for (i = 0; i < list_len; i++){
1324       counter[i] = FALSE;
1325     }
1326
1327     while (!feof (fp) && found_count < list_len){
1328       GError *err = NULL;
1329       gsize * consumed = NULL;
1330       gint gap = 0;
1331       guint charCount = 0;
1332       gchar* result = NULL;
1333       gchar* temp = NULL;
1334       gchar* temp_lang = NULL;
1335       gchar* con_temp_end = NULL;
1336       gchar* con_temp_start = NULL;
1337       gchar* new_key = NULL;
1338       gint new_key_length = 0;
1339       gboolean new_key_found = FALSE;
1340       gchar * temp1 = NULL;
1341       gchar *con_temp_lang = NULL;
1342       gchar *con_temp = NULL;
1343       gboolean conversion = TRUE;
1344       charCount = fread (line, sizeof(char), 1024, fp);
1345       line[charCount] = '\0';
1346       if (!charCount) {
1347         GST_WARNING_OBJECT (self, "fread returned zero bytes");
1348         continue;
1349       }
1350
1351       GST_DEBUG_OBJECT (self, "value of detected encoding is %s and self encoding is %s",
1352                              self->detected_encoding,self->encoding);
1353       if (self->detected_encoding && strcmp (self->detected_encoding, "UTF-8") && conversion){
1354         result = convert_to_utf8 (line, charCount, self->detected_encoding, consumed, &err, self);
1355       }
1356       if (result == NULL) {
1357          result = line;
1358          conversion =  FALSE;
1359       }
1360       con_temp = g_utf8_strdown (result, strlen (result));
1361       temp = con_temp;
1362       while (con_temp) {
1363         con_temp = g_strstr_len(con_temp, strlen (con_temp), "class=");
1364         if (con_temp) {
1365           temp1 = g_strstr_len(con_temp+1, strlen (con_temp), "class=");
1366         }
1367         if (temp1 && con_temp){
1368           gap = strlen (con_temp) - strlen (temp1);
1369         } else if (con_temp) {
1370           gap = strlen (con_temp);
1371         } else {
1372           continue;
1373         }
1374         if (con_temp){
1375           for (i = 0; i < list_len; i++){
1376             if (counter[i] == TRUE) {
1377               con_temp = con_temp + 1;
1378               continue;
1379             }
1380             lang = (struct LangStruct *) g_list_nth_data (lang_list, i);
1381             if (lang) {
1382               temp_lang = g_strdup(lang->language_key);
1383               con_temp_lang = g_utf8_strdown (temp_lang, strlen (temp_lang));
1384               if (g_strstr_len (con_temp, gap, con_temp_lang)) {
1385                 found_count++;
1386                 counter[i] = TRUE;
1387                 GST_INFO_OBJECT (self, "Valid Language in list : [%s]", lang->language_key);
1388                 con_temp = con_temp + 1;
1389               }
1390 /* Fix Me: Cases where there is no body for a specific language
1391  * inside a single language .smi file */
1392 #if 0
1393               else {
1394                 con_temp_start = con_temp;
1395                 con_temp_end = con_temp;
1396                 while(con_temp_end) {
1397                   if(*con_temp_end == '=') {
1398                     con_temp_start = con_temp_end+1;
1399                     con_temp_end++;
1400                   }else if(*con_temp_end == '>') {
1401                     con_temp_end = con_temp_end;
1402                     new_key_found = TRUE;
1403                     break;
1404                   }else {
1405                     con_temp_end++;
1406                     new_key_found = FALSE;
1407                   }
1408                 }
1409                 if(new_key_found) {
1410                   new_key_length = strlen(con_temp_start)-strlen(con_temp_end);
1411                   new_key = g_malloc(new_key_length +1);
1412                   for(k=0;k<new_key_length;k++){
1413                     *(new_key+k)=*(con_temp_start+k);
1414                   }
1415                   *(new_key+new_key_length)='\0';
1416                   GST_INFO("new lang key is %s",lang->language_key);
1417                   g_free(new_key);
1418                   found_count++;
1419                   counter[i] = TRUE;
1420                   con_temp = con_temp + 1;
1421                 }
1422               }
1423 #endif
1424               g_free (temp_lang);
1425               g_free (con_temp_lang);
1426             }
1427           }
1428         }
1429       }
1430       if (conversion)
1431         g_free (result);
1432       if (temp)
1433         g_free (temp);
1434     }
1435
1436     if (found_count < list_len) {
1437       for (i = 0; i < list_len; i++) {
1438         if (counter[i] == FALSE)
1439           lang_list = g_list_delete_link (lang_list, g_list_nth (lang_list, i));
1440       }
1441     }
1442   } else {
1443     GST_ERROR_OBJECT (self, "File is not a local file");
1444     g_free(file_path_type);
1445     return FALSE;
1446   }
1447   fclose (fp);
1448   g_free(file_path_type);
1449   return TRUE;
1450 }
1451
1452 /*
1453 **
1454 **  Description    : Chain function used to push the subtitle buffer to internal pipelines of submux element
1455 **  Params        : (1) sink pad on which buffer is arriving (2) the buffer itself
1456 **  return        : GST_FLOW_OK on successfully pushing subtitle buffer to next element
1457 **
1458 */
1459 static GstFlowReturn
1460 gst_submux_chain(GstPad *pad, GstBuffer *buffer)
1461 {
1462   guint length = 0;
1463   guint i=0;
1464   GstPad *checkpad = NULL;
1465   Gstsubmux *submux = GST_SUBMUX(GST_PAD_PARENT(pad));
1466   gboolean ret = FALSE;
1467   GstFlowReturn fret = GST_FLOW_ERROR;
1468   GstSubmuxStream *stream = NULL;
1469   GstMessage *m = NULL;
1470
1471   if (GST_BUFFER_IS_DISCONT (buffer))
1472     GST_DEBUG_OBJECT(submux, "Discont buffer came in chain function");
1473   GST_DEBUG_OBJECT (submux, "^^^^^entering in chain^^^^^^");
1474   if (!submux->priv->is_internal) {
1475     if (!submux->priv->first_buffer) {
1476       submux->detected_encoding = detect_encoding ((gchar*)GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
1477     }
1478     if (!submux->langlist_msg_posted && submux->priv->lang_list) {
1479       if (!validate_langlist_body (submux->priv->lang_list, submux)){
1480         GST_WARNING_OBJECT(submux, "Error occured while validating language list. Posting without validation");
1481       }
1482       if (submux->priv->lang_list) {
1483         GList* temp_list_to_post = NULL;
1484         temp_list_to_post = g_list_copy (submux->priv->lang_list);
1485         m = gst_message_new_element (GST_OBJECT_CAST (submux), gst_structure_new("Ext_Sub_Language_List",
1486                                     "lang_list", G_TYPE_POINTER, temp_list_to_post, NULL));
1487
1488         gst_element_post_message (GST_ELEMENT_CAST (submux), m);
1489         submux->langlist_msg_posted = TRUE;
1490       }
1491       GST_DEBUG_OBJECT (submux, "LANGLIST POSTED");
1492     }
1493     if (submux->need_segment) {
1494       ret = gst_pad_push_event (submux->srcpad, gst_event_new_new_segment (FALSE, submux->segment.rate,
1495                                 submux->segment.format, submux->segment.start, submux->segment.stop,
1496                                 submux->segment.time));
1497       GST_DEBUG_OBJECT (submux, "pushing newsegment event with %" GST_SEGMENT_FORMAT, &submux->segment);
1498       if (!ret) {
1499         GST_ERROR_OBJECT (submux, "Sending newsegment to next element is failed");
1500         return GST_FLOW_ERROR;
1501       }
1502       GST_DEBUG_OBJECT (submux, "Starting the loop again");
1503       if (!gst_pad_start_task (submux->srcpad, (GstTaskFunction) gst_submux_loop, submux)) {
1504          GST_ERROR_OBJECT (submux, "failed to start srcpad task...");
1505          GST_ELEMENT_ERROR (submux, RESOURCE, FAILED, ("failed to create  push loop"), (NULL));
1506          return GST_FLOW_ERROR;
1507       }
1508       submux->need_segment = FALSE;
1509     }
1510     GST_DEBUG_OBJECT (submux, "before pushing buffer to each apprsrc");
1511     if (!submux->priv->lang_list && submux->priv->parser_type == GST_SUB_PARSE_FORMAT_SAMI) {
1512       GST_ERROR_OBJECT (submux, "lang list is not there");
1513       return GST_FLOW_ERROR;
1514     }
1515     if (submux->priv->parser_type == GST_SUB_PARSE_FORMAT_SAMI)
1516       length = g_list_length (submux->priv->lang_list);
1517     else
1518       length = 1;
1519
1520     for (i = 0; i < length; i++) {
1521       stream = g_list_nth_data(submux->streams, i);
1522       if ((submux->priv->parser_type == GST_SUB_PARSE_FORMAT_SAMI) && !submux->priv->first_buffer){
1523         GstLangStruct *lang = g_list_nth_data(submux->priv->lang_list, i);
1524         if(submux->msl_streams){
1525            GstLangStruct *lang1 = g_list_nth_data(submux->msl_streams, i);
1526            lang->active = lang1->active;
1527         } else {
1528           if (i == 0)
1529             lang->active = TRUE;
1530           else
1531             lang->active = FALSE;
1532         }
1533       }
1534       GST_DEBUG_OBJECT (submux, "making stream need segment false");
1535       stream->need_segment = FALSE;
1536     }
1537
1538     for (i = 0; i < length; i++) {
1539       stream = g_list_nth_data(submux->streams, i);
1540       if (!stream){
1541         GST_ERROR_OBJECT (submux, "stream not found");
1542         return GST_FLOW_ERROR;
1543       }
1544
1545       if (!stream->pipe_struc.appsrc) {
1546         GST_ERROR_OBJECT (submux, "appsrc not found");
1547         return GST_FLOW_ERROR;
1548       }
1549       if (i < (length - 1))
1550         gst_buffer_ref (buffer);
1551
1552       fret = gst_app_src_push_buffer ((GstAppSrc*)stream->pipe_struc.appsrc, buffer);
1553
1554       if (fret != GST_FLOW_OK) {
1555         GST_ERROR_OBJECT (submux, "push buffer failed with fret is %d", fret);
1556         return fret;
1557       }
1558       GST_DEBUG_OBJECT (submux, "pad_push successfull to appsrc %p buffer", buffer);
1559     }
1560   } else {
1561     length = submux->sinkpads_count;
1562     checkpad = (GstPad *) g_list_nth_data (submux->sinkpad, 0);
1563     if (checkpad == pad) {
1564       if (submux->need_segment) {
1565         ret = gst_pad_push_event (submux->srcpad, gst_event_new_new_segment (FALSE, submux->segment.rate,
1566                                   submux->segment.format, submux->segment.start, submux->segment.stop,
1567                                   submux->segment.time));
1568         GST_DEBUG_OBJECT (submux, "pushing newsegment event with %" GST_SEGMENT_FORMAT, &submux->segment);
1569         if (!ret) {
1570           GST_ERROR_OBJECT (submux, "Sending newsegment to next element is failed");
1571           return GST_FLOW_ERROR;
1572         }
1573         GST_DEBUG_OBJECT (submux, "Starting the loop again");
1574         if (!gst_pad_start_task (submux->srcpad, (GstTaskFunction) gst_submux_loop, submux)) {
1575           GST_ERROR_OBJECT (submux, "failed to start srcpad task...");
1576           GST_ELEMENT_ERROR (submux, RESOURCE, FAILED, ("failed to create  push loop"), (NULL));
1577           return GST_FLOW_ERROR;
1578         }
1579         submux->need_segment = FALSE;
1580       }
1581     }
1582     for (i = 0; i < length; i++) {
1583       checkpad = (GstPad *) g_list_nth_data(submux->sinkpad, i);
1584       if (checkpad == pad) {
1585         stream = g_list_nth_data (submux->streams, i);
1586         if (!stream) {
1587           GST_ERROR_OBJECT (submux, "Stream not available...");
1588           return GST_FLOW_ERROR;
1589         }
1590         if (stream->flushing){
1591           GST_DEBUG_OBJECT (submux, "flushing going on in appsink");
1592           return GST_FLOW_OK ;
1593         }
1594
1595         g_mutex_lock (stream->queue_lock);
1596         g_queue_push_tail (stream->queue, buffer);
1597         g_cond_signal (stream->queue_empty);
1598         g_mutex_unlock (stream->queue_lock);
1599         fret = GST_FLOW_OK;
1600         GST_DEBUG_OBJECT (submux, "push buffer success to appsrc with fret is %d for stream[%d]", fret, i);
1601         break;
1602       }
1603     }
1604   }
1605
1606   if (!submux->priv->first_buffer) {
1607     GST_DEBUG_OBJECT (submux, "got the first buffer");
1608     submux->priv->first_buffer = TRUE;
1609     if (submux->priv->parser_type == GST_SUB_PARSE_FORMAT_SAMI) {
1610
1611     }
1612   }
1613   GST_DEBUG_OBJECT (submux, "^^^^^exiting in chain^^^^^^");
1614   return fret;
1615 }
1616
1617 /* stream_denit */
1618 static void
1619 gst_submux_stream_deinit (GstSubmuxStream *stream,Gstsubmux *submux)
1620 {
1621   GstBuffer *buf = NULL;
1622
1623   if (stream) {
1624     if (stream->queue) {
1625       while (!g_queue_is_empty (stream->queue)) {
1626         buf = g_queue_pop_head (stream->queue);
1627         gst_buffer_unref (buf);
1628         buf = NULL;
1629       }
1630       g_queue_free (stream->queue);
1631       stream->queue = NULL;
1632     }
1633
1634     if (stream->pipe_struc.pipe) {
1635       gst_element_set_state (stream->pipe_struc.pipe, GST_STATE_NULL);
1636       gst_element_get_state (stream->pipe_struc.pipe, NULL, NULL, GST_CLOCK_TIME_NONE);
1637       gst_object_unref(GST_OBJECT(stream->pipe_struc.appsrc));
1638       gst_object_unref(GST_OBJECT(stream->pipe_struc.appsink));
1639       gst_object_unref (stream->pipe_struc.pipe);
1640     }
1641
1642     if (stream->queue_lock) {
1643       g_cond_broadcast(stream->queue_empty);
1644       g_mutex_free (stream->queue_lock);
1645       stream->queue_lock = NULL;
1646     }
1647
1648     if (stream->queue_empty) {
1649       g_cond_free (stream->queue_empty);
1650       stream->queue_empty= NULL;
1651     }
1652
1653     g_free (stream);
1654     GST_DEBUG_OBJECT (submux, "stream deinit completed");
1655   }
1656 }
1657
1658 /* releasing the requested pad */
1659 static void
1660 gst_submux_release_pad (GstElement * element, GstPad * pad)
1661 {
1662   Gstsubmux *submux = GST_SUBMUX_CAST (element);
1663   GstPad *check_pad;
1664   int i=0;
1665   guint length;
1666   GST_INFO_OBJECT(element,"entering in the release pad");
1667   length = g_list_length(submux->sinkpad);
1668   GST_DEBUG_OBJECT (element, "Releasing %s:%s", GST_DEBUG_PAD_NAME (pad));
1669
1670   for (i=1;i<=length;i++) {
1671           check_pad = (struct GstPad *) g_list_nth_data(submux->sinkpad,i);
1672     if (check_pad == pad) {
1673       /* this is it, remove */
1674       submux->sinkpad = g_list_remove_link (submux->sinkpad, pad);
1675       gst_element_remove_pad (element, pad);
1676       break;
1677     }
1678   }
1679 }
1680
1681 /* request new pad */
1682 static GstPad *
1683 gst_submux_request_new_pad (GstElement * element,
1684     GstPadTemplate * templ, const gchar * req_name)
1685 {
1686   GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
1687   Gstsubmux *submux = GST_SUBMUX_CAST (element);
1688   GstPad *newpad = NULL;
1689   gchar *name = NULL;
1690
1691   if (templ->direction != GST_PAD_SINK) {
1692     GST_ERROR_OBJECT (submux, "templ direction is not sinkpad, returning from here");
1693     goto wrong_direction;
1694   }
1695
1696   if (templ == gst_element_class_get_pad_template (klass, "sink%d")) {
1697     name = g_strdup_printf ("sink%d", submux->sinkpads_count++);
1698   }
1699
1700   GST_DEBUG_OBJECT (submux, "Requested pad: %s", name);
1701   newpad = (GstPad*)g_new0 (GstPad*, 1);
1702   /* create pad and add to collections */
1703   newpad = gst_pad_new_from_template (templ, name);
1704   g_free (name);
1705   if(!submux->priv->is_internal) {
1706     submux->external_sinkpad = TRUE;
1707   }
1708   submux->sinkpad = g_list_append (submux->sinkpad, newpad);
1709   /* set up pad */
1710
1711   /* set up pad functions */
1712   gst_pad_set_setcaps_function (newpad, GST_DEBUG_FUNCPTR (gst_submux_setcaps));
1713   gst_pad_set_event_function (newpad, GST_DEBUG_FUNCPTR (gst_submux_handle_sink_event));
1714   gst_pad_set_chain_function(newpad, GST_DEBUG_FUNCPTR (gst_submux_chain));
1715   gst_pad_set_active (newpad, TRUE);
1716   gst_element_add_pad (element, newpad);
1717
1718   return newpad;
1719
1720 /* ERRORS */
1721 wrong_direction:
1722   GST_WARNING_OBJECT (submux, "Request pad that is not a SINK pad.");
1723   return NULL;
1724 }
1725
1726 static gboolean
1727 gst_submux_handle_src_event (GstPad * pad, GstEvent * event)
1728 {
1729   Gstsubmux *submux = GST_SUBMUX(GST_PAD_PARENT(pad));
1730   gboolean ret = FALSE;
1731   guint length = 0;
1732   gint i = 0;
1733   gboolean update;
1734   GstSubmuxStream *cur_stream = NULL;
1735
1736   GST_DEBUG_OBJECT (submux, "Handling %s event", GST_EVENT_TYPE_NAME (event));
1737   length = g_list_length(submux->streams);
1738
1739   switch (GST_EVENT_TYPE (event)) {
1740     /* this event indicates speed change or seek */
1741     case GST_EVENT_SEEK: {
1742       GstFormat format;
1743       GstSeekType start_type, stop_type;
1744       gint64 start, stop;
1745       gdouble rate;
1746       GstPad *sinkpad = (GstPad *) g_list_nth_data (submux->sinkpad, 0);
1747       gst_event_parse_seek (event, &rate, &format, &submux->segment_flags,
1748                              &start_type, &start, &stop_type, &stop);
1749       gst_segment_set_seek (&submux->segment, rate, format, submux->segment_flags,
1750                              start_type, start, stop_type, stop, &update);
1751       if (submux->priv->is_internal || submux->priv->parser_type != GST_SUB_PARSE_FORMAT_SAMI) {
1752         length = g_list_length (submux->sinkpad);
1753       } else {
1754         length = g_list_length(submux->streams);
1755       }
1756       if (!submux->priv->is_internal) {
1757         ret = gst_pad_push_event (sinkpad, gst_event_new_seek (rate, GST_FORMAT_BYTES, submux->segment_flags,
1758                                   GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, 0));
1759         gst_event_unref (event);
1760       } else {
1761         GST_DEBUG_OBJECT (submux, "handling seek in case of internal");
1762         ret = gst_pad_event_default (pad, event);
1763       }
1764
1765       if (!ret) {
1766         GST_ERROR_OBJECT (submux, "sending seek event to sink pad failed");
1767         break;
1768       }
1769       GST_DEBUG_OBJECT (submux, "sending seek event to sink pad passed");
1770
1771       break;
1772     }
1773
1774     default: {
1775       ret = gst_pad_event_default (pad, event);
1776       break;
1777     }
1778   }
1779
1780   return ret;
1781 }
1782
1783 static gboolean
1784 gst_submux_handle_sink_event (GstPad * pad, GstEvent * event)
1785 {
1786   Gstsubmux *submux = GST_SUBMUX (GST_PAD_PARENT (pad));
1787   gboolean ret = FALSE;
1788   guint length = 0;
1789   GstBuffer *buf = NULL;
1790   GstPad *checkpad = NULL;
1791   gint i = 0;
1792   GstSubmuxStream *cur_stream = NULL;
1793
1794   GST_DEBUG_OBJECT (submux, "Handling %s event", GST_EVENT_TYPE_NAME (event));
1795
1796   switch (GST_EVENT_TYPE (event)) {
1797     case GST_EVENT_EOS:{
1798       length = g_list_length (submux->sinkpad);
1799       GST_OBJECT_LOCK (submux);
1800       for (i = 0; i < length; i++) {
1801         GST_DEBUG_OBJECT(submux, "inside the handling of EOS event");
1802         cur_stream = g_list_nth_data(submux->streams,i);
1803         if (!cur_stream->eos_sent) {
1804           GstBuffer *buf = gst_buffer_new_and_alloc (3 + 1);
1805           GST_DEBUG_OBJECT(submux, "sending EOS buffer to chain\n");
1806           GST_DEBUG_OBJECT (submux, "EOS. Pushing remaining text (if any)");
1807           GST_BUFFER_DATA (buf)[0] = 'e';
1808           GST_BUFFER_DATA (buf)[1] = 'o';
1809           GST_BUFFER_DATA (buf)[2] = 's';
1810           GST_BUFFER_DATA (buf)[3] = '\0';
1811           /* play it safe */
1812           GST_BUFFER_SIZE (buf) = 3;
1813           GST_BUFFER_FLAG_SET(buf,GST_BUFFER_FLAG_GAP);
1814           gst_submux_chain (g_list_nth_data(submux->sinkpad,i), buf);//
1815           cur_stream->eos_sent = TRUE;
1816         }
1817       }
1818       GST_OBJECT_UNLOCK (submux);
1819       gst_event_unref(event);
1820       ret = TRUE;
1821       break;
1822     }
1823     case GST_EVENT_NEWSEGMENT: {
1824       GstFormat format;
1825       gdouble rate,arate;
1826       gint64 start, stop, time;
1827       gboolean update;
1828       GST_OBJECT_LOCK (submux);
1829       if (!submux->pipeline_made) {
1830         if (!gst_submux_format_autodetect (submux)) {
1831           GST_ERROR_OBJECT (submux, "auto detect function failed");
1832           return FALSE;
1833         }
1834         if (!gst_calculate_number_languages(submux)) {
1835           GST_ERROR_OBJECT (submux, "failed to calculate number of languages");
1836           return FALSE;
1837         }
1838         if (!gst_submux_create_pipelines (submux, pad)) {
1839           GST_ERROR_OBJECT (submux, "failed to create pipelines");
1840           return FALSE;
1841         }
1842      }
1843
1844       if (!submux->priv->is_internal) {
1845         gst_event_unref(event);
1846         length = g_list_length(submux->streams);
1847         for (i = 0; i < length; i++) {
1848           GST_DEBUG_OBJECT (submux, "inside the handling of new_segment event");
1849           cur_stream = g_list_nth_data(submux->streams,i);
1850           GST_DEBUG_OBJECT (submux, "pushing newsegment event with %" GST_SEGMENT_FORMAT, &submux->segment);
1851           if (!cur_stream->pipe_struc.pipe) {
1852             GST_ERROR_OBJECT (submux, "pipeline is null");
1853             return FALSE;
1854           }
1855           cur_stream = g_list_nth_data(submux->streams,i);
1856           cur_stream->seek_ts = submux->segment.start;
1857           ret = gst_element_send_event (cur_stream->pipe_struc.pipe, gst_event_new_new_segment (FALSE,
1858                                         submux->segment.rate, submux->segment.format,
1859                                         submux->segment.start, submux->segment.stop, submux->segment.time));
1860           if (!ret){
1861             GST_ERROR_OBJECT(submux, "sending newsegment event to stream[%d] failed", i);
1862             break;
1863           }
1864         }
1865         submux->need_segment = TRUE;
1866       } else {
1867         length = g_list_length (submux->sinkpad);
1868         if (length ==  g_list_length (submux->streams) && submux->need_segment) {
1869           for (i = 0; i < length; i++) {
1870             GST_DEBUG_OBJECT (submux, "inside the handling of new_segment event");
1871             cur_stream = g_list_nth_data(submux->streams, i);
1872             if (cur_stream->need_segment) {
1873               gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, &start, &stop, &time);
1874               gst_segment_set_newsegment_full (&submux->segment, update, rate, arate, format, start, stop, time);
1875               GST_DEBUG_OBJECT (submux, "pushing newsegment event with %" GST_SEGMENT_FORMAT, &submux->segment);
1876               ret = TRUE;
1877               cur_stream->need_segment = FALSE;
1878             }
1879           }
1880           submux->need_segment = TRUE;
1881           gst_event_unref(event);
1882         }
1883       }
1884       GST_OBJECT_UNLOCK (submux);
1885       break;
1886     }
1887     case GST_EVENT_FLUSH_START: {
1888       length = g_list_length(submux->streams);
1889       if (!submux->priv->is_internal) {
1890         gst_event_unref(event);
1891         ret = gst_pad_event_default (pad, gst_event_new_flush_start ());
1892         for (i = 0;i < length;i++) {
1893           cur_stream = g_list_nth_data(submux->streams,i);
1894           cur_stream->flushing = TRUE;
1895           cur_stream->discont_came = FALSE;
1896           GST_DEBUG_OBJECT (submux, "making discont false");
1897           GST_DEBUG_OBJECT (submux, "making flushing TRUE");
1898           cur_stream->eos_came = FALSE;
1899           cur_stream->eos_sent = FALSE;
1900           GST_DEBUG_OBJECT (submux, "making eos_came and eos_sent FALSE");
1901         }
1902         for (i = 0; i < length; i++) {
1903           cur_stream = g_list_nth_data(submux->streams,i);
1904           ret= gst_element_send_event(cur_stream->pipe_struc.appsrc,gst_event_new_flush_start ());
1905           ret= gst_element_send_event(cur_stream->pipe_struc.appsrc,gst_event_new_flush_stop ());
1906           ret = gst_element_send_event(cur_stream->pipe_struc.appsrc,gst_event_new_eos ());
1907           GST_INFO_OBJECT(cur_stream,"flush stop and start  and eos is done with ret %d",ret);
1908           submux->flushing =TRUE;
1909           g_mutex_lock (cur_stream->queue_lock);
1910           g_cond_signal (cur_stream->queue_empty);
1911           g_mutex_unlock(cur_stream->queue_lock);
1912           cur_stream->flush_done = TRUE;
1913           GST_DEBUG_OBJECT (cur_stream, "signaling queue empty signal from flush start");
1914           ret = TRUE;
1915           GST_DEBUG_OBJECT (submux, "sending flush start event to stream[%d] success", i);
1916         }
1917
1918         if (!ret){
1919           GST_ERROR_OBJECT (submux, "sending flush start event to srcpad pad failed");
1920           break;
1921         }
1922
1923         if (submux && GST_PAD_TASK(submux->srcpad)) {
1924           GST_INFO_OBJECT (submux, "trying acquire srcpad lock");
1925           GST_PAD_STREAM_LOCK (submux->srcpad);
1926           GST_INFO_OBJECT (submux, "acquired stream lock");
1927           GST_PAD_STREAM_UNLOCK (submux->srcpad);
1928         }
1929         /*changes for new design*/
1930         for (i = 0;i < length;i++) {
1931           cur_stream = g_list_nth_data(submux->streams,i);
1932           gst_submux_stream_deinit(cur_stream,submux);
1933         }
1934         g_list_free(submux->streams);
1935         submux->streams = NULL;
1936         gst_submux_deinit_private_values (submux);
1937
1938         submux->stop_loop = FALSE;
1939         submux->need_segment = TRUE;
1940         submux->langlist_msg_posted = FALSE;
1941         GST_DEBUG_OBJECT (submux, "flush start successfully send to next element");
1942       } else {
1943         GST_DEBUG_OBJECT(submux, "flusht start in case of internal subtitle");
1944         gst_event_unref (event);
1945         submux->flushing = TRUE;
1946         checkpad = (GstPad *) g_list_nth_data (submux->sinkpad, length - 1);
1947         if (checkpad == pad) {
1948           ret = gst_pad_event_default (pad, gst_event_new_flush_start ());
1949           for (i = 0; i < length; i++) {
1950             cur_stream = g_list_nth_data(submux->streams, i);
1951             cur_stream->flushing = TRUE;
1952             GST_DEBUG_OBJECT (submux, "in case of internal making discont unchanged");
1953             GST_DEBUG_OBJECT (submux, "making flushing TRUE");
1954           }
1955           for (i = 0; i < length; i++) {
1956             cur_stream = g_list_nth_data(submux->streams, i);
1957             submux->flushing = TRUE;
1958             g_mutex_lock (cur_stream->queue_lock);
1959             while (!g_queue_is_empty (cur_stream->queue)) {
1960               buf = g_queue_pop_head (cur_stream->queue);
1961               gst_buffer_unref (buf);
1962             }
1963             GST_DEBUG_OBJECT (submux, "cleared stream cur_stream->queue");
1964             g_queue_clear (cur_stream->queue);
1965             g_cond_signal (cur_stream->queue_empty);
1966             g_mutex_unlock(cur_stream->queue_lock);
1967             GST_DEBUG_OBJECT (cur_stream, "signaling queue empty signal from flush start");
1968             cur_stream->eos_came = FALSE;
1969             cur_stream->eos_sent = FALSE;
1970             GST_DEBUG_OBJECT (submux, "making eos_came and eos_sent FALSE");
1971             ret = TRUE;
1972             GST_DEBUG_OBJECT (submux, "sending flush start event to stream[%d] success", i);
1973           }
1974           if (!ret){
1975             GST_ERROR_OBJECT (submux, "sending flush start event to srcpad pad failed");
1976             break;
1977           }
1978
1979           if (submux && GST_PAD_TASK (submux->srcpad)) {
1980             GST_INFO_OBJECT (submux, "trying acquire srcpad lock");
1981             GST_PAD_STREAM_LOCK (submux->srcpad);
1982             GST_INFO_OBJECT (submux, "acquired srcpad lock");
1983             GST_PAD_STREAM_UNLOCK (submux->srcpad);
1984           }
1985           GST_DEBUG_OBJECT(submux, "flush start successfully send to next element");
1986          }
1987       }
1988       break;
1989     }
1990     case GST_EVENT_FLUSH_STOP: {
1991       gst_event_unref(event);
1992       if (!submux->priv->is_internal) {
1993         guint idx = 0;
1994         submux->flushing = FALSE;
1995         ret = gst_pad_event_default (pad, gst_event_new_flush_stop ());
1996         if (!ret){
1997           GST_ERROR_OBJECT (submux, "sending flush-stop event to srcpad pad failed");
1998           break;
1999         }
2000         for (idx = 0; idx < submux->priv->stream_count; idx++) {
2001           submux->cur_buf_array[idx] = NULL;
2002         }
2003         GST_DEBUG_OBJECT (submux, "flush stop successfully send to next element");
2004       } else {
2005         length = g_list_length(submux->streams);
2006         GST_DEBUG_OBJECT (submux, "flusht stop in case of internal subtitle");
2007         checkpad = (GstPad *) g_list_nth_data (submux->sinkpad, length - 1);
2008         if (checkpad == pad) {
2009           for (i = 0; i < length; i++) {
2010             cur_stream = g_list_nth_data(submux->streams, i);
2011             cur_stream->need_segment = TRUE;
2012             submux->cur_buf_array[i] = NULL;
2013             submux->need_segment = TRUE;
2014             GST_DEBUG_OBJECT (submux, "making need_segment true");
2015             submux->flushing = FALSE;
2016             cur_stream->flushing = FALSE;
2017             GST_DEBUG_OBJECT (submux, "making flushing FALSE");
2018             ret = TRUE;
2019             GST_DEBUG_OBJECT (submux, "sending %s event to stream[%d] success", GST_EVENT_TYPE_NAME (event), i);
2020           }
2021           ret = gst_pad_event_default (pad, gst_event_new_flush_stop ());
2022           if (!ret){
2023             GST_ERROR_OBJECT (submux, "sending flush-stop event to srcpad pad failed");
2024             break;
2025           }
2026           GST_DEBUG_OBJECT (submux, "flush stop successfully send to next element");
2027         }
2028       }
2029       break;
2030     }
2031     default:{
2032       if (!submux->priv->is_internal) {
2033         ret = gst_pad_event_default (pad, event);
2034       } else {
2035         checkpad = (GstPad *) g_list_nth_data (submux->sinkpad, length - 1);
2036         if (checkpad == pad) {
2037           ret = gst_pad_event_default (pad, event);
2038         } else {
2039           ret = TRUE;
2040         }
2041       }
2042       if (!ret){
2043         GST_ERROR_OBJECT (submux, "sending %s event to srcpad pad failed", GST_EVENT_TYPE_NAME (event));
2044         break;
2045       }
2046       break;
2047     }
2048   }
2049   return ret;
2050 }
2051
2052 static gint gst_submux_buffer_list_sorting (gconstpointer a, gconstpointer b)
2053 {
2054   GstBuffer *buf_a = (GstBuffer *) a;
2055   GstBuffer *buf_b = (GstBuffer *) b;
2056   if (GST_BUFFER_TIMESTAMP(buf_a)>GST_BUFFER_TIMESTAMP(buf_b))
2057     return -1;
2058   else if(GST_BUFFER_TIMESTAMP(buf_a)<GST_BUFFER_TIMESTAMP(buf_b))
2059     return 1;
2060   else
2061     return 0;
2062 }
2063
2064 static gboolean
2065 gst_submux_is_muxing_needed (GstBuffer *ref_buffer, GstBuffer *cur_buf)
2066 {
2067   GstClockTime ref_start = GST_BUFFER_TIMESTAMP(ref_buffer);
2068   GstClockTime ref_stop = GST_BUFFER_TIMESTAMP(ref_buffer) + GST_BUFFER_DURATION(ref_buffer);
2069   GstClockTime start = GST_BUFFER_TIMESTAMP(cur_buf);
2070   GstClockTime stop = GST_BUFFER_TIMESTAMP(cur_buf) + GST_BUFFER_DURATION(cur_buf);
2071
2072   /* if we have a stop position and a valid start and start is bigger,
2073    * we're outside of the segment */
2074   if (G_UNLIKELY (ref_stop != -1 && start != -1 && start >= ref_stop))
2075     return FALSE;
2076
2077   /* if a stop position is given and is before the segment start,
2078    * we're outside of the segment. Special case is were start
2079    * and stop are equal to the segment start. In that case we
2080    * are inside the segment. */
2081   if (G_UNLIKELY (stop != -1 && (stop < ref_start || (start != stop && stop == ref_start))))
2082     return FALSE;
2083
2084   return TRUE;
2085 }
2086
2087 /* This function do the actual muxing of buffer on the basis of timestamps */
2088 static GList*
2089 gst_submux_muxing (Gstsubmux *submux)
2090 {
2091   GstClockTime min_timestamp = 0;
2092   int min_stream = 0;
2093   int overlap = 0;
2094   GstClockTime next_min_time = 0;
2095   int idx = 0;
2096   GList *push_list = NULL;
2097
2098   /* Finding least timestamp of all streams and their stream ID */
2099   for (idx = 0; idx < submux->priv->stream_count; idx++) {
2100     if(submux->cur_buf_array[idx] && !min_timestamp) {
2101       min_timestamp = GST_BUFFER_TIMESTAMP(submux->cur_buf_array[idx]);
2102       min_stream = idx;
2103     }
2104     if(submux->cur_buf_array[idx] && (GST_BUFFER_TIMESTAMP(submux->cur_buf_array[idx]) < min_timestamp)) {
2105       min_timestamp = GST_BUFFER_TIMESTAMP(submux->cur_buf_array[idx]);
2106       min_stream = idx;
2107     }
2108   }
2109
2110   GST_DEBUG_OBJECT (submux, "Identified least timestamp: %"GST_TIME_FORMAT" for stream: %d",
2111     GST_TIME_ARGS(min_timestamp), min_stream);
2112
2113   /* Finding overlap buffers and next least timestamp */
2114   for (idx = 0; idx < submux->priv->stream_count; idx++) {
2115     if(submux->cur_buf_array[idx] && (idx != min_stream) && (!next_min_time)) {
2116       next_min_time = GST_BUFFER_TIMESTAMP(submux->cur_buf_array[idx]);
2117     }
2118     if(submux->cur_buf_array[idx] && (idx != min_stream)) {
2119       if(gst_submux_is_muxing_needed (submux->cur_buf_array[min_stream], submux->cur_buf_array[idx])) {
2120         overlap = overlap | (1<<idx);      // bit setting of overlap variable with stream ID
2121         GST_DEBUG_OBJECT (submux, "overlapped with stream = %d", idx);
2122         if(GST_BUFFER_TIMESTAMP(submux->cur_buf_array[idx]) < next_min_time)
2123           next_min_time = GST_BUFFER_TIMESTAMP(submux->cur_buf_array[idx]);
2124       }
2125     }
2126   }
2127
2128   GST_DEBUG_OBJECT (submux, "Identified overlap: %d next least timestamp: %"GST_TIME_FORMAT" ", overlap, GST_TIME_ARGS(next_min_time));
2129
2130   /* If no overlap send buffer as it is */
2131   if(!overlap) {
2132      GST_DEBUG_OBJECT (submux, "pushing string: %s....", (gchar*)GST_BUFFER_DATA(submux->cur_buf_array[min_stream]));
2133      push_list = g_list_append(push_list, submux->cur_buf_array[min_stream]);
2134      GST_DEBUG_OBJECT (submux, "No overlap found pushing buffer of ts = %"GST_TIME_FORMAT", dur = %"GST_TIME_FORMAT,
2135               GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(submux->cur_buf_array[min_stream])), GST_TIME_ARGS(GST_BUFFER_DURATION(submux->cur_buf_array[min_stream])));
2136      submux->cur_buf_array[min_stream] = NULL;
2137   } else {
2138     GstBuffer *push_buf = NULL;
2139     GstClockTime stop_time = 0;
2140     int stop_idx = 0;
2141     GstBuffer *overlap_buf = NULL;
2142     guint overlap_buf_length = 0;
2143     GString *overlap_text = NULL;
2144     gchar *text = NULL;
2145
2146     if(next_min_time > GST_BUFFER_TIMESTAMP(submux->cur_buf_array[min_stream])) {
2147     GST_DEBUG_OBJECT (submux, "Before duration change ts = %"GST_TIME_FORMAT", dur = %"GST_TIME_FORMAT,
2148              GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(submux->cur_buf_array[min_stream])), GST_TIME_ARGS(GST_BUFFER_DURATION(submux->cur_buf_array[min_stream])));
2149       push_buf = gst_buffer_copy (submux->cur_buf_array[min_stream]);
2150       push_buf->duration = next_min_time - GST_BUFFER_TIMESTAMP(submux->cur_buf_array[min_stream]);
2151       GST_BUFFER_TIMESTAMP(submux->cur_buf_array[min_stream]) = next_min_time;
2152       GST_BUFFER_DURATION(submux->cur_buf_array[min_stream]) -= push_buf->duration;
2153       GST_DEBUG_OBJECT (submux, "After duration change ts = %"GST_TIME_FORMAT", dur = %"GST_TIME_FORMAT,
2154              GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(submux->cur_buf_array[min_stream])), GST_TIME_ARGS(GST_BUFFER_DURATION(submux->cur_buf_array[min_stream])));
2155
2156       min_timestamp = next_min_time;
2157       GST_INFO_OBJECT (submux, "pushing string: %s...", (gchar*)GST_BUFFER_DATA(push_buf));
2158       push_list = g_list_append(push_list, push_buf);
2159       GST_DEBUG_OBJECT (submux, "Overlap found pushing initial partial buffer of ts = %"GST_TIME_FORMAT", dur = %"GST_TIME_FORMAT,
2160               GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(push_buf)), GST_TIME_ARGS(GST_BUFFER_DURATION(push_buf)));
2161     }
2162
2163     for (idx = 0; idx < submux->priv->stream_count; idx++) {
2164       if(submux->cur_buf_array[idx] && !stop_time) {
2165         stop_time = GST_BUFFER_TIMESTAMP(submux->cur_buf_array[idx]) + GST_BUFFER_DURATION(submux->cur_buf_array[idx]);
2166         stop_idx = idx;
2167       }
2168       if(submux->cur_buf_array[idx] &&
2169           ((GST_BUFFER_TIMESTAMP(submux->cur_buf_array[idx])+ GST_BUFFER_DURATION(submux->cur_buf_array[idx])) < stop_time)) {
2170         stop_time = GST_BUFFER_TIMESTAMP(submux->cur_buf_array[idx]) + GST_BUFFER_DURATION(submux->cur_buf_array[idx]);
2171         stop_idx = idx;
2172       }
2173     }
2174     GST_DEBUG_OBJECT (submux, "Identified least stop timestamp: %"GST_TIME_FORMAT" for stream: %d",
2175             GST_TIME_ARGS(stop_time), stop_idx);
2176
2177     overlap_text = g_string_new ("");
2178     overlap = overlap | (1<<min_stream);
2179     for (idx = 0; idx < submux->priv->stream_count; idx++) {
2180       int finder = 1<<idx;
2181       if(overlap & finder) {
2182         GST_DEBUG_OBJECT (submux, "append string: %s....", (gchar*)GST_BUFFER_DATA(submux->cur_buf_array[idx]));
2183         g_string_append (overlap_text, (gchar*)GST_BUFFER_DATA (submux->cur_buf_array[idx]));
2184         GST_BUFFER_TIMESTAMP(submux->cur_buf_array[idx])+= (stop_time - min_timestamp);
2185         GST_BUFFER_DURATION(submux->cur_buf_array[idx])-= (stop_time - min_timestamp);
2186         if(overlap > (1<<(idx+1))) g_string_append_c (overlap_text, '\n');
2187       }
2188     }
2189     text = g_string_free (overlap_text, FALSE);
2190     overlap_buf_length = strlen(text);
2191     overlap_buf = gst_buffer_new_and_alloc (overlap_buf_length + 1);
2192     memcpy (GST_BUFFER_DATA (overlap_buf), text, overlap_buf_length + 1);
2193     overlap_buf->timestamp = min_timestamp;
2194     overlap_buf->duration = stop_time - min_timestamp;
2195     g_free (text);
2196     text = NULL;
2197     submux->cur_buf_array[stop_idx] = NULL;
2198     GST_DEBUG_OBJECT (submux, "pushing string: %s....", (gchar*)GST_BUFFER_DATA(overlap_buf));
2199     push_list = g_list_append(push_list, overlap_buf);
2200     GST_DEBUG_OBJECT (submux, "Overlap found pushing merged buffer of ts = %"GST_TIME_FORMAT", dur = %"GST_TIME_FORMAT,
2201           GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(overlap_buf)), GST_TIME_ARGS(GST_BUFFER_DURATION(overlap_buf)));
2202     GST_DEBUG_OBJECT (submux, "request for new buffer for stream %d", stop_idx);
2203     for (idx = 0; idx < submux->priv->stream_count; idx++) {
2204       if(submux->cur_buf_array[idx] &&
2205            ((GST_BUFFER_TIMESTAMP(submux->cur_buf_array[idx])+ GST_BUFFER_DURATION(submux->cur_buf_array[idx])) <= stop_time)) {
2206         submux->cur_buf_array[idx] = NULL;
2207         GST_DEBUG_OBJECT (submux, "request for new buffer for stream %d", idx);
2208       }
2209     }
2210   }
2211   return push_list;
2212 }
2213
2214 static void gst_submux_loop (Gstsubmux *submux)
2215 {
2216   guint length = 0;
2217   GstBuffer *src_buffer = NULL;
2218   GstBuffer *temp_buffer = NULL;
2219   GstBuffer *check_buffer = NULL;
2220   GstSubmuxStream *cur_stream = NULL;
2221   GstSubmuxStream *check_stream = NULL;
2222   gboolean match = FALSE;
2223   GstFlowReturn fret = GST_FLOW_OK;
2224   GstClockTime cur_duration = 0 ;
2225   GstClockTime cur_ts = 0;
2226   gboolean eos = TRUE;
2227   guint i= 0,k = 0;
2228   GList *push_list = NULL;
2229   GstBuffer *push_buf = NULL;
2230
2231   if (!submux->priv->first_buffer) {
2232     GST_INFO_OBJECT (submux, "exiting from lopp");
2233     return;
2234   }
2235
2236   if (submux->priv->parser_type == GST_SUB_PARSE_FORMAT_SAMI) {
2237     length = g_list_length (submux->priv->lang_list);
2238   } else {
2239     length = submux->sinkpads_count;
2240   }
2241
2242   gboolean made = FALSE;
2243  // length = 2;
2244
2245   for (i = 0; i < length; i++) {
2246
2247 re_pop:
2248     cur_stream = g_list_nth_data (submux->streams, i);
2249     GST_DEBUG_OBJECT (submux, "Before lock acquired in loop stream[%d]", i);
2250     g_mutex_lock (cur_stream->queue_lock);
2251     GST_DEBUG_OBJECT (submux, "Lock acquired in loop stream[%d]", i);
2252
2253     if (g_queue_is_empty (cur_stream->queue) && !submux->flushing) {
2254       GST_DEBUG_OBJECT (submux, "Queue is empty, waiting for the condition signal stream[%d]", i);
2255       g_cond_wait (cur_stream->queue_empty, cur_stream->queue_lock);
2256     }
2257     GST_DEBUG_OBJECT (submux, "Got the queue condition signal stream[%d]", i);
2258
2259     if (submux->flushing || submux->stop_loop) {
2260       GST_DEBUG_OBJECT (submux, "Flushing going on in loop");
2261       GST_DEBUG_OBJECT (submux, "Got the condition signal");
2262       g_mutex_unlock (cur_stream->queue_lock);
2263       goto error;
2264     }
2265
2266     check_buffer = g_queue_peek_head (cur_stream->queue);
2267     if (!strcmp ((const char*)GST_BUFFER_DATA (check_buffer), "eos")){
2268       cur_stream->eos_came = TRUE;
2269       GST_DEBUG_OBJECT (submux, "Eos recieved for stream");
2270     }
2271     for (k = 0; k < length; k++)  {
2272       check_stream = g_list_nth_data(submux->streams, k);
2273       if (!check_stream->eos_came) {
2274         eos = FALSE;
2275         break;
2276       } else {
2277         eos = TRUE;
2278       }
2279     }
2280     if (eos) {
2281       GST_DEBUG_OBJECT (submux, "Sending EOS to submux srcpad");
2282       gst_pad_push_event(submux->srcpad, gst_event_new_eos ());
2283       g_mutex_unlock (cur_stream->queue_lock);
2284       goto eos_sent;
2285     }
2286
2287     if (!cur_stream->eos_came && (submux->priv->parser_type == GST_SUB_PARSE_FORMAT_SAMI ||
2288                                   submux->priv->is_internal)) {
2289       GstLangStruct *lang = NULL;
2290       if (submux->priv->lang_list) {
2291         if (submux->cur_buf_array[i] == NULL) {
2292           check_buffer = g_queue_pop_head (cur_stream->queue);
2293           lang = g_list_nth_data(submux->priv->lang_list, i);
2294           if (!lang->active) {
2295             if(check_buffer) {
2296               gst_buffer_unref(check_buffer);
2297               check_buffer = NULL;
2298               GST_DEBUG_OBJECT (submux, "unreffing the non-active stream[%d] buffer", i);
2299             }
2300             submux->cur_buf_array[i] = NULL;
2301             g_mutex_unlock (cur_stream->queue_lock);
2302             GST_DEBUG_OBJECT(submux,"rejecting not selected language");
2303             continue;
2304           } else {
2305             if (!check_buffer) {
2306               GST_WARNING_OBJECT (submux, "checkbuffer null.. repop");
2307               g_mutex_unlock (cur_stream->queue_lock);
2308               goto re_pop;
2309             }
2310             if (!GST_BUFFER_DURATION(check_buffer)) {
2311               GST_WARNING_OBJECT (submux, "duration of buffer is zero..re-pop");
2312               gst_buffer_unref (check_buffer);
2313               g_mutex_unlock (cur_stream->queue_lock);
2314               goto re_pop;
2315             }
2316             submux->cur_buf_array[i] = check_buffer;
2317             GST_DEBUG_OBJECT (submux, "consuming active stream [%d] buffer : ts = %"GST_TIME_FORMAT"and dur = %"GST_TIME_FORMAT,
2318               i, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (check_buffer)), GST_TIME_ARGS(GST_BUFFER_DURATION (check_buffer)));
2319           }
2320         }
2321       } else {
2322         g_mutex_unlock (cur_stream->queue_lock);
2323         GST_DEBUG_OBJECT(submux,"Coming to Else case lang submux->priv->lang_list %x ",submux->priv->lang_list);
2324         continue;
2325       }
2326     } else if (!cur_stream->eos_came) {
2327       /* External subtitle format other than smi */
2328       if (submux->sinkpad) {
2329         if (submux->cur_buf_array[i] == NULL) {
2330           check_buffer = g_queue_pop_head (cur_stream->queue);
2331           if (!check_buffer) {
2332             GST_WARNING_OBJECT (submux, "checkbuffer null.. repop");
2333             g_mutex_unlock (cur_stream->queue_lock);
2334             goto re_pop;
2335           }
2336           if (!GST_BUFFER_DURATION (check_buffer)) {
2337             GST_WARNING_OBJECT (submux, "duration of buffer is zero..re-pop");
2338             gst_buffer_unref (check_buffer);
2339             g_mutex_unlock (cur_stream->queue_lock);
2340             goto re_pop;
2341           }
2342           submux->cur_buf_array[i] = check_buffer;
2343           GST_DEBUG_OBJECT (submux, "consuming active stream [%d] buffer : ts = %"GST_TIME_FORMAT"and dur = %"GST_TIME_FORMAT,
2344             i, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (check_buffer)), GST_TIME_ARGS(GST_BUFFER_DURATION (check_buffer)));
2345         }
2346       } else {
2347         g_mutex_unlock (cur_stream->queue_lock);
2348         GST_DEBUG_OBJECT(submux,"Coming to Else case submux->sinkpad %x ",submux->sinkpad);
2349         continue;
2350       }
2351     } else {
2352       GST_DEBUG_OBJECT (submux, "already received EOS on this stream[%d] and cur_buf_array[idx] = NULL", i);
2353       submux->cur_buf_array[i] = NULL;
2354     }
2355
2356     g_mutex_unlock (cur_stream->queue_lock);
2357     GST_DEBUG_OBJECT (submux, "After unlocking in loop and signal queue full");
2358   }
2359
2360   push_list = gst_submux_muxing (submux);
2361   if (push_list) {
2362     guint idx = 0;
2363     GST_LOG_OBJECT (submux, "length of push list = %d", g_list_length (push_list));
2364
2365     for (idx = 0; idx < g_list_length (push_list); idx++) {
2366       push_buf = g_list_nth_data (push_list, idx);
2367
2368       if (push_buf) {
2369         GST_DEBUG_OBJECT (submux, "pushing buffer : ts = %"GST_TIME_FORMAT", "
2370             "dur = %"GST_TIME_FORMAT" and data %s ...",
2371         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (push_buf)),
2372         GST_TIME_ARGS (GST_BUFFER_DURATION (push_buf)), (gchar*)GST_BUFFER_DATA (push_buf));
2373
2374         fret = gst_pad_push (submux->srcpad, push_buf);
2375         if (fret != GST_FLOW_OK) {
2376           GST_ERROR_OBJECT (submux, "failed to push buffer. reason : %s", gst_flow_get_name (fret));
2377           /* clean any left buffers in push_list */
2378           idx++;
2379           for (; idx < g_list_length (push_list); idx++) {
2380             push_buf = g_list_nth_data (push_list, idx);
2381             gst_buffer_unref (push_buf);
2382           }
2383           g_list_free (push_list);
2384           goto error;
2385         }
2386       }
2387     }
2388
2389     g_list_free (push_list);
2390   }
2391
2392   GST_DEBUG_OBJECT (submux, "Exiting from lopp in last");
2393
2394   return;
2395
2396 eos_sent:
2397 error:
2398   GST_WARNING_OBJECT (submux->srcpad, "Pausing the push task...");
2399   if (fret < GST_FLOW_UNEXPECTED) {
2400     GST_ERROR_OBJECT (submux, "Crtical error in push loop....");
2401     GST_ELEMENT_ERROR (submux, CORE, PAD, ("failed to push. reason - %s", gst_flow_get_name (fret)), (NULL));
2402   }
2403   gst_pad_pause_task (submux->srcpad);
2404   GST_DEBUG_OBJECT (submux, "Exiting from lopp in last");
2405   return;
2406 }
2407
2408 ////////////////////////////////////////////////////////
2409 //        Plugin Utility Functions                    //
2410 ////////////////////////////////////////////////////////
2411 /*
2412 **
2413 **  Description    : De-Initializing the submux private structure
2414 **  Params        : (1) submux instance
2415 **  return        : TRUE
2416 **  Comments    :
2417 **
2418 */
2419 static gboolean
2420 gst_submux_deinit_private_values(Gstsubmux *submux)
2421 {
2422   guint idx = 0;
2423   GST_DEBUG_OBJECT (submux, "deinit priv values");
2424
2425   submux->priv->first_buffer = FALSE;
2426   submux->priv->parser_type = 0;
2427   if (submux->priv->lang_list && !submux->priv->is_internal) {
2428     g_list_free (submux->priv->lang_list);
2429     submux->priv->lang_list = NULL;
2430   }
2431   for (idx = 0; idx < submux->priv->stream_count; idx++) {
2432     submux->cur_buf_array[idx] = NULL;
2433   }
2434   if (submux->cur_buf_array) {
2435     g_free (submux->cur_buf_array);
2436     submux->cur_buf_array = NULL;
2437   }
2438
2439   submux->priv->is_internal = FALSE;
2440   submux->priv->stream_count = 0;
2441
2442   return TRUE;
2443 }
2444
2445 static gboolean
2446 gst_submux_plugin_init (GstPlugin * plugin)
2447 {
2448   return gst_element_register (plugin, "submux", GST_RANK_PRIMARY, GST_TYPE_SUBMUX);
2449 }
2450
2451 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")