Imported Upstream version 0.10.23
[profile/ivi/gst-plugins-bad.git] / gst / mpegdemux / mpegtsparse.c
1 /*
2  * mpegtsparse.c - 
3  * Copyright (C) 2007 Alessandro Decina
4  * 
5  * Authors:
6  *   Alessandro Decina <alessandro@nnva.org>
7  *   Zaheer Abbas Merali <zaheerabbas at merali dot org>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <stdlib.h>
30
31 #include "mpegtsparse.h"
32 #include "gstmpegdesc.h"
33
34 /* latency in mseconds */
35 #define TS_LATENCY 700
36
37 #define TABLE_ID_UNSET 0xFF
38 #define RUNNING_STATUS_RUNNING 4
39
40 GST_DEBUG_CATEGORY_STATIC (mpegts_parse_debug);
41 #define GST_CAT_DEFAULT mpegts_parse_debug
42
43 typedef struct _MpegTSParsePad MpegTSParsePad;
44
45 typedef struct
46 {
47   guint16 pid;
48   guint8 stream_type;
49 } MpegTSParseStream;
50
51 typedef struct
52 {
53   gint program_number;
54   guint16 pmt_pid;
55   guint16 pcr_pid;
56   GstStructure *pmt_info;
57   GHashTable *streams;
58   gint patcount;
59   gint selected;
60   gboolean active;
61   MpegTSParsePad *tspad;
62 } MpegTSParseProgram;
63
64 struct _MpegTSParsePad
65 {
66   GstPad *pad;
67
68   /* the program number that the peer wants on this pad */
69   gint program_number;
70   MpegTSParseProgram *program;
71
72   /* set to FALSE before a push and TRUE after */
73   gboolean pushed;
74
75   /* the return of the latest push */
76   GstFlowReturn flow_return;
77
78   GstTagList *tags;
79   guint event_id;
80 };
81
82 static GQuark QUARK_PROGRAMS;
83 static GQuark QUARK_PROGRAM_NUMBER;
84 static GQuark QUARK_PID;
85 static GQuark QUARK_PCR_PID;
86 static GQuark QUARK_STREAMS;
87 static GQuark QUARK_STREAM_TYPE;
88
89 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
90     GST_PAD_SINK,
91     GST_PAD_ALWAYS,
92     GST_STATIC_CAPS ("video/mpegts, " "systemstream = (boolean) true ")
93     );
94
95 static GstStaticPadTemplate src_template =
96 GST_STATIC_PAD_TEMPLATE ("src%d", GST_PAD_SRC,
97     GST_PAD_REQUEST,
98     GST_STATIC_CAPS ("video/mpegts, " "systemstream = (boolean) true ")
99     );
100
101 static GstStaticPadTemplate program_template =
102 GST_STATIC_PAD_TEMPLATE ("program_%d", GST_PAD_SRC,
103     GST_PAD_SOMETIMES,
104     GST_STATIC_CAPS ("video/mpegts, " "systemstream = (boolean) true ")
105     );
106
107 enum
108 {
109   ARG_0,
110   PROP_PROGRAM_NUMBERS,
111   /* FILL ME */
112 };
113
114 static void mpegts_parse_set_property (GObject * object, guint prop_id,
115     const GValue * value, GParamSpec * pspec);
116 static void mpegts_parse_get_property (GObject * object, guint prop_id,
117     GValue * value, GParamSpec * pspec);
118 static void mpegts_parse_dispose (GObject * object);
119 static void mpegts_parse_finalize (GObject * object);
120
121 static MpegTSParsePad *mpegts_parse_create_tspad (MpegTSParse * parse,
122     const gchar * name);
123 static void mpegts_parse_destroy_tspad (MpegTSParse * parse,
124     MpegTSParsePad * tspad);
125 static GstPad *mpegts_parse_activate_program (MpegTSParse * parse,
126     MpegTSParseProgram * program);
127 static void mpegts_parse_free_program (MpegTSParseProgram * program);
128 static void mpegts_parse_free_stream (MpegTSParseStream * ptream);
129 static void mpegts_parse_reset_selected_programs (MpegTSParse * parse,
130     gchar * programs);
131
132 static void mpegts_parse_pad_removed (GstElement * element, GstPad * pad);
133 static GstPad *mpegts_parse_request_new_pad (GstElement * element,
134     GstPadTemplate * templ, const gchar * name);
135 static void mpegts_parse_release_pad (GstElement * element, GstPad * pad);
136 static GstFlowReturn mpegts_parse_chain (GstPad * pad, GstBuffer * buf);
137 static gboolean mpegts_parse_sink_event (GstPad * pad, GstEvent * event);
138 static GstStateChangeReturn mpegts_parse_change_state (GstElement * element,
139     GstStateChange transition);
140 static gboolean mpegts_parse_src_pad_query (GstPad * pad, GstQuery * query);
141 static void _extra_init (GType type);
142 static void mpegts_parse_get_tags_from_sdt (MpegTSParse * parse,
143     GstStructure * sdt_info);
144 static void mpegts_parse_get_tags_from_eit (MpegTSParse * parse,
145     GstStructure * eit_info);
146
147 GST_BOILERPLATE_FULL (MpegTSParse, mpegts_parse, GstElement, GST_TYPE_ELEMENT,
148     _extra_init);
149
150 static const guint32 crc_tab[256] = {
151   0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
152   0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
153   0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
154   0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
155   0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
156   0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
157   0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
158   0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
159   0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
160   0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
161   0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
162   0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
163   0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
164   0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
165   0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
166   0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
167   0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
168   0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
169   0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
170   0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
171   0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
172   0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
173   0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
174   0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
175   0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
176   0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
177   0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
178   0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
179   0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
180   0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
181   0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
182   0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
183   0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
184   0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
185   0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
186   0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
187   0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
188   0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
189   0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
190   0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
191   0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
192   0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
193   0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
194 };
195
196 /* relicenced to LGPL from fluendo ts demuxer */
197 static guint32
198 mpegts_parse_calc_crc32 (guint8 * data, guint datalen)
199 {
200   gint i;
201   guint32 crc = 0xffffffff;
202
203   for (i = 0; i < datalen; i++) {
204     crc = (crc << 8) ^ crc_tab[((crc >> 24) ^ *data++) & 0xff];
205   }
206   return crc;
207 }
208
209 static void
210 _extra_init (GType type)
211 {
212   QUARK_PROGRAMS = g_quark_from_string ("programs");
213   QUARK_PROGRAM_NUMBER = g_quark_from_string ("program-number");
214   QUARK_PID = g_quark_from_string ("pid");
215   QUARK_PCR_PID = g_quark_from_string ("pcr-pid");
216   QUARK_STREAMS = g_quark_from_string ("streams");
217   QUARK_STREAM_TYPE = g_quark_from_string ("stream-type");
218 }
219
220 static void
221 mpegts_parse_base_init (gpointer klass)
222 {
223   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
224
225   gst_element_class_add_static_pad_template (element_class,
226       &sink_template);
227   gst_element_class_add_static_pad_template (element_class, &src_template);
228   gst_element_class_add_static_pad_template (element_class,
229       &program_template);
230
231   gst_element_class_set_details_simple (element_class,
232       "MPEG transport stream parser", "Codec/Parser",
233       "Parses MPEG2 transport streams",
234       "Alessandro Decina <alessandro@nnva.org>, "
235       "Zaheer Abbas Merali <zaheerabbas at merali dot org>");
236 }
237
238 static void
239 mpegts_parse_class_init (MpegTSParseClass * klass)
240 {
241   GObjectClass *gobject_class;
242   GstElementClass *element_class;
243
244   element_class = GST_ELEMENT_CLASS (klass);
245   element_class->pad_removed = mpegts_parse_pad_removed;
246   element_class->request_new_pad = mpegts_parse_request_new_pad;
247   element_class->release_pad = mpegts_parse_release_pad;
248   element_class->change_state = mpegts_parse_change_state;
249
250   gobject_class = G_OBJECT_CLASS (klass);
251   gobject_class->set_property = mpegts_parse_set_property;
252   gobject_class->get_property = mpegts_parse_get_property;
253   gobject_class->dispose = mpegts_parse_dispose;
254   gobject_class->finalize = mpegts_parse_finalize;
255
256   g_object_class_install_property (gobject_class, PROP_PROGRAM_NUMBERS,
257       g_param_spec_string ("program-numbers",
258           "Program Numbers",
259           "Colon separated list of programs", "",
260           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
261 }
262
263 static gboolean
264 foreach_psi_pid_remove (gpointer key, gpointer value, gpointer data)
265 {
266   return TRUE;
267 }
268
269 static void
270 mpegts_parse_reset (MpegTSParse * parse)
271 {
272   mpegts_packetizer_clear (parse->packetizer);
273   g_hash_table_foreach_remove (parse->psi_pids, foreach_psi_pid_remove, NULL);
274
275   /* PAT */
276   g_hash_table_insert (parse->psi_pids,
277       GINT_TO_POINTER (0), GINT_TO_POINTER (1));
278   /* pmt pids will be added and removed dynamically */
279
280 }
281
282 static void
283 mpegts_parse_init (MpegTSParse * parse, MpegTSParseClass * klass)
284 {
285   parse->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
286   gst_pad_set_chain_function (parse->sinkpad, mpegts_parse_chain);
287   gst_pad_set_event_function (parse->sinkpad, mpegts_parse_sink_event);
288   gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad);
289
290   parse->disposed = FALSE;
291   parse->need_sync_program_pads = FALSE;
292   parse->packetizer = mpegts_packetizer_new ();
293   parse->program_numbers = g_strdup ("");
294   parse->pads_to_add = NULL;
295   parse->pads_to_remove = NULL;
296   parse->programs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
297       NULL, (GDestroyNotify) mpegts_parse_free_program);
298   parse->psi_pids = g_hash_table_new (g_direct_hash, g_direct_equal);
299   parse->pes_pids = g_hash_table_new (g_direct_hash, g_direct_equal);
300   mpegts_parse_reset (parse);
301
302 }
303
304 static void
305 mpegts_parse_dispose (GObject * object)
306 {
307   MpegTSParse *parse = GST_MPEGTS_PARSE (object);
308
309   if (!parse->disposed) {
310     g_object_unref (parse->packetizer);
311     parse->disposed = TRUE;
312   }
313
314   if (G_OBJECT_CLASS (parent_class)->dispose)
315     G_OBJECT_CLASS (parent_class)->dispose (object);
316 }
317
318 static void
319 mpegts_parse_finalize (GObject * object)
320 {
321   MpegTSParse *parse = GST_MPEGTS_PARSE (object);
322
323   g_free (parse->program_numbers);
324   if (parse->pat) {
325     gst_structure_free (parse->pat);
326     parse->pat = NULL;
327   }
328   g_hash_table_destroy (parse->programs);
329   g_hash_table_destroy (parse->psi_pids);
330   g_hash_table_destroy (parse->pes_pids);
331
332   if (G_OBJECT_CLASS (parent_class)->finalize)
333     G_OBJECT_CLASS (parent_class)->finalize (object);
334 }
335
336 static void
337 mpegts_parse_set_property (GObject * object, guint prop_id,
338     const GValue * value, GParamSpec * pspec)
339 {
340   MpegTSParse *parse = GST_MPEGTS_PARSE (object);
341
342   switch (prop_id) {
343     case PROP_PROGRAM_NUMBERS:
344       mpegts_parse_reset_selected_programs (parse, g_value_dup_string (value));
345       break;
346     default:
347       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
348   }
349 }
350
351 static void
352 mpegts_parse_get_property (GObject * object, guint prop_id,
353     GValue * value, GParamSpec * pspec)
354 {
355   MpegTSParse *parse = GST_MPEGTS_PARSE (object);
356
357   switch (prop_id) {
358     case PROP_PROGRAM_NUMBERS:
359       g_value_set_string (value, parse->program_numbers);
360       break;
361     default:
362       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
363   }
364 }
365
366 static MpegTSParseProgram *
367 mpegts_parse_add_program (MpegTSParse * parse,
368     gint program_number, guint16 pmt_pid)
369 {
370   MpegTSParseProgram *program;
371
372   program = g_new0 (MpegTSParseProgram, 1);
373   program->program_number = program_number;
374   program->pmt_pid = pmt_pid;
375   program->pcr_pid = G_MAXUINT16;
376   program->streams = g_hash_table_new_full (g_direct_hash, g_direct_equal,
377       NULL, (GDestroyNotify) mpegts_parse_free_stream);
378   program->patcount = 0;
379   program->selected = 0;
380   program->active = FALSE;
381
382   g_hash_table_insert (parse->programs,
383       GINT_TO_POINTER (program_number), program);
384
385   return program;
386 }
387
388 static MpegTSParseProgram *
389 mpegts_parse_get_program (MpegTSParse * parse, gint program_number)
390 {
391   MpegTSParseProgram *program;
392
393   program = (MpegTSParseProgram *) g_hash_table_lookup (parse->programs,
394       GINT_TO_POINTER ((gint) program_number));
395
396   return program;
397 }
398
399 static GstPad *
400 mpegts_parse_activate_program (MpegTSParse * parse,
401     MpegTSParseProgram * program)
402 {
403   MpegTSParsePad *tspad;
404   gchar *pad_name;
405
406   pad_name = g_strdup_printf ("program_%d", program->program_number);
407
408   tspad = mpegts_parse_create_tspad (parse, pad_name);
409   tspad->program_number = program->program_number;
410   tspad->program = program;
411   program->tspad = tspad;
412   g_free (pad_name);
413   gst_pad_set_active (tspad->pad, TRUE);
414   program->active = TRUE;
415
416   return tspad->pad;
417 }
418
419 static GstPad *
420 mpegts_parse_deactivate_program (MpegTSParse * parse,
421     MpegTSParseProgram * program)
422 {
423   MpegTSParsePad *tspad;
424
425   tspad = program->tspad;
426   gst_pad_set_active (tspad->pad, FALSE);
427   program->active = FALSE;
428
429   /* tspad will be destroyed in GstElementClass::pad_removed */
430
431   return tspad->pad;
432 }
433
434 static void
435 mpegts_parse_free_program (MpegTSParseProgram * program)
436 {
437   if (program->pmt_info)
438     gst_structure_free (program->pmt_info);
439
440   g_hash_table_destroy (program->streams);
441
442   g_free (program);
443 }
444
445 static void
446 mpegts_parse_remove_program (MpegTSParse * parse, gint program_number)
447 {
448   g_hash_table_remove (parse->programs, GINT_TO_POINTER (program_number));
449 }
450
451 static void
452 mpegts_parse_sync_program_pads (MpegTSParse * parse)
453 {
454   GList *walk;
455
456   GST_INFO_OBJECT (parse, "begin sync pads");
457   for (walk = parse->pads_to_remove; walk; walk = walk->next)
458     gst_element_remove_pad (GST_ELEMENT (parse), GST_PAD (walk->data));
459
460   for (walk = parse->pads_to_add; walk; walk = walk->next)
461     gst_element_add_pad (GST_ELEMENT (parse), GST_PAD (walk->data));
462
463   if (parse->pads_to_add)
464     g_list_free (parse->pads_to_add);
465
466   if (parse->pads_to_remove)
467     g_list_free (parse->pads_to_remove);
468
469   GST_OBJECT_LOCK (parse);
470   parse->pads_to_remove = NULL;
471   parse->pads_to_add = NULL;
472   parse->need_sync_program_pads = FALSE;
473   GST_OBJECT_UNLOCK (parse);
474
475   GST_INFO_OBJECT (parse, "end sync pads");
476 }
477
478
479 static MpegTSParseStream *
480 mpegts_parse_program_add_stream (MpegTSParse * parse,
481     MpegTSParseProgram * program, guint16 pid, guint8 stream_type)
482 {
483   MpegTSParseStream *stream;
484
485   stream = g_new0 (MpegTSParseStream, 1);
486   stream->pid = pid;
487   stream->stream_type = stream_type;
488
489   g_hash_table_insert (program->streams, GINT_TO_POINTER ((gint) pid), stream);
490
491   return stream;
492 }
493
494 static void
495 foreach_program_activate_or_deactivate (gpointer key, gpointer value,
496     gpointer data)
497 {
498   MpegTSParse *parse = GST_MPEGTS_PARSE (data);
499   MpegTSParseProgram *program = (MpegTSParseProgram *) value;
500
501   /* at this point selected programs have program->selected == 2,
502    * unselected programs thay may have to be deactivated have selected == 1 and
503    * unselected inactive programs have selected == 0 */
504
505   switch (--program->selected) {
506     case 1:
507       /* selected */
508       if (!program->active && program->pmt_pid != G_MAXUINT16)
509         parse->pads_to_add = g_list_append (parse->pads_to_add,
510             mpegts_parse_activate_program (parse, program));
511       break;
512     case 0:
513       /* unselected */
514       if (program->active)
515         parse->pads_to_remove = g_list_append (parse->pads_to_remove,
516             mpegts_parse_deactivate_program (parse, program));
517       break;
518     case -1:
519       /* was already unselected */
520       program->selected = 0;
521       break;
522     default:
523       g_return_if_reached ();
524   }
525 }
526
527 static void
528 mpegts_parse_reset_selected_programs (MpegTSParse * parse,
529     gchar * program_numbers)
530 {
531   GST_OBJECT_LOCK (parse);
532   if (parse->program_numbers)
533     g_free (parse->program_numbers);
534
535   parse->program_numbers = program_numbers;
536
537   if (*parse->program_numbers != '\0') {
538     gint program_number;
539     MpegTSParseProgram *program;
540     gchar **progs, **walk;
541
542     progs = g_strsplit (parse->program_numbers, ":", 0);
543
544     walk = progs;
545     while (*walk != NULL) {
546       program_number = strtol (*walk, NULL, 0);
547       program = mpegts_parse_get_program (parse, program_number);
548       if (program == NULL)
549         /* create the program, it will get activated once we get a PMT for it */
550         program = mpegts_parse_add_program (parse, program_number, G_MAXUINT16);
551
552       program->selected = 2;
553       ++walk;
554     }
555     g_strfreev (progs);
556   }
557
558   g_hash_table_foreach (parse->programs,
559       foreach_program_activate_or_deactivate, parse);
560
561   if (parse->pads_to_remove || parse->pads_to_add)
562     parse->need_sync_program_pads = TRUE;
563   GST_OBJECT_UNLOCK (parse);
564 }
565
566 static void
567 mpegts_parse_free_stream (MpegTSParseStream * stream)
568 {
569   g_free (stream);
570 }
571
572 static void
573 mpegts_parse_program_remove_stream (MpegTSParse * parse,
574     MpegTSParseProgram * program, guint16 pid)
575 {
576   g_hash_table_remove (program->streams, GINT_TO_POINTER ((gint) pid));
577 }
578
579 static void
580 mpegts_parse_deactivate_pmt (MpegTSParse * parse, MpegTSParseProgram * program)
581 {
582   gint i;
583   guint pid;
584   guint stream_type;
585   GstStructure *stream;
586   const GValue *streams;
587   const GValue *value;
588
589   if (program->pmt_info) {
590     streams = gst_structure_id_get_value (program->pmt_info, QUARK_STREAMS);
591
592     for (i = 0; i < gst_value_list_get_size (streams); ++i) {
593       value = gst_value_list_get_value (streams, i);
594       stream = g_value_get_boxed (value);
595       gst_structure_id_get (stream, QUARK_PID, G_TYPE_UINT, &pid,
596           QUARK_STREAM_TYPE, G_TYPE_UINT, &stream_type, NULL);
597       mpegts_parse_program_remove_stream (parse, program, (guint16) pid);
598       g_hash_table_remove (parse->pes_pids, GINT_TO_POINTER ((gint) pid));
599     }
600
601     /* remove pcr stream */
602     mpegts_parse_program_remove_stream (parse, program, program->pcr_pid);
603     g_hash_table_remove (parse->pes_pids,
604         GINT_TO_POINTER ((gint) program->pcr_pid));
605   }
606 }
607
608 static MpegTSParsePad *
609 mpegts_parse_create_tspad (MpegTSParse * parse, const gchar * pad_name)
610 {
611   GstPad *pad;
612   MpegTSParsePad *tspad;
613
614   pad = gst_pad_new_from_static_template (&program_template, pad_name);
615   gst_pad_set_query_function (pad,
616       GST_DEBUG_FUNCPTR (mpegts_parse_src_pad_query));
617
618   /* create our wrapper */
619   tspad = g_new0 (MpegTSParsePad, 1);
620   tspad->pad = pad;
621   tspad->program_number = -1;
622   tspad->program = NULL;
623   tspad->pushed = FALSE;
624   tspad->flow_return = GST_FLOW_NOT_LINKED;
625   gst_pad_set_element_private (pad, tspad);
626
627   return tspad;
628 }
629
630 static void
631 mpegts_parse_destroy_tspad (MpegTSParse * parse, MpegTSParsePad * tspad)
632 {
633   if (tspad->tags) {
634     gst_tag_list_free (tspad->tags);
635   }
636
637   /* free the wrapper */
638   g_free (tspad);
639 }
640
641 static void
642 mpegts_parse_pad_removed (GstElement * element, GstPad * pad)
643 {
644   MpegTSParsePad *tspad;
645   MpegTSParse *parse = GST_MPEGTS_PARSE (element);
646
647   if (gst_pad_get_direction (pad) == GST_PAD_SINK)
648     return;
649
650   tspad = (MpegTSParsePad *) gst_pad_get_element_private (pad);
651   mpegts_parse_destroy_tspad (parse, tspad);
652
653   if (GST_ELEMENT_CLASS (parent_class)->pad_removed)
654     GST_ELEMENT_CLASS (parent_class)->pad_removed (element, pad);
655 }
656
657 static GstPad *
658 mpegts_parse_request_new_pad (GstElement * element, GstPadTemplate * template,
659     const gchar * unused)
660 {
661   MpegTSParse *parse;
662   gchar *name;
663   GstPad *pad;
664
665   g_return_val_if_fail (template != NULL, NULL);
666   g_return_val_if_fail (GST_IS_MPEGTS_PARSE (element), NULL);
667
668   parse = GST_MPEGTS_PARSE (element);
669
670   GST_OBJECT_LOCK (element);
671   name = g_strdup_printf ("src%d", parse->req_pads++);
672   GST_OBJECT_UNLOCK (element);
673
674   pad = mpegts_parse_create_tspad (parse, name)->pad;
675   gst_pad_set_active (pad, TRUE);
676   gst_element_add_pad (element, pad);
677   g_free (name);
678
679   return pad;
680 }
681
682 static void
683 mpegts_parse_release_pad (GstElement * element, GstPad * pad)
684 {
685   g_return_if_fail (GST_IS_MPEGTS_PARSE (element));
686
687   gst_pad_set_active (pad, FALSE);
688   /* we do the cleanup in GstElement::pad-removed */
689   gst_element_remove_pad (element, pad);
690 }
691
692 static GstFlowReturn
693 mpegts_parse_tspad_push_section (MpegTSParse * parse, MpegTSParsePad * tspad,
694     MpegTSPacketizerSection * section, GstBuffer * buffer)
695 {
696   GstFlowReturn ret = GST_FLOW_NOT_LINKED;
697   gboolean to_push = TRUE;
698
699   if (tspad->program_number != -1) {
700     if (tspad->program) {
701       /* we push all sections to all pads except PMTs which we
702        * only push to pads meant to receive that program number */
703       if (section->table_id == 0x02) {
704         /* PMT */
705         if (section->subtable_extension != tspad->program_number)
706           to_push = FALSE;
707       }
708     } else {
709       /* there's a program filter on the pad but the PMT for the program has not
710        * been parsed yet, ignore the pad until we get a PMT */
711       to_push = FALSE;
712       ret = GST_FLOW_OK;
713     }
714   }
715   GST_DEBUG_OBJECT (parse,
716       "pushing section: %d program number: %d table_id: %d", to_push,
717       tspad->program_number, section->table_id);
718   if (to_push) {
719     ret = gst_pad_push (tspad->pad, buffer);
720   } else {
721     gst_buffer_unref (buffer);
722     if (gst_pad_is_linked (tspad->pad))
723       ret = GST_FLOW_OK;
724   }
725
726   return ret;
727 }
728
729 static GstFlowReturn
730 mpegts_parse_tspad_push (MpegTSParse * parse, MpegTSParsePad * tspad,
731     guint16 pid, GstBuffer * buffer)
732 {
733   GstFlowReturn ret = GST_FLOW_NOT_LINKED;
734   GHashTable *pad_pids = NULL;
735
736   if (tspad->program_number != -1) {
737     if (tspad->program) {
738       pad_pids = tspad->program->streams;
739
740       if (tspad->tags) {
741         gst_element_found_tags_for_pad (GST_ELEMENT_CAST (parse),
742             tspad->pad, tspad->tags);
743         tspad->tags = NULL;
744       }
745     } else {
746       /* there's a program filter on the pad but the PMT for the program has not
747        * been parsed yet, ignore the pad until we get a PMT */
748       gst_buffer_unref (buffer);
749       ret = GST_FLOW_OK;
750       goto out;
751     }
752   }
753
754   if (pad_pids == NULL ||
755       g_hash_table_lookup (pad_pids, GINT_TO_POINTER ((gint) pid)) != NULL) {
756     /* push if there's no filter or if the pid is in the filter */
757     ret = gst_pad_push (tspad->pad, buffer);
758   } else {
759     gst_buffer_unref (buffer);
760     if (gst_pad_is_linked (tspad->pad))
761       ret = GST_FLOW_OK;
762   }
763
764 out:
765   return ret;
766 }
767
768 static void
769 pad_clear_for_push (GstPad * pad, MpegTSParse * parse)
770 {
771   MpegTSParsePad *tspad = (MpegTSParsePad *) gst_pad_get_element_private (pad);
772
773   tspad->flow_return = GST_FLOW_NOT_LINKED;
774   tspad->pushed = FALSE;
775 }
776
777 static GstFlowReturn
778 mpegts_parse_push (MpegTSParse * parse, MpegTSPacketizerPacket * packet,
779     MpegTSPacketizerSection * section)
780 {
781   guint32 pads_cookie;
782   gboolean done = FALSE;
783   GstPad *pad = NULL;
784   MpegTSParsePad *tspad;
785   guint16 pid;
786   GstBuffer *buffer;
787   GstFlowReturn ret;
788   GList *srcpads;
789
790   pid = packet->pid;
791   buffer = gst_buffer_make_metadata_writable (packet->buffer);
792   /* we have the same caps on all the src pads */
793   gst_buffer_set_caps (buffer, parse->packetizer->caps);
794
795   GST_OBJECT_LOCK (parse);
796   /* clear tspad->pushed on pads */
797   g_list_foreach (GST_ELEMENT_CAST (parse)->srcpads,
798       (GFunc) pad_clear_for_push, parse);
799   if (GST_ELEMENT_CAST (parse)->srcpads)
800     ret = GST_FLOW_NOT_LINKED;
801   else
802     ret = GST_FLOW_OK;
803
804   /* Get cookie and source pads list */
805   pads_cookie = GST_ELEMENT_CAST (parse)->pads_cookie;
806   srcpads = GST_ELEMENT_CAST (parse)->srcpads;
807   if (G_LIKELY (srcpads)) {
808     pad = GST_PAD_CAST (srcpads->data);
809     g_object_ref (pad);
810   }
811   GST_OBJECT_UNLOCK (parse);
812
813   while (pad && !done) {
814     tspad = gst_pad_get_element_private (pad);
815
816     if (G_LIKELY (!tspad->pushed)) {
817       /* ref the buffer as gst_pad_push takes a ref but we want to reuse the
818        * same buffer for next pushes */
819       gst_buffer_ref (buffer);
820       if (section) {
821         tspad->flow_return =
822             mpegts_parse_tspad_push_section (parse, tspad, section, buffer);
823       } else {
824         tspad->flow_return =
825             mpegts_parse_tspad_push (parse, tspad, pid, buffer);
826       }
827       tspad->pushed = TRUE;
828
829       if (G_UNLIKELY (tspad->flow_return != GST_FLOW_OK
830               && tspad->flow_return != GST_FLOW_NOT_LINKED)) {
831         /* return the error upstream */
832         ret = tspad->flow_return;
833         done = TRUE;
834       }
835
836     }
837
838     if (ret == GST_FLOW_NOT_LINKED)
839       ret = tspad->flow_return;
840
841     g_object_unref (pad);
842
843     if (G_UNLIKELY (!done)) {
844       GST_OBJECT_LOCK (parse);
845       if (G_UNLIKELY (pads_cookie != GST_ELEMENT_CAST (parse)->pads_cookie)) {
846         /* resync */
847         GST_DEBUG ("resync");
848         pads_cookie = GST_ELEMENT_CAST (parse)->pads_cookie;
849         srcpads = GST_ELEMENT_CAST (parse)->srcpads;
850       } else {
851         GST_DEBUG ("getting next pad");
852         /* Get next pad */
853         srcpads = g_list_next (srcpads);
854       }
855
856       if (srcpads) {
857         pad = GST_PAD_CAST (srcpads->data);
858         g_object_ref (pad);
859       } else
860         done = TRUE;
861       GST_OBJECT_UNLOCK (parse);
862     }
863   }
864
865   gst_buffer_unref (buffer);
866   packet->buffer = NULL;
867
868   return ret;
869 }
870
871 static gboolean
872 mpegts_parse_is_psi (MpegTSParse * parse, MpegTSPacketizerPacket * packet)
873 {
874   gboolean retval = FALSE;
875   guint8 table_id;
876   guint8 *data;
877   guint8 pointer;
878   int i;
879   static const guint8 si_tables[] =
880       { 0x00, 0x01, 0x02, 0x03, 0x40, 0x41, 0x42, 0x46, 0x4A, 0x4E, 0x4F, 0x50,
881     0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C,
882     0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
883     0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x7E,
884     0x7F, TABLE_ID_UNSET
885   };
886   if (g_hash_table_lookup (parse->psi_pids,
887           GINT_TO_POINTER ((gint) packet->pid)) != NULL)
888     retval = TRUE;
889   /* check is it is a pes pid */
890   if (g_hash_table_lookup (parse->pes_pids,
891           GINT_TO_POINTER ((gint) packet->pid)) != NULL)
892     return FALSE;
893   if (!retval) {
894     if (packet->payload_unit_start_indicator) {
895       data = packet->data;
896       pointer = *data++;
897       data += pointer;
898       /* 'pointer' value may be invalid on malformed packet
899        * so we need to avoid out of range
900        */
901       if (!(data < packet->data_end)) {
902         GST_WARNING_OBJECT (parse,
903             "Wrong offset when retrieving table id: 0x%x", pointer);
904         return FALSE;
905       }
906       table_id = *data;
907       i = 0;
908       while (si_tables[i] != TABLE_ID_UNSET) {
909         if (G_UNLIKELY (si_tables[i] == table_id)) {
910           GST_DEBUG_OBJECT (parse, "Packet has table id 0x%x", table_id);
911           retval = TRUE;
912           break;
913         }
914         i++;
915       }
916     } else {
917       MpegTSPacketizerStream *stream = parse->packetizer->streams[packet->pid];
918       if (stream) {
919         i = 0;
920         GST_DEBUG_OBJECT (parse, "section table id: 0x%x",
921             stream->section_table_id);
922         while (si_tables[i] != TABLE_ID_UNSET) {
923           if (G_UNLIKELY (si_tables[i] == stream->section_table_id)) {
924             retval = TRUE;
925             break;
926           }
927           i++;
928         }
929       }
930     }
931   }
932
933   GST_DEBUG_OBJECT (parse, "Packet of pid 0x%x is psi: %d", packet->pid,
934       retval);
935   return retval;
936 }
937
938 static void
939 mpegts_parse_apply_pat (MpegTSParse * parse, GstStructure * pat_info)
940 {
941   const GValue *value;
942   GstStructure *old_pat;
943   GstStructure *program_info;
944   guint program_number;
945   guint pid;
946   MpegTSParseProgram *program;
947   gint i;
948   const GValue *programs;
949
950   old_pat = parse->pat;
951   parse->pat = gst_structure_copy (pat_info);
952
953   GST_INFO_OBJECT (parse, "PAT %" GST_PTR_FORMAT, pat_info);
954
955   gst_element_post_message (GST_ELEMENT_CAST (parse),
956       gst_message_new_element (GST_OBJECT (parse),
957           gst_structure_copy (pat_info)));
958
959   GST_OBJECT_LOCK (parse);
960   programs = gst_structure_id_get_value (pat_info, QUARK_PROGRAMS);
961   /* activate the new table */
962   for (i = 0; i < gst_value_list_get_size (programs); ++i) {
963     value = gst_value_list_get_value (programs, i);
964
965     program_info = g_value_get_boxed (value);
966     gst_structure_id_get (program_info, QUARK_PROGRAM_NUMBER, G_TYPE_UINT,
967         &program_number, QUARK_PID, G_TYPE_UINT, &pid, NULL);
968
969     program = mpegts_parse_get_program (parse, program_number);
970     if (program) {
971       if (program->pmt_pid != pid) {
972         if (program->pmt_pid != G_MAXUINT16) {
973           /* pmt pid changed */
974           g_hash_table_remove (parse->psi_pids,
975               GINT_TO_POINTER ((gint) program->pmt_pid));
976         }
977
978         program->pmt_pid = pid;
979         g_hash_table_insert (parse->psi_pids,
980             GINT_TO_POINTER ((gint) pid), GINT_TO_POINTER (1));
981       }
982     } else {
983       g_hash_table_insert (parse->psi_pids,
984           GINT_TO_POINTER ((gint) pid), GINT_TO_POINTER (1));
985       program = mpegts_parse_add_program (parse, program_number, pid);
986     }
987     program->patcount += 1;
988     if (program->selected && !program->active)
989       parse->pads_to_add = g_list_append (parse->pads_to_add,
990           mpegts_parse_activate_program (parse, program));
991   }
992
993   if (old_pat) {
994     /* deactivate the old table */
995
996     programs = gst_structure_id_get_value (old_pat, QUARK_PROGRAMS);
997     for (i = 0; i < gst_value_list_get_size (programs); ++i) {
998       value = gst_value_list_get_value (programs, i);
999
1000       program_info = g_value_get_boxed (value);
1001       gst_structure_id_get (program_info,
1002           QUARK_PROGRAM_NUMBER, G_TYPE_UINT, &program_number,
1003           QUARK_PID, G_TYPE_UINT, &pid, NULL);
1004
1005       program = mpegts_parse_get_program (parse, program_number);
1006       if (program == NULL) {
1007         GST_DEBUG_OBJECT (parse, "broken PAT, duplicated entry for program %d",
1008             program_number);
1009         continue;
1010       }
1011
1012       if (--program->patcount > 0)
1013         /* the program has been referenced by the new pat, keep it */
1014         continue;
1015
1016       GST_INFO_OBJECT (parse, "PAT removing program %" GST_PTR_FORMAT,
1017           program_info);
1018
1019       if (program->active)
1020         parse->pads_to_remove = g_list_append (parse->pads_to_remove,
1021             mpegts_parse_deactivate_program (parse, program));
1022
1023       mpegts_parse_deactivate_pmt (parse, program);
1024       mpegts_parse_remove_program (parse, program_number);
1025       g_hash_table_remove (parse->psi_pids, GINT_TO_POINTER ((gint) pid));
1026       mpegts_packetizer_remove_stream (parse->packetizer, pid);
1027     }
1028
1029     gst_structure_free (old_pat);
1030   }
1031
1032   GST_OBJECT_UNLOCK (parse);
1033
1034   mpegts_parse_sync_program_pads (parse);
1035 }
1036
1037 static void
1038 mpegts_parse_apply_pmt (MpegTSParse * parse,
1039     guint16 pmt_pid, GstStructure * pmt_info)
1040 {
1041   MpegTSParseProgram *program;
1042   guint program_number;
1043   guint pcr_pid;
1044   guint pid;
1045   guint stream_type;
1046   GstStructure *stream;
1047   gint i;
1048   const GValue *new_streams;
1049   const GValue *value;
1050
1051   gst_structure_id_get (pmt_info,
1052       QUARK_PROGRAM_NUMBER, G_TYPE_UINT, &program_number,
1053       QUARK_PCR_PID, G_TYPE_UINT, &pcr_pid, NULL);
1054   new_streams = gst_structure_id_get_value (pmt_info, QUARK_STREAMS);
1055
1056   GST_OBJECT_LOCK (parse);
1057   program = mpegts_parse_get_program (parse, program_number);
1058   if (program) {
1059     /* deactivate old pmt */
1060     mpegts_parse_deactivate_pmt (parse, program);
1061     if (program->pmt_info)
1062       gst_structure_free (program->pmt_info);
1063     program->pmt_info = NULL;
1064   } else {
1065     /* no PAT?? */
1066     g_hash_table_insert (parse->psi_pids,
1067         GINT_TO_POINTER ((gint) pmt_pid), GINT_TO_POINTER (1));
1068     program = mpegts_parse_add_program (parse, program_number, pid);
1069   }
1070
1071   /* activate new pmt */
1072   program->pmt_info = gst_structure_copy (pmt_info);
1073   program->pmt_pid = pmt_pid;
1074   program->pcr_pid = pcr_pid;
1075   mpegts_parse_program_add_stream (parse, program, (guint16) pcr_pid, -1);
1076   g_hash_table_insert (parse->pes_pids, GINT_TO_POINTER ((gint) pcr_pid),
1077       GINT_TO_POINTER (1));
1078
1079   for (i = 0; i < gst_value_list_get_size (new_streams); ++i) {
1080     value = gst_value_list_get_value (new_streams, i);
1081     stream = g_value_get_boxed (value);
1082
1083     gst_structure_id_get (stream, QUARK_PID, G_TYPE_UINT, &pid,
1084         QUARK_STREAM_TYPE, G_TYPE_UINT, &stream_type, NULL);
1085     mpegts_parse_program_add_stream (parse, program,
1086         (guint16) pid, (guint8) stream_type);
1087     g_hash_table_insert (parse->pes_pids, GINT_TO_POINTER ((gint) pid),
1088         GINT_TO_POINTER ((gint) 1));
1089
1090   }
1091   GST_OBJECT_UNLOCK (parse);
1092
1093   GST_DEBUG_OBJECT (parse, "new pmt %" GST_PTR_FORMAT, pmt_info);
1094
1095   gst_element_post_message (GST_ELEMENT_CAST (parse),
1096       gst_message_new_element (GST_OBJECT (parse),
1097           gst_structure_copy (pmt_info)));
1098 }
1099
1100 static void
1101 mpegts_parse_apply_nit (MpegTSParse * parse,
1102     guint16 pmt_pid, GstStructure * nit_info)
1103 {
1104   gst_element_post_message (GST_ELEMENT_CAST (parse),
1105       gst_message_new_element (GST_OBJECT (parse),
1106           gst_structure_copy (nit_info)));
1107 }
1108
1109 static void
1110 mpegts_parse_apply_sdt (MpegTSParse * parse,
1111     guint16 pmt_pid, GstStructure * sdt_info)
1112 {
1113   mpegts_parse_get_tags_from_sdt (parse, sdt_info);
1114
1115   gst_element_post_message (GST_ELEMENT_CAST (parse),
1116       gst_message_new_element (GST_OBJECT (parse),
1117           gst_structure_copy (sdt_info)));
1118 }
1119
1120 static void
1121 mpegts_parse_apply_eit (MpegTSParse * parse,
1122     guint16 pmt_pid, GstStructure * eit_info)
1123 {
1124   mpegts_parse_get_tags_from_eit (parse, eit_info);
1125
1126   gst_element_post_message (GST_ELEMENT_CAST (parse),
1127       gst_message_new_element (GST_OBJECT (parse),
1128           gst_structure_copy (eit_info)));
1129 }
1130
1131 static void
1132 mpegts_parse_apply_tdt (MpegTSParse * parse,
1133     guint16 tdt_pid, GstStructure * tdt_info)
1134 {
1135   gst_element_post_message (GST_ELEMENT_CAST (parse),
1136       gst_message_new_element (GST_OBJECT (parse),
1137           gst_structure_copy (tdt_info)));
1138
1139   gst_element_send_event (GST_ELEMENT_CAST (parse),
1140       gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM,
1141           gst_structure_copy (tdt_info)));
1142 }
1143
1144 static gboolean
1145 mpegts_parse_handle_psi (MpegTSParse * parse, MpegTSPacketizerSection * section)
1146 {
1147   gboolean res = TRUE;
1148   GstStructure *structure = NULL;
1149
1150   /* table ids 0x70 - 0x73 do not have a crc */
1151   if (G_LIKELY (section->table_id < 0x70 || section->table_id > 0x73)) {
1152     if (G_UNLIKELY (mpegts_parse_calc_crc32 (GST_BUFFER_DATA (section->buffer),
1153                 GST_BUFFER_SIZE (section->buffer)) != 0)) {
1154       GST_WARNING_OBJECT (parse, "bad crc in psi pid 0x%x", section->pid);
1155       return FALSE;
1156     }
1157   }
1158
1159   switch (section->table_id) {
1160     case 0x00:
1161       /* PAT */
1162       structure = mpegts_packetizer_parse_pat (parse->packetizer, section);
1163       if (G_LIKELY (structure))
1164         mpegts_parse_apply_pat (parse, structure);
1165       else
1166         res = FALSE;
1167
1168       break;
1169     case 0x02:
1170       structure = mpegts_packetizer_parse_pmt (parse->packetizer, section);
1171       if (G_LIKELY (structure))
1172         mpegts_parse_apply_pmt (parse, section->pid, structure);
1173       else
1174         res = FALSE;
1175
1176       break;
1177     case 0x40:
1178       /* NIT, actual network */
1179     case 0x41:
1180       /* NIT, other network */
1181       structure = mpegts_packetizer_parse_nit (parse->packetizer, section);
1182       if (G_LIKELY (structure))
1183         mpegts_parse_apply_nit (parse, section->pid, structure);
1184       else
1185         res = FALSE;
1186
1187       break;
1188     case 0x42:
1189     case 0x46:
1190       structure = mpegts_packetizer_parse_sdt (parse->packetizer, section);
1191       if (G_LIKELY (structure))
1192         mpegts_parse_apply_sdt (parse, section->pid, structure);
1193       else
1194         res = FALSE;
1195       break;
1196     case 0x4E:
1197     case 0x4F:
1198       /* EIT, present/following */
1199     case 0x50:
1200     case 0x51:
1201     case 0x52:
1202     case 0x53:
1203     case 0x54:
1204     case 0x55:
1205     case 0x56:
1206     case 0x57:
1207     case 0x58:
1208     case 0x59:
1209     case 0x5A:
1210     case 0x5B:
1211     case 0x5C:
1212     case 0x5D:
1213     case 0x5E:
1214     case 0x5F:
1215     case 0x60:
1216     case 0x61:
1217     case 0x62:
1218     case 0x63:
1219     case 0x64:
1220     case 0x65:
1221     case 0x66:
1222     case 0x67:
1223     case 0x68:
1224     case 0x69:
1225     case 0x6A:
1226     case 0x6B:
1227     case 0x6C:
1228     case 0x6D:
1229     case 0x6E:
1230     case 0x6F:
1231       /* EIT, schedule */
1232       structure = mpegts_packetizer_parse_eit (parse->packetizer, section);
1233       if (G_LIKELY (structure))
1234         mpegts_parse_apply_eit (parse, section->pid, structure);
1235       else
1236         res = FALSE;
1237       break;
1238     case 0x70:
1239       /* TDT (Time and Date table) */
1240       structure = mpegts_packetizer_parse_tdt (parse->packetizer, section);
1241       if (G_LIKELY (structure))
1242         mpegts_parse_apply_tdt (parse, section->pid, structure);
1243       else
1244         res = FALSE;
1245       break;
1246     default:
1247       break;
1248   }
1249
1250   if (structure)
1251     gst_structure_free (structure);
1252
1253   return res;
1254 }
1255
1256 static void
1257 mpegts_parse_get_tags_from_sdt (MpegTSParse * parse, GstStructure * sdt_info)
1258 {
1259   const GValue *services;
1260   guint i;
1261
1262   services = gst_structure_get_value (sdt_info, "services");
1263
1264   for (i = 0; i < gst_value_list_get_size (services); i++) {
1265     const GstStructure *service;
1266     const gchar *sid_str;
1267     gchar *tmp;
1268     gint program_number;
1269     MpegTSParseProgram *program;
1270
1271     service = gst_value_get_structure (gst_value_list_get_value (services, i));
1272
1273     /* get program_number from structure name
1274      * which looks like service-%d */
1275     sid_str = gst_structure_get_name (service);
1276     tmp = g_strstr_len (sid_str, -1, "-");
1277     if (!tmp)
1278       continue;
1279     program_number = atoi (++tmp);
1280
1281     program = mpegts_parse_get_program (parse, program_number);
1282     if (program && program->tspad && !program->tspad->tags) {
1283       program->tspad->tags = gst_tag_list_new_full (GST_TAG_ARTIST,
1284           gst_structure_get_string (service, "name"), NULL);
1285     }
1286   }
1287 }
1288
1289 static void
1290 mpegts_parse_get_tags_from_eit (MpegTSParse * parse, GstStructure * eit_info)
1291 {
1292   const GValue *events;
1293   guint i;
1294   guint program_number;
1295   MpegTSParseProgram *program;
1296   gboolean present_following;
1297
1298   gst_structure_get_uint (eit_info, "service-id", &program_number);
1299   program = mpegts_parse_get_program (parse, program_number);
1300
1301   gst_structure_get_boolean (eit_info, "present-following", &present_following);
1302
1303   if (program && program->tspad && present_following) {
1304     events = gst_structure_get_value (eit_info, "events");
1305
1306     for (i = 0; i < gst_value_list_get_size (events); i++) {
1307       const GstStructure *event;
1308       const gchar *title;
1309       guint status;
1310       guint event_id;
1311       guint duration;
1312
1313       event = gst_value_get_structure (gst_value_list_get_value (events, i));
1314
1315       title = gst_structure_get_string (event, "name");
1316       gst_structure_get_uint (event, "event-id", &event_id);
1317       gst_structure_get_uint (event, "running-status", &status);
1318
1319       if (title && event_id != program->tspad->event_id
1320           && status == RUNNING_STATUS_RUNNING) {
1321         gst_structure_get_uint (event, "duration", &duration);
1322
1323         program->tspad->event_id = event_id;
1324         program->tspad->tags = gst_tag_list_new_full (GST_TAG_TITLE,
1325             title, GST_TAG_DURATION, duration * GST_SECOND, NULL);
1326       }
1327     }
1328   }
1329 }
1330
1331 static gboolean
1332 mpegts_parse_sink_event (GstPad * pad, GstEvent * event)
1333 {
1334   gboolean res;
1335   MpegTSParse *parse =
1336       GST_MPEGTS_PARSE (gst_object_get_parent (GST_OBJECT (pad)));
1337
1338   switch (GST_EVENT_TYPE (event)) {
1339     case GST_EVENT_FLUSH_STOP:
1340       mpegts_packetizer_clear (parse->packetizer);
1341       res = gst_pad_event_default (pad, event);
1342       break;
1343     default:
1344       res = gst_pad_event_default (pad, event);
1345   }
1346
1347   gst_object_unref (parse);
1348   return res;
1349 }
1350
1351 static GstFlowReturn
1352 mpegts_parse_chain (GstPad * pad, GstBuffer * buf)
1353 {
1354   GstFlowReturn res = GST_FLOW_OK;
1355   MpegTSParse *parse;
1356   gboolean parsed;
1357   MpegTSPacketizerPacketReturn pret;
1358   MpegTSPacketizer *packetizer;
1359   MpegTSPacketizerPacket packet;
1360
1361   parse = GST_MPEGTS_PARSE (gst_object_get_parent (GST_OBJECT (pad)));
1362   packetizer = parse->packetizer;
1363
1364   mpegts_packetizer_push (parse->packetizer, buf);
1365   while (((pret =
1366               mpegts_packetizer_next_packet (parse->packetizer,
1367                   &packet)) != PACKET_NEED_MORE) && res == GST_FLOW_OK) {
1368     if (G_UNLIKELY (pret == PACKET_BAD))
1369       /* bad header, skip the packet */
1370       goto next;
1371
1372     /* parse PSI data */
1373     if (packet.payload != NULL && mpegts_parse_is_psi (parse, &packet)) {
1374       MpegTSPacketizerSection section;
1375
1376       parsed = mpegts_packetizer_push_section (packetizer, &packet, &section);
1377       if (G_UNLIKELY (!parsed))
1378         /* bad section data */
1379         goto next;
1380
1381       if (G_LIKELY (section.complete)) {
1382         /* section complete */
1383         parsed = mpegts_parse_handle_psi (parse, &section);
1384         gst_buffer_unref (section.buffer);
1385
1386         if (G_UNLIKELY (!parsed))
1387           /* bad PSI table */
1388           goto next;
1389       }
1390       /* we need to push section packet downstream */
1391       res = mpegts_parse_push (parse, &packet, &section);
1392
1393     } else {
1394       /* push the packet downstream */
1395       res = mpegts_parse_push (parse, &packet, NULL);
1396     }
1397
1398   next:
1399     mpegts_packetizer_clear_packet (parse->packetizer, &packet);
1400   }
1401
1402   if (parse->need_sync_program_pads)
1403     mpegts_parse_sync_program_pads (parse);
1404
1405   gst_object_unref (parse);
1406   return res;
1407 }
1408
1409 static GstStateChangeReturn
1410 mpegts_parse_change_state (GstElement * element, GstStateChange transition)
1411 {
1412   MpegTSParse *parse;
1413   GstStateChangeReturn ret;
1414
1415   parse = GST_MPEGTS_PARSE (element);
1416   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1417
1418   switch (transition) {
1419     case GST_STATE_CHANGE_PAUSED_TO_READY:
1420       mpegts_parse_reset (parse);
1421       break;
1422     default:
1423       break;
1424   }
1425
1426   return ret;
1427 }
1428
1429 static gboolean
1430 mpegts_parse_src_pad_query (GstPad * pad, GstQuery * query)
1431 {
1432   MpegTSParse *parse = GST_MPEGTS_PARSE (gst_pad_get_parent (pad));
1433   gboolean res;
1434
1435   switch (GST_QUERY_TYPE (query)) {
1436     case GST_QUERY_LATENCY:
1437     {
1438       if ((res = gst_pad_peer_query (parse->sinkpad, query))) {
1439         gboolean is_live;
1440         GstClockTime min_latency, max_latency;
1441
1442         gst_query_parse_latency (query, &is_live, &min_latency, &max_latency);
1443         if (is_live) {
1444           min_latency += TS_LATENCY * GST_MSECOND;
1445           if (max_latency != GST_CLOCK_TIME_NONE)
1446             max_latency += TS_LATENCY * GST_MSECOND;
1447         }
1448
1449         gst_query_set_latency (query, is_live, min_latency, max_latency);
1450       }
1451
1452       break;
1453     }
1454     default:
1455       res = gst_pad_query_default (pad, query);
1456   }
1457   gst_object_unref (parse);
1458   return res;
1459 }
1460
1461 gboolean
1462 gst_mpegtsparse_plugin_init (GstPlugin * plugin)
1463 {
1464   GST_DEBUG_CATEGORY_INIT (mpegts_parse_debug, "mpegtsparse", 0,
1465       "MPEG transport stream parser");
1466
1467   gst_mpegtsdesc_init_debug ();
1468
1469   return gst_element_register (plugin, "mpegtsparse",
1470       GST_RANK_NONE, GST_TYPE_MPEGTS_PARSE);
1471 }