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