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