mpegtsbase: remember stream pid before remove stream
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / gst / mpegtsdemux / mpegtsbase.c
1 /*
2  * mpegtsbase.c -
3  * Copyright (C) 2007 Alessandro Decina
4  *               2010 Edward Hervey
5  * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
6  *  Author: Youness Alaoui <youness.alaoui@collabora.co.uk>, Collabora Ltd.
7  *  Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
8  *  Author: Edward Hervey <bilboed@bilboed.com>, Collabora Ltd.
9  *
10  * Authors:
11  *   Alessandro Decina <alessandro@nnva.org>
12  *   Zaheer Abbas Merali <zaheerabbas at merali dot org>
13  *   Edward Hervey <edward.hervey@collabora.co.uk>
14  *
15  * This library is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU Library General Public
17  * License as published by the Free Software Foundation; either
18  * version 2 of the License, or (at your option) any later version.
19  *
20  * This library is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23  * Library General Public License for more details.
24  *
25  * You should have received a copy of the GNU Library General Public
26  * License along with this library; if not, write to the
27  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
28  * Boston, MA 02110-1301, USA.
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include <glib.h>
39
40 #include <glib/gi18n-lib.h>
41 #include "mpegtsbase.h"
42 #include "gstmpegdesc.h"
43
44 #define RUNNING_STATUS_RUNNING 4
45
46 GST_DEBUG_CATEGORY_STATIC (mpegts_base_debug);
47 #define GST_CAT_DEFAULT mpegts_base_debug
48
49 static GQuark QUARK_PROGRAMS;
50 static GQuark QUARK_PROGRAM_NUMBER;
51 static GQuark QUARK_PID;
52 static GQuark QUARK_PCR_PID;
53 static GQuark QUARK_STREAMS;
54 static GQuark QUARK_STREAM_TYPE;
55
56 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
57     GST_PAD_SINK,
58     GST_PAD_ALWAYS,
59     GST_STATIC_CAPS ("video/mpegts, " "systemstream = (boolean) true ")
60     );
61
62 #define DEFAULT_IGNORE_PCR FALSE
63
64 enum
65 {
66   PROP_0,
67   PROP_PARSE_PRIVATE_SECTIONS,
68   PROP_IGNORE_PCR,
69   /* FILL ME */
70 };
71
72 static void mpegts_base_dispose (GObject * object);
73 static void mpegts_base_finalize (GObject * object);
74 static void mpegts_base_set_property (GObject * object, guint prop_id,
75     const GValue * value, GParamSpec * pspec);
76 static void mpegts_base_get_property (GObject * object, guint prop_id,
77     GValue * value, GParamSpec * pspec);
78
79 static void mpegts_base_free_program (MpegTSBaseProgram * program);
80 static void mpegts_base_deactivate_program (MpegTSBase * base,
81     MpegTSBaseProgram * program);
82 static gboolean mpegts_base_sink_activate (GstPad * pad, GstObject * parent);
83 static gboolean mpegts_base_sink_activate_mode (GstPad * pad,
84     GstObject * parent, GstPadMode mode, gboolean active);
85 static GstFlowReturn mpegts_base_chain (GstPad * pad, GstObject * parent,
86     GstBuffer * buf);
87 static gboolean mpegts_base_sink_event (GstPad * pad, GstObject * parent,
88     GstEvent * event);
89 static gboolean mpegts_base_sink_query (GstPad * pad, GstObject * parent,
90     GstQuery * query);
91 static gboolean mpegts_base_default_sink_query (MpegTSBase * base,
92     GstQuery * query);
93 static GstStateChangeReturn mpegts_base_change_state (GstElement * element,
94     GstStateChange transition);
95 static gboolean mpegts_base_get_tags_from_eit (MpegTSBase * base,
96     GstMpegtsSection * section);
97 static gboolean mpegts_base_parse_atsc_mgt (MpegTSBase * base,
98     GstMpegtsSection * section);
99 static void remove_each_program (MpegTSBaseProgram * program,
100     MpegTSBase * base);
101
102 static void
103 _extra_init (void)
104 {
105   QUARK_PROGRAMS = g_quark_from_string ("programs");
106   QUARK_PROGRAM_NUMBER = g_quark_from_string ("program-number");
107   QUARK_PID = g_quark_from_string ("pid");
108   QUARK_PCR_PID = g_quark_from_string ("pcr-pid");
109   QUARK_STREAMS = g_quark_from_string ("streams");
110   QUARK_STREAM_TYPE = g_quark_from_string ("stream-type");
111   GST_DEBUG_CATEGORY_INIT (mpegts_base_debug, "mpegtsbase", 0,
112       "MPEG transport stream base class");
113   gst_mpegts_initialize ();
114 }
115
116 #define mpegts_base_parent_class parent_class
117 G_DEFINE_TYPE_WITH_CODE (MpegTSBase, mpegts_base, GST_TYPE_ELEMENT,
118     _extra_init ());
119
120 /* Default implementation is that mpegtsbase can remove any program */
121 static gboolean
122 mpegts_base_can_remove_program (MpegTSBase * base, MpegTSBaseProgram * program)
123 {
124   return TRUE;
125 }
126
127 static void
128 mpegts_base_class_init (MpegTSBaseClass * klass)
129 {
130   GObjectClass *gobject_class;
131   GstElementClass *element_class;
132
133   klass->can_remove_program = mpegts_base_can_remove_program;
134
135   element_class = GST_ELEMENT_CLASS (klass);
136   element_class->change_state = mpegts_base_change_state;
137
138   gst_element_class_add_static_pad_template (element_class, &sink_template);
139
140   gobject_class = G_OBJECT_CLASS (klass);
141   gobject_class->dispose = mpegts_base_dispose;
142   gobject_class->finalize = mpegts_base_finalize;
143   gobject_class->set_property = mpegts_base_set_property;
144   gobject_class->get_property = mpegts_base_get_property;
145
146   g_object_class_install_property (gobject_class, PROP_PARSE_PRIVATE_SECTIONS,
147       g_param_spec_boolean ("parse-private-sections", "Parse private sections",
148           "Parse private sections", FALSE,
149           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
150
151   /**
152    * GstMpegtsBase:ignore-pcr:
153    *
154    * Ignore PCR (Program Clock Reference) data from MPEG-TS PSI.
155    * This can help with playback of some broken files.
156    *
157    * Since: 1.18
158    */
159   g_object_class_install_property (gobject_class, PROP_IGNORE_PCR,
160       g_param_spec_boolean ("ignore-pcr", "Ignore PCR stream for timing",
161           "Ignore PCR stream for timing", DEFAULT_IGNORE_PCR,
162           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
163
164   klass->sink_query = GST_DEBUG_FUNCPTR (mpegts_base_default_sink_query);
165   klass->handle_psi = NULL;
166
167   gst_type_mark_as_plugin_api (GST_TYPE_MPEGTS_BASE, 0);
168 }
169
170 static void
171 mpegts_base_set_property (GObject * object, guint prop_id,
172     const GValue * value, GParamSpec * pspec)
173 {
174   MpegTSBase *base = GST_MPEGTS_BASE (object);
175
176   switch (prop_id) {
177     case PROP_PARSE_PRIVATE_SECTIONS:
178       base->parse_private_sections = g_value_get_boolean (value);
179       break;
180     case PROP_IGNORE_PCR:
181       base->ignore_pcr = g_value_get_boolean (value);
182       break;
183     default:
184       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
185   }
186 }
187
188 static void
189 mpegts_base_get_property (GObject * object, guint prop_id,
190     GValue * value, GParamSpec * pspec)
191 {
192   MpegTSBase *base = GST_MPEGTS_BASE (object);
193
194   switch (prop_id) {
195     case PROP_PARSE_PRIVATE_SECTIONS:
196       g_value_set_boolean (value, base->parse_private_sections);
197       break;
198     case PROP_IGNORE_PCR:
199       g_value_set_boolean (value, base->ignore_pcr);
200       break;
201     default:
202       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
203   }
204 }
205
206
207 static void
208 mpegts_base_reset (MpegTSBase * base)
209 {
210   MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
211
212   mpegts_packetizer_clear (base->packetizer);
213   memset (base->is_pes, 0, 1024);
214   memset (base->known_psi, 0, 1024);
215
216   /* FIXME : Actually these are not *always* know SI streams
217    * depending on the variant of mpeg-ts being used. */
218
219   /* Known PIDs : PAT, TSDT, IPMP CIT */
220   MPEGTS_BIT_SET (base->known_psi, 0);
221   MPEGTS_BIT_SET (base->known_psi, 2);
222   MPEGTS_BIT_SET (base->known_psi, 3);
223   /* TDT, TOT, ST */
224   MPEGTS_BIT_SET (base->known_psi, 0x14);
225   /* network synchronization */
226   MPEGTS_BIT_SET (base->known_psi, 0x15);
227
228   /* ATSC */
229   MPEGTS_BIT_SET (base->known_psi, 0x1ffb);
230
231   if (base->pat) {
232     g_ptr_array_unref (base->pat);
233     base->pat = NULL;
234   }
235
236   gst_segment_init (&base->segment, GST_FORMAT_UNDEFINED);
237   gst_segment_init (&base->out_segment, GST_FORMAT_UNDEFINED);
238   base->last_seek_seqnum = GST_SEQNUM_INVALID;
239
240   base->mode = BASE_MODE_STREAMING;
241   base->seen_pat = FALSE;
242   base->seek_offset = -1;
243
244   g_ptr_array_foreach (base->programs, (GFunc) remove_each_program, base);
245   g_ptr_array_remove_range (base->programs, 0, base->programs->len);
246
247   base->streams_aware = GST_OBJECT_PARENT (base)
248       && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (base),
249       GST_BIN_FLAG_STREAMS_AWARE);
250   GST_DEBUG_OBJECT (base, "Streams aware : %d", base->streams_aware);
251
252   gst_event_replace (&base->seek_event, NULL);
253
254   if (klass->reset)
255     klass->reset (base);
256 }
257
258 static void
259 mpegts_base_init (MpegTSBase * base)
260 {
261   base->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
262   gst_pad_set_activate_function (base->sinkpad, mpegts_base_sink_activate);
263   gst_pad_set_activatemode_function (base->sinkpad,
264       mpegts_base_sink_activate_mode);
265   gst_pad_set_chain_function (base->sinkpad, mpegts_base_chain);
266   gst_pad_set_event_function (base->sinkpad, mpegts_base_sink_event);
267   gst_pad_set_query_function (base->sinkpad, mpegts_base_sink_query);
268   gst_element_add_pad (GST_ELEMENT (base), base->sinkpad);
269
270   base->disposed = FALSE;
271   base->packetizer = mpegts_packetizer_new ();
272   base->programs =
273       g_ptr_array_new_full (16, (GDestroyNotify) mpegts_base_free_program);
274
275   base->parse_private_sections = FALSE;
276   base->is_pes = g_new0 (guint8, 1024);
277   base->known_psi = g_new0 (guint8, 1024);
278   base->program_size = sizeof (MpegTSBaseProgram);
279   base->stream_size = sizeof (MpegTSBaseStream);
280
281   base->push_data = TRUE;
282   base->push_section = TRUE;
283   base->ignore_pcr = DEFAULT_IGNORE_PCR;
284
285   mpegts_base_reset (base);
286 }
287
288 static void
289 mpegts_base_dispose (GObject * object)
290 {
291   MpegTSBase *base = GST_MPEGTS_BASE (object);
292
293   if (!base->disposed) {
294     g_object_unref (base->packetizer);
295     base->disposed = TRUE;
296     g_free (base->known_psi);
297     g_free (base->is_pes);
298   }
299
300   if (G_OBJECT_CLASS (parent_class)->dispose)
301     G_OBJECT_CLASS (parent_class)->dispose (object);
302 }
303
304 static void
305 mpegts_base_finalize (GObject * object)
306 {
307   MpegTSBase *base = GST_MPEGTS_BASE (object);
308
309   if (base->pat) {
310     g_ptr_array_unref (base->pat);
311     base->pat = NULL;
312   }
313   g_ptr_array_free (base->programs, TRUE);
314
315   gst_event_replace (&base->seek_event, NULL);
316
317   if (G_OBJECT_CLASS (parent_class)->finalize)
318     G_OBJECT_CLASS (parent_class)->finalize (object);
319 }
320
321
322 /* returns NULL if no matching descriptor found *
323  * otherwise returns a descriptor that needs to *
324  * be freed */
325 const GstMpegtsDescriptor *
326 mpegts_get_descriptor_from_stream (MpegTSBaseStream * stream, guint8 tag)
327 {
328   GstMpegtsPMTStream *pmt = stream->stream;
329
330   GST_DEBUG ("Searching for tag 0x%02x in stream 0x%04x (stream_type 0x%02x)",
331       tag, stream->pid, stream->stream_type);
332
333   return gst_mpegts_find_descriptor (pmt->descriptors, tag);
334 }
335
336 const GstMpegtsDescriptor *
337 mpegts_get_descriptor_from_stream_with_extension (MpegTSBaseStream * stream,
338     guint8 tag, guint8 tag_extension)
339 {
340   GstMpegtsPMTStream *pmt = stream->stream;
341
342   GST_DEBUG ("Searching for tag 0x%02x tag_extension 0x%02x "
343       "in stream 0x%04x (stream_type 0x%02x)",
344       tag, tag_extension, stream->pid, stream->stream_type);
345
346   return gst_mpegts_find_descriptor_with_extension (pmt->descriptors, tag,
347       tag_extension);
348 }
349
350 typedef struct
351 {
352   gboolean res;
353   guint16 pid;
354 } PIDLookup;
355
356 static void
357 foreach_pid_in_program (MpegTSBaseProgram * program, PIDLookup * lookup)
358 {
359   if (!program->active)
360     return;
361   if (program->streams[lookup->pid])
362     lookup->res = TRUE;
363 }
364
365 static gboolean
366 mpegts_pid_in_active_programs (MpegTSBase * base, guint16 pid)
367 {
368   PIDLookup lookup;
369
370   lookup.res = FALSE;
371   lookup.pid = pid;
372   g_ptr_array_foreach (base->programs, (GFunc) foreach_pid_in_program, &lookup);
373
374   return lookup.res;
375 }
376
377 /* returns NULL if no matching descriptor found *
378  * otherwise returns a descriptor that needs to *
379  * be freed */
380 const GstMpegtsDescriptor *
381 mpegts_get_descriptor_from_program (MpegTSBaseProgram * program, guint8 tag)
382 {
383   const GstMpegtsPMT *pmt = program->pmt;
384
385   return gst_mpegts_find_descriptor (pmt->descriptors, tag);
386 }
387
388 static gchar *
389 _get_upstream_id (GstElement * element, GstPad * sinkpad)
390 {
391   gchar *upstream_id = gst_pad_get_stream_id (sinkpad);
392
393   if (!upstream_id) {
394     /* Try to create one from the upstream URI, else use a randome number */
395     GstQuery *query;
396     gchar *uri = NULL;
397
398     /* Try to generate one from the URI query and
399      * if it fails take a random number instead */
400     query = gst_query_new_uri ();
401     if (gst_element_query (element, query)) {
402       gst_query_parse_uri (query, &uri);
403     }
404
405     if (uri) {
406       GChecksum *cs;
407
408       /* And then generate an SHA256 sum of the URI */
409       cs = g_checksum_new (G_CHECKSUM_SHA256);
410       g_checksum_update (cs, (const guchar *) uri, strlen (uri));
411       g_free (uri);
412       upstream_id = g_strdup (g_checksum_get_string (cs));
413       g_checksum_free (cs);
414     } else {
415       /* Just get some random number if the URI query fails */
416       GST_FIXME_OBJECT (element, "Creating random stream-id, consider "
417           "implementing a deterministic way of creating a stream-id");
418       upstream_id =
419           g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
420           g_random_int (), g_random_int ());
421     }
422
423     gst_query_unref (query);
424   }
425   return upstream_id;
426 }
427
428 static MpegTSBaseProgram *
429 mpegts_base_new_program (MpegTSBase * base,
430     gint program_number, guint16 pmt_pid)
431 {
432   MpegTSBaseProgram *program;
433   gchar *upstream_id, *stream_id;
434
435   GST_DEBUG_OBJECT (base, "program_number : %d, pmt_pid : 0x%04x",
436       program_number, pmt_pid);
437
438   program = g_malloc0 (base->program_size);
439   program->program_number = program_number;
440   program->pmt_pid = pmt_pid;
441   program->pcr_pid = G_MAXUINT16;
442   program->streams = g_new0 (MpegTSBaseStream *, 0x2000);
443   program->patcount = 0;
444
445   upstream_id = _get_upstream_id ((GstElement *) base, base->sinkpad);
446   stream_id = g_strdup_printf ("%s:%d", upstream_id, program_number);
447   program->collection = gst_stream_collection_new (stream_id);
448   g_free (stream_id);
449   g_free (upstream_id);
450
451   return program;
452 }
453
454 MpegTSBaseProgram *
455 mpegts_base_add_program (MpegTSBase * base,
456     gint program_number, guint16 pmt_pid)
457 {
458   MpegTSBaseProgram *program;
459
460   GST_DEBUG_OBJECT (base, "program_number : %d, pmt_pid : 0x%04x",
461       program_number, pmt_pid);
462
463   program = mpegts_base_new_program (base, program_number, pmt_pid);
464
465   /* Mark the PMT PID as being a known PSI PID */
466   if (G_UNLIKELY (MPEGTS_BIT_IS_SET (base->known_psi, pmt_pid))) {
467     GST_FIXME ("Refcounting. Setting twice a PID (0x%04x) as known PSI",
468         pmt_pid);
469   }
470   MPEGTS_BIT_SET (base->known_psi, pmt_pid);
471
472   /* Ensure the PMT PID was not used by some PES stream */
473   if (G_UNLIKELY (MPEGTS_BIT_IS_SET (base->is_pes, pmt_pid))) {
474     GST_DEBUG ("New program PMT PID was previously used by a PES stream");
475     MPEGTS_BIT_UNSET (base->is_pes, pmt_pid);
476   }
477
478
479   g_ptr_array_add (base->programs, program);
480
481   return program;
482 }
483
484 MpegTSBaseProgram *
485 mpegts_base_get_program (MpegTSBase * base, gint program_number)
486 {
487   guint i;
488
489   for (i = 0; i < base->programs->len; i++) {
490     MpegTSBaseProgram *program = g_ptr_array_index (base->programs, i);
491     if (program->program_number == program_number)
492       return program;
493   }
494   return NULL;
495 }
496
497 static MpegTSBaseProgram *
498 mpegts_base_steal_program (MpegTSBase * base, gint program_number)
499 {
500   guint i;
501
502   for (i = 0; i < base->programs->len; i++) {
503     MpegTSBaseProgram *program = g_ptr_array_index (base->programs, i);
504     if (program->program_number == program_number) {
505       return g_ptr_array_steal_index (base->programs, i);
506     }
507   }
508
509   return NULL;
510 }
511
512 static void
513 mpegts_base_free_stream (MpegTSBaseStream * stream)
514 {
515   if (stream->stream_object)
516     gst_object_unref (stream->stream_object);
517   if (stream->stream_id)
518     g_free (stream->stream_id);
519   g_free (stream);
520 }
521
522 static void
523 mpegts_base_free_program (MpegTSBaseProgram * program)
524 {
525   GList *tmp;
526
527   if (program->recycle) {
528     program->recycle = FALSE;
529     return;
530   }
531
532   if (program->pmt) {
533     gst_mpegts_section_unref (program->section);
534     program->pmt = NULL;
535   }
536
537   /* FIXME FIXME FIXME FREE STREAM OBJECT ! */
538   for (tmp = program->stream_list; tmp; tmp = tmp->next)
539     mpegts_base_free_stream ((MpegTSBaseStream *) tmp->data);
540
541   if (program->stream_list)
542     g_list_free (program->stream_list);
543
544   g_free (program->streams);
545
546   if (program->tags)
547     gst_tag_list_unref (program->tags);
548   if (program->collection)
549     gst_object_unref (program->collection);
550
551   g_free (program);
552 }
553
554 void
555 mpegts_base_deactivate_and_free_program (MpegTSBase * base,
556     MpegTSBaseProgram * program)
557 {
558   GST_DEBUG_OBJECT (base, "program_number : %d", program->program_number);
559
560   mpegts_base_deactivate_program (base, program);
561   mpegts_base_free_program (program);
562 }
563
564 static void
565 mpegts_base_remove_program (MpegTSBase * base, MpegTSBaseProgram * program)
566 {
567   GST_DEBUG_OBJECT (base, "program_number : %d", program->program_number);
568
569   g_ptr_array_remove (base->programs, program);
570 }
571
572 static guint32
573 get_registration_from_descriptors (GPtrArray * descriptors)
574 {
575   const GstMpegtsDescriptor *desc;
576
577   if ((desc =
578           gst_mpegts_find_descriptor (descriptors,
579               GST_MTS_DESC_REGISTRATION))) {
580     if (G_UNLIKELY (desc->length < 4)) {
581       GST_WARNING ("Registration descriptor with length < 4. (Corrupted ?)");
582     } else
583       return GST_READ_UINT32_BE (desc->data + 2);
584   }
585
586   return 0;
587 }
588
589 static gboolean
590 find_registration_in_descriptors (GPtrArray * descriptors,
591     guint32 registration_id)
592 {
593
594   guint i, nb_desc;
595
596   if (!descriptors)
597     return FALSE;
598
599   nb_desc = descriptors->len;
600   for (i = 0; i < nb_desc; i++) {
601     GstMpegtsDescriptor *desc = g_ptr_array_index (descriptors, i);
602     if (desc->tag == GST_MTS_DESC_REGISTRATION) {
603       guint32 reg_desc = GST_READ_UINT32_BE (desc->data + 2);
604       if (reg_desc == registration_id)
605         return TRUE;
606     }
607   }
608   return FALSE;
609 }
610
611 static MpegTSBaseStream *
612 mpegts_base_program_add_stream (MpegTSBase * base,
613     MpegTSBaseProgram * program, guint16 pid, guint8 stream_type,
614     GstMpegtsPMTStream * stream)
615 {
616   MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
617   MpegTSBaseStream *bstream;
618
619   GST_DEBUG ("pid:0x%04x, stream_type:0x%03x", pid, stream_type);
620
621   /* FIXME : PID information/nature might change through time.
622    * We therefore *do* want to be able to replace an existing stream
623    * with updated information */
624   if (G_UNLIKELY (program->streams[pid])) {
625     if (stream_type != 0xff)
626       GST_WARNING ("Stream already present !");
627     return NULL;
628   }
629
630   bstream = g_malloc0 (base->stream_size);
631   bstream->stream_id =
632       g_strdup_printf ("%s/%08x",
633       gst_stream_collection_get_upstream_id (program->collection), pid);
634   bstream->pid = pid;
635   bstream->stream_type = stream_type;
636   bstream->stream = stream;
637   /* We don't yet know the stream type, subclasses will fill that */
638   bstream->stream_object = gst_stream_new (bstream->stream_id, NULL,
639       GST_STREAM_TYPE_UNKNOWN, GST_STREAM_FLAG_NONE);
640   if (stream) {
641     bstream->registration_id =
642         get_registration_from_descriptors (stream->descriptors);
643     GST_DEBUG ("PID 0x%04x, registration_id %" SAFE_FOURCC_FORMAT,
644         bstream->pid, SAFE_FOURCC_ARGS (bstream->registration_id));
645   }
646
647   program->streams[pid] = bstream;
648   program->stream_list = g_list_append (program->stream_list, bstream);
649
650   if (klass->stream_added)
651     if (klass->stream_added (base, bstream, program)) {
652       gst_stream_collection_add_stream (program->collection,
653           (GstStream *) gst_object_ref (bstream->stream_object));
654       bstream->in_collection = TRUE;
655     }
656
657
658   return bstream;
659 }
660
661 static void
662 mpegts_base_program_remove_stream (MpegTSBase * base,
663     MpegTSBaseProgram * program, guint16 pid)
664 {
665   MpegTSBaseClass *klass;
666   MpegTSBaseStream *stream = program->streams[pid];
667
668   GST_DEBUG ("pid:0x%04x", pid);
669
670   if (G_UNLIKELY (stream == NULL)) {
671     /* Can happen if the PCR PID is the same as a audio/video PID */
672     GST_DEBUG ("Stream already removed");
673     return;
674   }
675
676   klass = GST_MPEGTS_BASE_GET_CLASS (base);
677
678   /* If subclass needs it, inform it of the stream we are about to remove */
679   if (klass->stream_removed)
680     klass->stream_removed (base, stream);
681
682   program->stream_list = g_list_remove_all (program->stream_list, stream);
683   mpegts_base_free_stream (stream);
684   program->streams[pid] = NULL;
685 }
686
687 /* Check if pmtstream is already present in the program */
688 static inline gboolean
689 _stream_in_pmt (const GstMpegtsPMT * pmt, MpegTSBaseStream * stream)
690 {
691   guint i, nbstreams = pmt->streams->len;
692
693   for (i = 0; i < nbstreams; i++) {
694     GstMpegtsPMTStream *pmt_stream = g_ptr_array_index (pmt->streams, i);
695
696     if (pmt_stream->pid == stream->pid &&
697         pmt_stream->stream_type == stream->stream_type)
698       return TRUE;
699   }
700
701   return FALSE;
702 }
703
704 static inline gboolean
705 _pmt_stream_in_program (MpegTSBaseProgram * program,
706     GstMpegtsPMTStream * stream)
707 {
708   MpegTSBaseStream *old_stream = program->streams[stream->pid];
709   if (!old_stream)
710     return FALSE;
711   return old_stream->stream_type == stream->stream_type;
712 }
713
714 static gboolean
715 mpegts_base_update_program (MpegTSBase * base, MpegTSBaseProgram * program,
716     GstMpegtsSection * section, const GstMpegtsPMT * pmt)
717 {
718   MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
719   const gchar *stream_id =
720       gst_stream_collection_get_upstream_id (program->collection);
721   GstStreamCollection *collection;
722   GList *tmp, *toremove;
723   guint i, nbstreams;
724
725   /* Create new collection */
726   collection = gst_stream_collection_new (stream_id);
727   gst_object_unref (program->collection);
728   program->collection = collection;
729
730   /* Replace section and pmt with the new one */
731   gst_mpegts_section_unref (program->section);
732   program->section = gst_mpegts_section_ref (section);
733   program->pmt = pmt;
734
735   /* Copy over gststream that still exist into the collection */
736   for (tmp = program->stream_list; tmp; tmp = tmp->next) {
737     MpegTSBaseStream *stream = (MpegTSBaseStream *) tmp->data;
738     if (_stream_in_pmt (pmt, stream) && stream->in_collection) {
739       gst_stream_collection_add_stream (program->collection,
740           gst_object_ref (stream->stream_object));
741     }
742   }
743
744   /* Add new streams (will also create and add gststream to the collection) */
745   nbstreams = pmt->streams->len;
746   for (i = 0; i < nbstreams; i++) {
747     GstMpegtsPMTStream *stream = g_ptr_array_index (pmt->streams, i);
748     if (!_pmt_stream_in_program (program, stream)) {
749 #ifdef TIZEN_FEATURE_TSDEMUX_UPDATE_STREAM
750       if (G_UNLIKELY (MPEGTS_BIT_IS_SET (base->is_pes, stream->pid)))
751         GST_FIXME
752             ("Refcounting issue. Setting twice a PID (0x%04x) as known PES",
753             stream->pid);
754       if (G_UNLIKELY (MPEGTS_BIT_IS_SET (base->known_psi, stream->pid))) {
755         GST_FIXME
756             ("Refcounting issue. Setting a known PSI PID (0x%04x) as known PES",
757             stream->pid);
758         MPEGTS_BIT_UNSET (base->known_psi, stream->pid);
759       }
760       MPEGTS_BIT_SET (base->is_pes, stream->pid);
761 #endif
762       mpegts_base_program_add_stream (base, program, stream->pid,
763           stream->stream_type, stream);
764     }
765   }
766
767   /* Call subclass update */
768   if (klass->update_program)
769     klass->update_program (base, program);
770
771   /* Remove streams no longer present */
772   toremove = NULL;
773   for (tmp = program->stream_list; tmp; tmp = tmp->next) {
774     MpegTSBaseStream *stream = (MpegTSBaseStream *) tmp->data;
775     if (!_stream_in_pmt (pmt, stream))
776       toremove = g_list_prepend (toremove, stream);
777   }
778   for (tmp = toremove; tmp; tmp = tmp->next) {
779     MpegTSBaseStream *stream = (MpegTSBaseStream *) tmp->data;
780 #ifdef TIZEN_FEATURE_TSDEMUX_UPDATE_STREAM
781     MPEGTS_BIT_UNSET (base->is_pes, stream->pid);
782 #endif
783     mpegts_base_program_remove_stream (base, program, stream->pid);
784   }
785   g_list_free (toremove);
786   return TRUE;
787 }
788
789
790 static gboolean
791 _stream_is_private_section (const GstMpegtsPMT * pmt,
792     GstMpegtsPMTStream * stream)
793 {
794   switch (stream->stream_type) {
795     case GST_MPEGTS_STREAM_TYPE_SCTE_DSMCC_DCB:
796     case GST_MPEGTS_STREAM_TYPE_SCTE_SIGNALING:
797     {
798       guint32 registration_id =
799           get_registration_from_descriptors (stream->descriptors);
800       /* Not a private section stream */
801       if (registration_id != DRF_ID_CUEI && registration_id != DRF_ID_ETV1)
802         return FALSE;
803     }
804     case GST_MPEGTS_STREAM_TYPE_PRIVATE_SECTIONS:
805     case GST_MPEGTS_STREAM_TYPE_MHEG:
806     case GST_MPEGTS_STREAM_TYPE_DSM_CC:
807     case GST_MPEGTS_STREAM_TYPE_DSMCC_A:
808     case GST_MPEGTS_STREAM_TYPE_DSMCC_B:
809     case GST_MPEGTS_STREAM_TYPE_DSMCC_C:
810     case GST_MPEGTS_STREAM_TYPE_DSMCC_D:
811     case GST_MPEGTS_STREAM_TYPE_SL_FLEXMUX_SECTIONS:
812     case GST_MPEGTS_STREAM_TYPE_METADATA_SECTIONS:
813       /* known PSI streams */
814       return TRUE;
815     case GST_MPEGTS_STREAM_TYPE_SCTE_SIT:
816     {
817       /* Not a private section stream */
818       if (!find_registration_in_descriptors (pmt->descriptors, DRF_ID_CUEI))
819         return FALSE;
820       return TRUE;
821     }
822     default:
823       return FALSE;
824   }
825 }
826
827 /* Return TRUE if programs are equal */
828 static gboolean
829 mpegts_base_is_same_program (MpegTSBase * base, MpegTSBaseProgram * oldprogram,
830     guint16 new_pmt_pid, const GstMpegtsPMT * new_pmt)
831 {
832   guint i, nbstreams;
833   MpegTSBaseStream *oldstream;
834   gboolean sawpcrpid = FALSE;
835
836   if (oldprogram->pmt_pid != new_pmt_pid) {
837     GST_DEBUG ("Different pmt_pid (new:0x%04x, old:0x%04x)", new_pmt_pid,
838         oldprogram->pmt_pid);
839     return FALSE;
840   }
841
842   if (!base->ignore_pcr && oldprogram->pcr_pid != new_pmt->pcr_pid) {
843     GST_DEBUG ("Different pcr_pid (new:0x%04x, old:0x%04x)",
844         new_pmt->pcr_pid, oldprogram->pcr_pid);
845     return FALSE;
846   }
847
848   /* Check the streams */
849   nbstreams = new_pmt->streams->len;
850   for (i = 0; i < nbstreams; ++i) {
851     GstMpegtsPMTStream *stream = g_ptr_array_index (new_pmt->streams, i);
852
853     oldstream = oldprogram->streams[stream->pid];
854     if (!oldstream) {
855       GST_DEBUG ("New stream 0x%04x not present in old program", stream->pid);
856       return FALSE;
857     }
858     if (oldstream->stream_type != stream->stream_type) {
859       GST_DEBUG
860           ("New stream 0x%04x has a different stream type (new:%d, old:%d)",
861           stream->pid, stream->stream_type, oldstream->stream_type);
862       return FALSE;
863     }
864     if (stream->pid == oldprogram->pcr_pid)
865       sawpcrpid = TRUE;
866   }
867
868   /* If we have a PCR PID and the pcr is not shared with an existing stream, we'll have one extra stream */
869   if (!sawpcrpid && !base->ignore_pcr)
870     nbstreams += 1;
871
872   if (nbstreams != g_list_length (oldprogram->stream_list)) {
873     GST_DEBUG ("Different number of streams (new:%d, old:%d)",
874         nbstreams, g_list_length (oldprogram->stream_list));
875     return FALSE;
876   }
877
878   GST_DEBUG ("Programs are equal");
879   return TRUE;
880 }
881
882 /* Return TRUE if program is an update
883  *
884  * A program is equal if:
885  * * The program number is the same (will be if it enters this function)
886  * * AND The PMT PID is equal to the old one
887  * * AND It contains at least one stream from the previous program
888  *
889  * Changes that are acceptable are therefore:
890  * * New streams appearing
891  * * Old streams going away
892  * * PCR PID changing
893  *
894  * Unclear changes:
895  * * PMT PID being changed ?
896  * * Properties of elementary stream being changed ? (new tags ? metadata ?)
897  */
898 static gboolean
899 mpegts_base_is_program_update (MpegTSBase * base,
900     MpegTSBaseProgram * oldprogram, guint16 new_pmt_pid,
901     const GstMpegtsPMT * new_pmt)
902 {
903   guint i, nbstreams;
904   MpegTSBaseStream *oldstream;
905
906   if (oldprogram->pmt_pid != new_pmt_pid) {
907     /* FIXME/CHECK: Can a program be updated by just changing its PID
908      * in the PAT ? */
909     GST_DEBUG ("Different pmt_pid (new:0x%04x, old:0x%04x)", new_pmt_pid,
910         oldprogram->pmt_pid);
911     return FALSE;
912   }
913
914   /* Check if at least one stream from the previous program is still present
915    * in the new program */
916
917   /* Check the streams */
918   nbstreams = new_pmt->streams->len;
919   for (i = 0; i < nbstreams; ++i) {
920     GstMpegtsPMTStream *stream = g_ptr_array_index (new_pmt->streams, i);
921
922     oldstream = oldprogram->streams[stream->pid];
923     if (!oldstream) {
924       GST_DEBUG ("New stream 0x%04x not present in old program", stream->pid);
925     } else if (oldstream->stream_type != stream->stream_type) {
926       GST_DEBUG
927           ("New stream 0x%04x has a different stream type (new:%d, old:%d)",
928           stream->pid, stream->stream_type, oldstream->stream_type);
929     } else if (!_stream_is_private_section (new_pmt, stream)) {
930       /* FIXME : We should actually be checking a bit deeper,
931        * especially for private streams (where the differentiation is
932        * done at the registration level) */
933       GST_DEBUG
934           ("Stream 0x%04x is identical (stream_type %d) ! Program is an update",
935           stream->pid, stream->stream_type);
936       return TRUE;
937     }
938   }
939
940   GST_DEBUG ("Program is not an update of the previous one");
941   return FALSE;
942 }
943
944 static void
945 mpegts_base_deactivate_program (MpegTSBase * base, MpegTSBaseProgram * program)
946 {
947   gint i;
948   MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
949
950   if (G_UNLIKELY (program->active == FALSE))
951     return;
952
953   GST_DEBUG_OBJECT (base, "Deactivating PMT");
954
955   program->active = FALSE;
956
957   if (program->pmt) {
958     for (i = 0; i < program->pmt->streams->len; ++i) {
959       GstMpegtsPMTStream *stream = g_ptr_array_index (program->pmt->streams, i);
960
961       mpegts_base_program_remove_stream (base, program, stream->pid);
962
963       /* Only unset the is_pes/known_psi bit if the PID isn't used in any other active
964        * program */
965       if (!mpegts_pid_in_active_programs (base, stream->pid)) {
966         if (_stream_is_private_section (program->pmt, stream)) {
967           if (base->parse_private_sections)
968             MPEGTS_BIT_UNSET (base->known_psi, stream->pid);
969         } else {
970           MPEGTS_BIT_UNSET (base->is_pes, stream->pid);
971         }
972       }
973     }
974
975     /* remove pcr stream */
976     /* FIXME : This might actually be shared with another stream ? */
977     mpegts_base_program_remove_stream (base, program, program->pcr_pid);
978     if (!mpegts_pid_in_active_programs (base, program->pcr_pid))
979       MPEGTS_BIT_UNSET (base->is_pes, program->pcr_pid);
980
981     GST_DEBUG ("program stream_list is now %p", program->stream_list);
982   }
983
984   /* Inform subclasses we're deactivating this program */
985   if (klass->program_stopped)
986     klass->program_stopped (base, program);
987 }
988
989 static void
990 mpegts_base_activate_program (MpegTSBase * base, MpegTSBaseProgram * program,
991     guint16 pmt_pid, GstMpegtsSection * section, const GstMpegtsPMT * pmt,
992     gboolean initial_program)
993 {
994   guint i;
995   MpegTSBaseClass *klass;
996
997   if (G_UNLIKELY (program->active))
998     return;
999
1000   GST_DEBUG ("Activating program %d", program->program_number);
1001
1002   /* activate new pmt */
1003   if (program->section)
1004     gst_mpegts_section_unref (program->section);
1005   program->section = gst_mpegts_section_ref (section);
1006
1007   program->pmt = pmt;
1008   program->pmt_pid = pmt_pid;
1009   if (!base->ignore_pcr)
1010     program->pcr_pid = pmt->pcr_pid;
1011   else
1012     program->pcr_pid = 0x1fff;
1013
1014   /* extract top-level registration_id if present */
1015   program->registration_id =
1016       get_registration_from_descriptors (pmt->descriptors);
1017   GST_DEBUG ("program 0x%04x, registration_id %" SAFE_FOURCC_FORMAT,
1018       program->program_number, SAFE_FOURCC_ARGS (program->registration_id));
1019
1020   for (i = 0; i < pmt->streams->len; ++i) {
1021     GstMpegtsPMTStream *stream = g_ptr_array_index (pmt->streams, i);
1022     if (_stream_is_private_section (pmt, stream)) {
1023       if (base->parse_private_sections)
1024         MPEGTS_BIT_SET (base->known_psi, stream->pid);
1025     } else {
1026       if (G_UNLIKELY (MPEGTS_BIT_IS_SET (base->is_pes, stream->pid)))
1027         GST_FIXME
1028             ("Refcounting issue. Setting twice a PID (0x%04x) as known PES",
1029             stream->pid);
1030       if (G_UNLIKELY (MPEGTS_BIT_IS_SET (base->known_psi, stream->pid))) {
1031         GST_FIXME
1032             ("Refcounting issue. Setting a known PSI PID (0x%04x) as known PES",
1033             stream->pid);
1034         MPEGTS_BIT_UNSET (base->known_psi, stream->pid);
1035       }
1036       MPEGTS_BIT_SET (base->is_pes, stream->pid);
1037     }
1038     mpegts_base_program_add_stream (base, program,
1039         stream->pid, stream->stream_type, stream);
1040   }
1041   /* We add the PCR pid last. If that PID is already used by one of the media
1042    * streams above, no new stream will be created */
1043   mpegts_base_program_add_stream (base, program, program->pcr_pid, -1, NULL);
1044   MPEGTS_BIT_SET (base->is_pes, program->pcr_pid);
1045
1046   program->active = TRUE;
1047   program->initial_program = initial_program;
1048
1049   klass = GST_MPEGTS_BASE_GET_CLASS (base);
1050   if (klass->program_started != NULL)
1051     klass->program_started (base, program);
1052
1053   GST_DEBUG_OBJECT (base, "new pmt activated");
1054 }
1055
1056
1057 static gboolean
1058 mpegts_base_apply_pat (MpegTSBase * base, GstMpegtsSection * section)
1059 {
1060   GPtrArray *pat = gst_mpegts_section_get_pat (section);
1061   GPtrArray *old_pat;
1062   MpegTSBaseProgram *program;
1063   gint i;
1064
1065   if (G_UNLIKELY (pat == NULL))
1066     return FALSE;
1067
1068   GST_INFO_OBJECT (base, "PAT");
1069
1070   /* Applying a new PAT does two things:
1071    * * It adds the new programs to the list of programs this element handles
1072    *   and increments at the same time the number of times a program is referenced.
1073    *
1074    * * If there was a previously active PAT, It decrements the reference count
1075    *   of all program it used. If a program is no longer needed, it is removed.
1076    */
1077
1078   old_pat = base->pat;
1079   base->pat = pat;
1080
1081   GST_LOG ("Activating new Program Association Table");
1082   /* activate the new table */
1083   for (i = 0; i < pat->len; ++i) {
1084     GstMpegtsPatProgram *patp = g_ptr_array_index (pat, i);
1085
1086     GST_LOG ("Looking for program %d / 0x%04x", patp->program_number,
1087         patp->network_or_program_map_PID);
1088     program = mpegts_base_get_program (base, patp->program_number);
1089     if (program) {
1090       GST_LOG ("Program exists on pid 0x%04x", program->pmt_pid);
1091       /* If the new PMT PID clashes with an existing known PES stream, we know
1092        * it is not an update */
1093       if (MPEGTS_BIT_IS_SET (base->is_pes, patp->network_or_program_map_PID)) {
1094         GST_LOG ("Program is not an update");
1095         program =
1096             mpegts_base_add_program (base, patp->program_number,
1097             patp->network_or_program_map_PID);
1098       } else if (program->pmt_pid != patp->network_or_program_map_PID) {
1099         /* IF the program already existed, just check if the PMT PID changed */
1100         GST_LOG ("PMT is on a different PID");
1101         if (program->pmt_pid != G_MAXUINT16) {
1102           /* pmt pid changed */
1103           /* FIXME: when this happens it may still be pmt pid of another
1104            * program, so setting to False may make it go through expensive
1105            * path in is_psi unnecessarily */
1106           MPEGTS_BIT_UNSET (base->known_psi, program->pmt_pid);
1107         }
1108
1109         program->pmt_pid = patp->network_or_program_map_PID;
1110         if (G_UNLIKELY (MPEGTS_BIT_IS_SET (base->known_psi, program->pmt_pid)))
1111           GST_FIXME
1112               ("Refcounting issue. Setting twice a PMT PID (0x%04x) as know PSI",
1113               program->pmt_pid);
1114         MPEGTS_BIT_SET (base->known_psi, patp->network_or_program_map_PID);
1115 #ifdef TIZEN_FEATURE_TSDEMUX_UPDATE_PMT
1116         MPEGTS_BIT_UNSET (base->is_pes, patp->network_or_program_map_PID);
1117 #endif
1118       } else {
1119         GST_LOG ("Regular program update");
1120       }
1121     } else {
1122       /* Create a new program */
1123       program =
1124           mpegts_base_add_program (base, patp->program_number,
1125           patp->network_or_program_map_PID);
1126     }
1127     /* We mark this program as being referenced by one PAT */
1128     program->patcount += 1;
1129   }
1130
1131   if (old_pat) {
1132     MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
1133     /* deactivate the old table */
1134     GST_LOG ("Deactivating old Program Association Table");
1135
1136     for (i = 0; i < old_pat->len; ++i) {
1137       GstMpegtsPatProgram *patp = g_ptr_array_index (old_pat, i);
1138
1139       program = mpegts_base_get_program (base, patp->program_number);
1140       if (G_UNLIKELY (program == NULL)) {
1141         GST_DEBUG_OBJECT (base, "broken PAT, duplicated entry for program %d",
1142             patp->program_number);
1143         continue;
1144       }
1145
1146       GST_LOG ("Deactivating program %d / 0x%04x", patp->program_number,
1147           patp->network_or_program_map_PID);
1148
1149       if (--program->patcount > 0) {
1150         GST_LOG ("Referenced by new program, keeping");
1151         /* the program has been referenced by the new pat, keep it */
1152         continue;
1153       }
1154
1155       GST_INFO_OBJECT (base, "PAT removing program 0x%04x 0x%04x",
1156           patp->program_number, patp->network_or_program_map_PID);
1157
1158       if (klass->can_remove_program (base, program)) {
1159         mpegts_base_deactivate_program (base, program);
1160         mpegts_base_remove_program (base, program);
1161       } else {
1162         /* sub-class now owns the program and must call
1163          * mpegts_base_deactivate_and_free_program later */
1164         mpegts_base_steal_program (base, patp->program_number);
1165       }
1166       /* FIXME: when this happens it may still be pmt pid of another
1167        * program, so setting to False may make it go through expensive
1168        * path in is_psi unnecessarily */
1169       if (G_UNLIKELY (MPEGTS_BIT_IS_SET (base->known_psi,
1170                   patp->network_or_program_map_PID))) {
1171         GST_FIXME
1172             ("Program refcounting : Setting twice a pid (0x%04x) as known PSI",
1173             patp->network_or_program_map_PID);
1174       }
1175       MPEGTS_BIT_SET (base->known_psi, patp->network_or_program_map_PID);
1176       mpegts_packetizer_remove_stream (base->packetizer,
1177           patp->network_or_program_map_PID);
1178     }
1179
1180     g_ptr_array_unref (old_pat);
1181   }
1182
1183   return TRUE;
1184 }
1185
1186 static gboolean
1187 mpegts_base_apply_pmt (MpegTSBase * base, GstMpegtsSection * section)
1188 {
1189   const GstMpegtsPMT *pmt;
1190   MpegTSBaseProgram *program, *old_program;
1191   guint program_number;
1192   gboolean initial_program = TRUE;
1193
1194   pmt = gst_mpegts_section_get_pmt (section);
1195   if (G_UNLIKELY (pmt == NULL)) {
1196     GST_ERROR ("Could not get PMT (corrupted ?)");
1197     return FALSE;
1198   }
1199
1200   /* FIXME : not so sure this is valid anymore */
1201   if (G_UNLIKELY (base->seen_pat == FALSE)) {
1202     GST_WARNING ("Got pmt without pat first. Returning");
1203     /* remove the stream since we won't get another PMT otherwise */
1204     mpegts_packetizer_remove_stream (base->packetizer, section->pid);
1205     return TRUE;
1206   }
1207
1208   /* Don't attempt to handle pmt without any streams */
1209   if (G_UNLIKELY (pmt->streams->len == 0)) {
1210     GST_WARNING ("Skipping PMT without any entries");
1211     return TRUE;
1212   }
1213
1214   program_number = section->subtable_extension;
1215   GST_DEBUG ("Applying PMT (program_number:%d, pid:0x%04x)",
1216       program_number, section->pid);
1217
1218   /* In order for stream switching to happen properly in decodebin(2),
1219    * we need to first add the new pads (i.e. activate the new program)
1220    * before removing the old ones (i.e. deactivating the old program)
1221    */
1222
1223   old_program = mpegts_base_get_program (base, program_number);
1224   if (G_UNLIKELY (old_program == NULL))
1225     goto no_program;
1226
1227   if (G_UNLIKELY (mpegts_base_is_same_program (base, old_program, section->pid,
1228               pmt)))
1229     goto same_program;
1230
1231   if (base->streams_aware
1232       && mpegts_base_is_program_update (base, old_program, section->pid, pmt)) {
1233     GST_FIXME ("We are streams_aware and new program is an update");
1234     /* The program is an update, and we can add/remove pads dynamically */
1235     mpegts_base_update_program (base, old_program, section, pmt);
1236     goto beach;
1237   }
1238
1239   /* If the current program is active, this means we have a new program */
1240   if (old_program->active) {
1241     MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
1242     old_program = mpegts_base_steal_program (base, program_number);
1243     program = mpegts_base_new_program (base, program_number, section->pid);
1244     program->patcount = old_program->patcount;
1245
1246     /* Deactivate the old program */
1247     /* FIXME : THIS IS BREAKING THE STREAM SWITCHING LOGIC !
1248      *  */
1249     if (klass->can_remove_program (base, old_program)) {
1250       mpegts_base_deactivate_program (base, old_program);
1251       mpegts_base_free_program (old_program);
1252     } else {
1253       /* sub-class now owns the program and must call
1254        * mpegts_base_deactivate_and_free_program later */
1255       mpegts_base_steal_program (base, old_program->program_number);
1256     }
1257     /* Add new program to the programs we track */
1258     g_ptr_array_add (base->programs, program);
1259     initial_program = FALSE;
1260   } else {
1261     GST_DEBUG ("Program update, re-using same program");
1262     program = old_program;
1263   }
1264
1265   /* activate program */
1266   /* Ownership of pmt_info is given to the program */
1267   mpegts_base_activate_program (base, program, section->pid, section, pmt,
1268       initial_program);
1269
1270 beach:
1271   GST_DEBUG ("Done activating program");
1272   return TRUE;
1273
1274 no_program:
1275   {
1276     GST_ERROR ("Attempted to apply a PMT on a program that wasn't created");
1277     return TRUE;
1278   }
1279
1280 same_program:
1281   {
1282     GST_DEBUG ("Not applying identical program");
1283     return TRUE;
1284   }
1285 }
1286
1287 static void
1288 mpegts_base_handle_psi (MpegTSBase * base, GstMpegtsSection * section)
1289 {
1290   gboolean post_message = TRUE;
1291
1292   GST_DEBUG ("Handling PSI (pid: 0x%04x , table_id: 0x%02x)",
1293       section->pid, section->table_id);
1294
1295   switch (section->section_type) {
1296     case GST_MPEGTS_SECTION_PAT:
1297       post_message = mpegts_base_apply_pat (base, section);
1298       if (base->seen_pat == FALSE) {
1299         base->seen_pat = TRUE;
1300         GST_DEBUG ("First PAT offset: %" G_GUINT64_FORMAT, section->offset);
1301         mpegts_packetizer_set_reference_offset (base->packetizer,
1302             section->offset);
1303       }
1304       break;
1305     case GST_MPEGTS_SECTION_PMT:
1306       post_message = mpegts_base_apply_pmt (base, section);
1307       break;
1308     case GST_MPEGTS_SECTION_EIT:
1309       /* some tag xtraction + posting */
1310       post_message = mpegts_base_get_tags_from_eit (base, section);
1311       break;
1312     case GST_MPEGTS_SECTION_ATSC_MGT:
1313       post_message = mpegts_base_parse_atsc_mgt (base, section);
1314       break;
1315     default:
1316       break;
1317   }
1318
1319   /* Give the subclass a chance to look at the section */
1320   if (GST_MPEGTS_BASE_GET_CLASS (base)->handle_psi)
1321     GST_MPEGTS_BASE_GET_CLASS (base)->handle_psi (base, section);
1322
1323   /* Finally post message (if it wasn't corrupted) */
1324   if (post_message)
1325     gst_element_post_message (GST_ELEMENT_CAST (base),
1326         gst_message_new_mpegts_section (GST_OBJECT (base), section));
1327   gst_mpegts_section_unref (section);
1328 }
1329
1330 static gboolean
1331 mpegts_base_parse_atsc_mgt (MpegTSBase * base, GstMpegtsSection * section)
1332 {
1333   const GstMpegtsAtscMGT *mgt;
1334   gint i;
1335
1336   mgt = gst_mpegts_section_get_atsc_mgt (section);
1337   if (G_UNLIKELY (mgt == NULL))
1338     return FALSE;
1339
1340   for (i = 0; i < mgt->tables->len; ++i) {
1341     GstMpegtsAtscMGTTable *table = g_ptr_array_index (mgt->tables, i);
1342
1343     if ((table->table_type >= GST_MPEGTS_ATSC_MGT_TABLE_TYPE_EIT0 &&
1344             table->table_type <= GST_MPEGTS_ATSC_MGT_TABLE_TYPE_EIT127) ||
1345         (table->table_type >= GST_MPEGTS_ATSC_MGT_TABLE_TYPE_ETT0 &&
1346             table->table_type <= GST_MPEGTS_ATSC_MGT_TABLE_TYPE_ETT127)) {
1347       MPEGTS_BIT_SET (base->known_psi, table->pid);
1348     }
1349   }
1350
1351   return TRUE;
1352 }
1353
1354 static gboolean
1355 mpegts_base_get_tags_from_eit (MpegTSBase * base, GstMpegtsSection * section)
1356 {
1357   const GstMpegtsEIT *eit;
1358   guint i;
1359   MpegTSBaseProgram *program;
1360
1361   /* Early exit if it's not from the present/following table_id */
1362   if (section->table_id != GST_MTS_TABLE_ID_EVENT_INFORMATION_ACTUAL_TS_PRESENT
1363       && section->table_id !=
1364       GST_MTS_TABLE_ID_EVENT_INFORMATION_OTHER_TS_PRESENT)
1365     return TRUE;
1366
1367   eit = gst_mpegts_section_get_eit (section);
1368   if (G_UNLIKELY (eit == NULL))
1369     return FALSE;
1370
1371   program = mpegts_base_get_program (base, section->subtable_extension);
1372
1373   GST_DEBUG
1374       ("program_id:0x%04x, table_id:0x%02x, actual_stream:%d, present_following:%d, program:%p",
1375       section->subtable_extension, section->table_id, eit->actual_stream,
1376       eit->present_following, program);
1377
1378   if (program && eit->present_following) {
1379     for (i = 0; i < eit->events->len; i++) {
1380       GstMpegtsEITEvent *event = g_ptr_array_index (eit->events, i);
1381       const GstMpegtsDescriptor *desc;
1382
1383       if (event->running_status == RUNNING_STATUS_RUNNING) {
1384         program->event_id = event->event_id;
1385         if ((desc =
1386                 gst_mpegts_find_descriptor (event->descriptors,
1387                     GST_MTS_DESC_DVB_SHORT_EVENT))) {
1388           gchar *name = NULL, *text = NULL;
1389
1390           if (gst_mpegts_descriptor_parse_dvb_short_event (desc, NULL, &name,
1391                   &text)) {
1392             if (!program->tags)
1393               program->tags = gst_tag_list_new_empty ();
1394
1395             if (name) {
1396               gst_tag_list_add (program->tags, GST_TAG_MERGE_APPEND,
1397                   GST_TAG_TITLE, name, NULL);
1398               g_free (name);
1399             }
1400             if (text) {
1401               gst_tag_list_add (program->tags, GST_TAG_MERGE_APPEND,
1402                   GST_TAG_DESCRIPTION, text, NULL);
1403               g_free (text);
1404             }
1405             /* FIXME : Is it correct to post an event duration as a GST_TAG_DURATION ??? */
1406             gst_tag_list_add (program->tags, GST_TAG_MERGE_APPEND,
1407                 GST_TAG_DURATION, event->duration * GST_SECOND, NULL);
1408             return TRUE;
1409           }
1410         }
1411       }
1412     }
1413   }
1414
1415   return TRUE;
1416 }
1417
1418 static void
1419 remove_each_program (MpegTSBaseProgram * program, MpegTSBase * base)
1420 {
1421   /* First deactivate it */
1422   mpegts_base_deactivate_program (base, program);
1423 }
1424
1425 static inline GstFlowReturn
1426 mpegts_base_drain (MpegTSBase * base)
1427 {
1428   MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
1429
1430   /* Call implementation */
1431   if (klass->drain)
1432     return klass->drain (base);
1433
1434   return GST_FLOW_OK;
1435 }
1436
1437 static inline void
1438 mpegts_base_flush (MpegTSBase * base, gboolean hard)
1439 {
1440   MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
1441
1442   /* Call implementation */
1443   if (klass->flush)
1444     klass->flush (base, hard);
1445 }
1446
1447 static gboolean
1448 mpegts_base_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
1449 {
1450   gboolean res = TRUE;
1451   gboolean hard;
1452   MpegTSBase *base = GST_MPEGTS_BASE (parent);
1453   gboolean is_sticky = GST_EVENT_IS_STICKY (event);
1454 #ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
1455   GstStructure *structure = NULL;
1456   GstCaps *caps = NULL;
1457   gboolean caps_ret = FALSE;
1458 #endif
1459
1460   GST_DEBUG_OBJECT (base, "Got event %s",
1461       gst_event_type_get_name (GST_EVENT_TYPE (event)));
1462
1463   switch (GST_EVENT_TYPE (event)) {
1464     case GST_EVENT_SEGMENT:
1465       gst_event_copy_segment (event, &base->segment);
1466       GST_DEBUG_OBJECT (base, "Received segment %" GST_SEGMENT_FORMAT,
1467           &base->segment);
1468       /* Check if we need to switch PCR/PTS handling */
1469       if (base->segment.format == GST_FORMAT_TIME) {
1470         base->packetizer->calculate_offset = FALSE;
1471         base->packetizer->calculate_skew = TRUE;
1472         /* Seek was handled upstream */
1473         base->last_seek_seqnum = gst_event_get_seqnum (event);
1474       } else {
1475         base->packetizer->calculate_offset = TRUE;
1476         base->packetizer->calculate_skew = FALSE;
1477       }
1478
1479       res = GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, event);
1480       break;
1481     case GST_EVENT_STREAM_START:
1482       gst_event_unref (event);
1483       break;
1484     case GST_EVENT_CAPS:
1485       /* FIXME, do something */
1486 #ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
1487       if (base->packetizer) {
1488         gst_event_parse_caps (event, &caps);
1489         GST_DEBUG_OBJECT (base, "got caps: %" GST_PTR_FORMAT, caps);
1490
1491         structure = gst_caps_get_structure (caps, 0);
1492         caps_ret = gst_structure_get_boolean (structure, "is_live", &base->packetizer->is_live_stream);
1493         if (caps_ret == FALSE)
1494           base->packetizer->is_live_stream = TRUE;
1495       } else {
1496         GST_DEBUG_OBJECT (base, "base->packetizer pointer is NULL !!!");
1497       }
1498 #endif
1499       gst_event_unref (event);
1500       break;
1501     case GST_EVENT_FLUSH_STOP:
1502       res = GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, event);
1503       hard = (base->mode != BASE_MODE_SEEKING);
1504       mpegts_packetizer_flush (base->packetizer, hard);
1505       mpegts_base_flush (base, hard);
1506       gst_segment_init (&base->segment, GST_FORMAT_UNDEFINED);
1507       base->seen_pat = FALSE;
1508       break;
1509     default:
1510       res = GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, event);
1511   }
1512
1513   /* Always return TRUE for sticky events */
1514   if (is_sticky)
1515     res = TRUE;
1516
1517   return res;
1518 }
1519
1520 static gboolean
1521 mpegts_base_default_sink_query (MpegTSBase * base, GstQuery * query)
1522 {
1523   return gst_pad_query_default (base->sinkpad, GST_OBJECT (base), query);
1524 }
1525
1526 static gboolean
1527 mpegts_base_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
1528 {
1529   MpegTSBase *base = GST_MPEGTS_BASE (parent);
1530
1531   GST_DEBUG_OBJECT (base, "Got query %s",
1532       gst_query_type_get_name (GST_QUERY_TYPE (query)));
1533
1534   return GST_MPEGTS_BASE_GET_CLASS (base)->sink_query (base, query);
1535 }
1536
1537 static GstFlowReturn
1538 mpegts_base_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
1539 {
1540   GstFlowReturn res = GST_FLOW_OK;
1541   MpegTSBase *base;
1542   MpegTSPacketizerPacketReturn pret;
1543   MpegTSPacketizer2 *packetizer;
1544   MpegTSPacketizerPacket packet;
1545   MpegTSBaseClass *klass;
1546
1547   base = GST_MPEGTS_BASE (parent);
1548   klass = GST_MPEGTS_BASE_GET_CLASS (base);
1549
1550   packetizer = base->packetizer;
1551
1552   if (GST_BUFFER_IS_DISCONT (buf)) {
1553     GST_DEBUG_OBJECT (base, "Got DISCONT buffer, flushing");
1554     res = mpegts_base_drain (base);
1555     if (G_UNLIKELY (res != GST_FLOW_OK))
1556       return res;
1557
1558     mpegts_base_flush (base, FALSE);
1559     if (base->mode == BASE_MODE_PUSHING) {
1560       if (base->segment.format == GST_FORMAT_TIME) {
1561         /* In the case of discontinuities in push-mode with TIME segment
1562          * we want to drop all previous observations (hard:TRUE) from
1563          * the packetizer */
1564         mpegts_packetizer_flush (base->packetizer, TRUE);
1565       }
1566       /* In all cases, we clear observations when we get a discontinuity in
1567        * push-mode to re-check if the sections (PAT/PMT) changed or not */
1568       mpegts_packetizer_clear (base->packetizer);
1569     } else {
1570       mpegts_packetizer_flush (base->packetizer, FALSE);
1571     }
1572   }
1573
1574   mpegts_packetizer_push (base->packetizer, buf);
1575
1576   while (res == GST_FLOW_OK) {
1577     pret = mpegts_packetizer_next_packet (base->packetizer, &packet);
1578
1579     /* If we don't have enough data, return */
1580     if (G_UNLIKELY (pret == PACKET_NEED_MORE))
1581       break;
1582
1583     if (G_UNLIKELY (pret == PACKET_BAD)) {
1584       /* bad header, skip the packet */
1585       GST_DEBUG_OBJECT (base, "bad packet, skipping");
1586       goto next;
1587     }
1588
1589     if (klass->inspect_packet)
1590       klass->inspect_packet (base, &packet);
1591
1592     /* If it's a known PES, push it */
1593     if (MPEGTS_BIT_IS_SET (base->is_pes, packet.pid)) {
1594       /* push the packet downstream */
1595       if (base->push_data)
1596         res = klass->push (base, &packet, NULL);
1597     } else if (packet.payload
1598         && MPEGTS_BIT_IS_SET (base->known_psi, packet.pid)) {
1599       /* base PSI data */
1600       GList *others, *tmp;
1601       GstMpegtsSection *section;
1602
1603       section = mpegts_packetizer_push_section (packetizer, &packet, &others);
1604       if (section)
1605         mpegts_base_handle_psi (base, section);
1606       if (G_UNLIKELY (others)) {
1607         for (tmp = others; tmp; tmp = tmp->next)
1608           mpegts_base_handle_psi (base, (GstMpegtsSection *) tmp->data);
1609         g_list_free (others);
1610       }
1611
1612       /* we need to push section packet downstream */
1613       if (base->push_section)
1614         res = klass->push (base, &packet, section);
1615
1616     } else if (base->push_unknown) {
1617       res = klass->push (base, &packet, NULL);
1618     } else if (packet.payload && packet.pid != 0x1fff)
1619       GST_LOG ("PID 0x%04x Saw packet on a pid we don't handle", packet.pid);
1620
1621   next:
1622     mpegts_packetizer_clear_packet (base->packetizer, &packet);
1623   }
1624
1625   if (res == GST_FLOW_OK && klass->input_done)
1626     res = klass->input_done (base);
1627
1628   return res;
1629 }
1630
1631 static GstFlowReturn
1632 mpegts_base_scan (MpegTSBase * base)
1633 {
1634   GstFlowReturn ret = GST_FLOW_OK;
1635   GstBuffer *buf = NULL;
1636   guint i;
1637   gboolean done = FALSE;
1638   MpegTSPacketizerPacketReturn pret;
1639   gint64 tmpval;
1640   gint64 upstream_size, seek_pos, reverse_limit;
1641   GstFormat format;
1642   guint initial_pcr_seen;
1643
1644   GST_DEBUG ("Scanning for initial sync point");
1645
1646   /* Find initial sync point and at least 5 PCR values */
1647   for (i = 0; i < 20 && !done; i++) {
1648     GST_DEBUG ("Grabbing %d => %d", i * 65536, (i + 1) * 65536);
1649
1650     ret = gst_pad_pull_range (base->sinkpad, i * 65536, 65536, &buf);
1651     if (G_UNLIKELY (ret == GST_FLOW_EOS))
1652       break;
1653     if (G_UNLIKELY (ret != GST_FLOW_OK))
1654       goto beach;
1655
1656     /* Push to packetizer */
1657     mpegts_packetizer_push (base->packetizer, buf);
1658     buf = NULL;
1659
1660     if (mpegts_packetizer_has_packets (base->packetizer)) {
1661       if (base->seek_offset == -1) {
1662         /* Mark the initial sync point and remember the packetsize */
1663         base->seek_offset = base->packetizer->offset;
1664         GST_DEBUG ("Sync point is now %" G_GUINT64_FORMAT, base->seek_offset);
1665         base->packetsize = base->packetizer->packet_size;
1666       }
1667       while (1) {
1668         /* Eat up all packets */
1669         pret = mpegts_packetizer_process_next_packet (base->packetizer);
1670         if (pret == PACKET_NEED_MORE)
1671           break;
1672         if (pret != PACKET_BAD && base->packetizer->nb_seen_offsets >= 5) {
1673           GST_DEBUG ("Got enough initial PCR");
1674           done = TRUE;
1675           break;
1676         }
1677       }
1678     }
1679   }
1680
1681   initial_pcr_seen = base->packetizer->nb_seen_offsets;
1682   if (G_UNLIKELY (initial_pcr_seen == 0))
1683     goto no_initial_pcr;
1684   GST_DEBUG ("Seen %d initial PCR", initial_pcr_seen);
1685
1686   /* Now send data from the end */
1687
1688   /* Get the size of upstream */
1689   format = GST_FORMAT_BYTES;
1690   if (!gst_pad_peer_query_duration (base->sinkpad, format, &tmpval))
1691     goto beach;
1692   upstream_size = tmpval;
1693
1694   /* The scanning takes place on the last 2048kB. Considering PCR should
1695    * be present at least every 100ms, this should cope with streams
1696    * up to 160Mbit/s */
1697   reverse_limit = MAX (0, upstream_size - 2097152);
1698
1699   /* Find last PCR value, searching backwards by chunks of 300 MPEG-ts packets */
1700   for (seek_pos = MAX (0, upstream_size - 56400);
1701       seek_pos >= reverse_limit; seek_pos -= 56400) {
1702     mpegts_packetizer_clear (base->packetizer);
1703     GST_DEBUG ("Grabbing %" G_GUINT64_FORMAT " => %" G_GUINT64_FORMAT, seek_pos,
1704         seek_pos + 56400);
1705
1706     ret = gst_pad_pull_range (base->sinkpad, seek_pos, 56400, &buf);
1707     if (G_UNLIKELY (ret == GST_FLOW_EOS))
1708       break;
1709     if (G_UNLIKELY (ret != GST_FLOW_OK))
1710       goto beach;
1711
1712     /* Push to packetizer */
1713     mpegts_packetizer_push (base->packetizer, buf);
1714     buf = NULL;
1715
1716     if (mpegts_packetizer_has_packets (base->packetizer)) {
1717       pret = PACKET_OK;
1718       /* Eat up all packets, really try to get last PCR(s) */
1719       while (pret != PACKET_NEED_MORE)
1720         pret = mpegts_packetizer_process_next_packet (base->packetizer);
1721
1722       if (base->packetizer->nb_seen_offsets > initial_pcr_seen) {
1723         GST_DEBUG ("Got last PCR(s) (total seen:%d)",
1724             base->packetizer->nb_seen_offsets);
1725         break;
1726       }
1727     }
1728   }
1729
1730 beach:
1731   mpegts_packetizer_clear (base->packetizer);
1732   return ret;
1733
1734 no_initial_pcr:
1735   mpegts_packetizer_clear (base->packetizer);
1736   GST_WARNING_OBJECT (base, "Couldn't find any PCR within the first %d bytes",
1737       10 * 65536);
1738   return GST_FLOW_OK;
1739 }
1740
1741
1742 static void
1743 mpegts_base_loop (MpegTSBase * base)
1744 {
1745   GstFlowReturn ret = GST_FLOW_ERROR;
1746
1747   switch (base->mode) {
1748     case BASE_MODE_SCANNING:
1749       /* Find first sync point */
1750       ret = mpegts_base_scan (base);
1751       if (G_UNLIKELY (ret != GST_FLOW_OK))
1752         goto error;
1753       base->mode = BASE_MODE_STREAMING;
1754       GST_DEBUG ("Changing to Streaming");
1755       break;
1756     case BASE_MODE_SEEKING:
1757       /* FIXME : unclear if we still need mode_seeking... */
1758       base->mode = BASE_MODE_STREAMING;
1759       break;
1760     case BASE_MODE_STREAMING:
1761     {
1762       GstBuffer *buf = NULL;
1763
1764       GST_DEBUG ("Pulling data from %" G_GUINT64_FORMAT, base->seek_offset);
1765
1766       if (G_UNLIKELY (base->last_seek_seqnum == GST_SEQNUM_INVALID)) {
1767         /* No configured seek, set a valid seqnum */
1768         base->last_seek_seqnum = gst_util_seqnum_next ();
1769       }
1770       ret = gst_pad_pull_range (base->sinkpad, base->seek_offset,
1771           100 * base->packetsize, &buf);
1772       if (G_UNLIKELY (ret != GST_FLOW_OK))
1773         goto error;
1774       base->seek_offset += gst_buffer_get_size (buf);
1775       ret = mpegts_base_chain (base->sinkpad, GST_OBJECT_CAST (base), buf);
1776       if (G_UNLIKELY (ret != GST_FLOW_OK))
1777         goto error;
1778     }
1779       break;
1780     case BASE_MODE_PUSHING:
1781       GST_WARNING ("wrong BASE_MODE_PUSHING mode in pull loop");
1782       break;
1783   }
1784
1785   return;
1786
1787 error:
1788   {
1789     GST_DEBUG_OBJECT (base, "Pausing task, reason %s", gst_flow_get_name (ret));
1790     if (ret == GST_FLOW_EOS) {
1791       if (!GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base,
1792               gst_event_new_eos ()))
1793         GST_ELEMENT_ERROR (base, STREAM, FAILED,
1794             (_("Internal data stream error.")),
1795             ("No program activated before EOS"));
1796     } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
1797       GST_ELEMENT_FLOW_ERROR (base, ret);
1798       GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, gst_event_new_eos ());
1799     }
1800     gst_pad_pause_task (base->sinkpad);
1801   }
1802 }
1803
1804
1805 gboolean
1806 mpegts_base_handle_seek_event (MpegTSBase * base, GstPad * pad,
1807     GstEvent * event)
1808 {
1809   MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
1810   GstFlowReturn ret = GST_FLOW_ERROR;
1811   gdouble rate;
1812   gboolean flush, instant_rate_change;
1813   GstFormat format;
1814   GstSeekFlags flags;
1815   GstSeekType start_type, stop_type;
1816   gint64 start, stop;
1817   GstEvent *flush_event = NULL;
1818
1819   gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
1820       &stop_type, &stop);
1821
1822   if (format != GST_FORMAT_TIME)
1823     return FALSE;
1824
1825   if (GST_EVENT_SEQNUM (event) == base->last_seek_seqnum) {
1826     GST_DEBUG_OBJECT (base, "Skipping already handled seek");
1827     return TRUE;
1828   }
1829
1830   if (base->mode == BASE_MODE_PUSHING) {
1831     /* First try if upstream supports seeking in TIME format */
1832     if (gst_pad_push_event (base->sinkpad, gst_event_ref (event))) {
1833       GST_DEBUG ("upstream handled SEEK event");
1834       return TRUE;
1835     }
1836
1837     /* If the subclass can seek, do that */
1838     if (klass->seek) {
1839       ret = klass->seek (base, event);
1840       if (G_UNLIKELY (ret != GST_FLOW_OK))
1841         GST_WARNING ("seeking failed %s", gst_flow_get_name (ret));
1842       else {
1843         GstEvent *new_seek;
1844
1845         if (GST_CLOCK_TIME_IS_VALID (base->seek_offset)) {
1846           base->mode = BASE_MODE_SEEKING;
1847           new_seek = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags,
1848               GST_SEEK_TYPE_SET, base->seek_offset, GST_SEEK_TYPE_NONE, -1);
1849           gst_event_set_seqnum (new_seek, GST_EVENT_SEQNUM (event));
1850           if (!gst_pad_push_event (base->sinkpad, new_seek))
1851             ret = GST_FLOW_ERROR;
1852           else
1853             base->last_seek_seqnum = GST_EVENT_SEQNUM (event);
1854         }
1855         base->mode = BASE_MODE_PUSHING;
1856       }
1857     } else {
1858       GST_WARNING ("subclass has no seek implementation");
1859     }
1860
1861     return ret == GST_FLOW_OK;
1862   }
1863
1864   if (!klass->seek) {
1865     GST_WARNING ("subclass has no seek implementation");
1866     return FALSE;
1867   }
1868
1869   if (rate <= 0.0) {
1870     GST_WARNING ("Negative rate not supported");
1871     return FALSE;
1872   }
1873
1874   GST_DEBUG ("seek event, rate: %f start: %" GST_TIME_FORMAT
1875       " stop: %" GST_TIME_FORMAT, rate, GST_TIME_ARGS (start),
1876       GST_TIME_ARGS (stop));
1877
1878   flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
1879   instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1880
1881   /* Directly send the instant-rate-change event here before taking the
1882    * stream-lock so that it can be applied as soon as possible */
1883   if (base->mode != BASE_MODE_PUSHING && instant_rate_change) {
1884     GstEvent *ev;
1885
1886     /* instant rate change only supported if direction does not change. All
1887      * other requirements are already checked before creating the seek event
1888      * but let's double-check here to be sure */
1889     if ((rate > 0 && base->out_segment.rate < 0) ||
1890         (rate < 0 && base->out_segment.rate > 0) ||
1891         start_type != GST_SEEK_TYPE_NONE ||
1892         stop_type != GST_SEEK_TYPE_NONE || flush) {
1893       GST_ERROR_OBJECT (base,
1894           "Instant rate change seeks only supported in the "
1895           "same direction, without flushing and position change");
1896       return FALSE;
1897     }
1898
1899     ev = gst_event_new_instant_rate_change (rate / base->out_segment.rate,
1900         (GstSegmentFlags) (flags));
1901     gst_event_set_seqnum (ev, GST_EVENT_SEQNUM (event));
1902     GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, ev);
1903     return TRUE;
1904   }
1905
1906   /* stop streaming, either by flushing or by pausing the task */
1907   base->mode = BASE_MODE_SEEKING;
1908   if (flush) {
1909     GST_DEBUG_OBJECT (base, "sending flush start");
1910     flush_event = gst_event_new_flush_start ();
1911     gst_event_set_seqnum (flush_event, GST_EVENT_SEQNUM (event));
1912     gst_pad_push_event (base->sinkpad, gst_event_ref (flush_event));
1913     GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, flush_event);
1914   } else
1915     gst_pad_pause_task (base->sinkpad);
1916
1917   /* wait for streaming to finish */
1918   GST_PAD_STREAM_LOCK (base->sinkpad);
1919
1920   if (flush) {
1921     /* send a FLUSH_STOP for the sinkpad, since we need data for seeking */
1922     GST_DEBUG_OBJECT (base, "sending flush stop");
1923     flush_event = gst_event_new_flush_stop (TRUE);
1924     gst_event_set_seqnum (flush_event, GST_EVENT_SEQNUM (event));
1925
1926     /* ref for it to be reused later */
1927     gst_pad_push_event (base->sinkpad, gst_event_ref (flush_event));
1928     /* And actually flush our pending data but allow to preserve some info
1929      * to perform the seek */
1930     mpegts_base_flush (base, FALSE);
1931     mpegts_packetizer_flush (base->packetizer, FALSE);
1932   }
1933
1934   if (flags & (GST_SEEK_FLAG_SEGMENT)) {
1935     GST_WARNING ("seek flags 0x%x are not supported", (int) flags);
1936     goto done;
1937   }
1938
1939
1940   /* If the subclass can seek, do that */
1941   ret = klass->seek (base, event);
1942   if (G_UNLIKELY (ret != GST_FLOW_OK))
1943     GST_WARNING ("seeking failed %s", gst_flow_get_name (ret));
1944   else
1945     base->last_seek_seqnum = GST_EVENT_SEQNUM (event);
1946
1947   if (flush_event) {
1948     /* if we sent a FLUSH_START, we now send a FLUSH_STOP */
1949     GST_DEBUG_OBJECT (base, "sending flush stop");
1950     GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, flush_event);
1951     flush_event = NULL;
1952   }
1953 done:
1954   if (flush_event)
1955     gst_event_unref (flush_event);
1956   gst_pad_start_task (base->sinkpad, (GstTaskFunction) mpegts_base_loop, base,
1957       NULL);
1958
1959   GST_PAD_STREAM_UNLOCK (base->sinkpad);
1960   return ret == GST_FLOW_OK;
1961 }
1962
1963
1964 static gboolean
1965 mpegts_base_sink_activate (GstPad * sinkpad, GstObject * parent)
1966 {
1967   GstQuery *query;
1968   gboolean pull_mode;
1969
1970   query = gst_query_new_scheduling ();
1971
1972   if (!gst_pad_peer_query (sinkpad, query)) {
1973     gst_query_unref (query);
1974     goto activate_push;
1975   }
1976
1977   pull_mode = gst_query_has_scheduling_mode_with_flags (query,
1978       GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
1979   gst_query_unref (query);
1980
1981   if (!pull_mode)
1982     goto activate_push;
1983
1984   GST_DEBUG_OBJECT (sinkpad, "activating pull");
1985   return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
1986
1987 activate_push:
1988   {
1989     GST_DEBUG_OBJECT (sinkpad, "activating push");
1990     return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
1991   }
1992 }
1993
1994 static gboolean
1995 mpegts_base_sink_activate_mode (GstPad * pad, GstObject * parent,
1996     GstPadMode mode, gboolean active)
1997 {
1998   gboolean res;
1999   MpegTSBase *base = GST_MPEGTS_BASE (parent);
2000
2001   switch (mode) {
2002     case GST_PAD_MODE_PUSH:
2003       base->mode = BASE_MODE_PUSHING;
2004       res = TRUE;
2005       break;
2006     case GST_PAD_MODE_PULL:
2007       if (active) {
2008         base->mode = BASE_MODE_SCANNING;
2009         /* When working pull-based, we always use offsets for estimation */
2010         base->packetizer->calculate_offset = TRUE;
2011         base->packetizer->calculate_skew = FALSE;
2012         gst_segment_init (&base->segment, GST_FORMAT_BYTES);
2013         res =
2014             gst_pad_start_task (pad, (GstTaskFunction) mpegts_base_loop, base,
2015             NULL);
2016       } else
2017         res = gst_pad_stop_task (pad);
2018       break;
2019     default:
2020       res = FALSE;
2021       break;
2022   }
2023   return res;
2024 }
2025
2026 static GstStateChangeReturn
2027 mpegts_base_change_state (GstElement * element, GstStateChange transition)
2028 {
2029   MpegTSBase *base;
2030   GstStateChangeReturn ret;
2031
2032   base = GST_MPEGTS_BASE (element);
2033
2034   switch (transition) {
2035     case GST_STATE_CHANGE_READY_TO_PAUSED:
2036       mpegts_base_reset (base);
2037       break;
2038     default:
2039       break;
2040   }
2041
2042   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2043
2044   switch (transition) {
2045     case GST_STATE_CHANGE_PAUSED_TO_READY:
2046       mpegts_base_reset (base);
2047       if (base->mode != BASE_MODE_PUSHING)
2048         base->mode = BASE_MODE_SCANNING;
2049       break;
2050     default:
2051       break;
2052   }
2053
2054   return ret;
2055 }
2056
2057 gboolean
2058 gst_mpegtsbase_plugin_init (GstPlugin * plugin)
2059 {
2060   GST_DEBUG_CATEGORY_INIT (mpegts_base_debug, "mpegtsbase", 0,
2061       "MPEG transport stream base class");
2062
2063   return TRUE;
2064 }