~ubuntu-branches/ubuntu/quantal/gst-plugins-bad0.10/quantal-proposed

« back to all changes in this revision

Viewing changes to gst/mpegtsdemux/mpegtsbase.c

  • Committer: Bazaar Package Importer
  • Author(s): Ken VanDine
  • Date: 2011-07-19 14:32:43 UTC
  • mfrom: (18.4.21 sid)
  • Revision ID: james.westby@ubuntu.com-20110719143243-p7pnkh45akfp0ihk
Tags: 0.10.22-2ubuntu1
* Rebased on debian unstable, remaining changes:
  - debian/gstreamer-plugins-bad.install
    * don't include dtmf, liveadder, rtpmux, autoconvert and shm, we include 
      them in -good

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * mpegtsbase.c - 
 
3
 * Copyright (C) 2007 Alessandro Decina
 
4
 *               2010 Edward Hervey
 
5
 *
 
6
 * Authors:
 
7
 *   Alessandro Decina <alessandro@nnva.org>
 
8
 *   Zaheer Abbas Merali <zaheerabbas at merali dot org>
 
9
 *   Edward Hervey <edward.hervey@collabora.co.uk>
 
10
 *
 
11
 * This library is free software; you can redistribute it and/or
 
12
 * modify it under the terms of the GNU Library General Public
 
13
 * License as published by the Free Software Foundation; either
 
14
 * version 2 of the License, or (at your option) any later version.
 
15
 *
 
16
 * This library is distributed in the hope that it will be useful,
 
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
19
 * Library General Public License for more details.
 
20
 *
 
21
 * You should have received a copy of the GNU Library General Public
 
22
 * License along with this library; if not, write to the
 
23
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
24
 * Boston, MA 02111-1307, USA.
 
25
 */
 
26
 
 
27
#ifdef HAVE_CONFIG_H
 
28
#include "config.h"
 
29
#endif
 
30
 
 
31
#include <stdlib.h>
 
32
#include <string.h>
 
33
 
 
34
#include <gst/gst-i18n-plugin.h>
 
35
#include "mpegtsbase.h"
 
36
#include "gstmpegdesc.h"
 
37
 
 
38
/* latency in mseconds */
 
39
#define TS_LATENCY 700
 
40
 
 
41
#define TABLE_ID_UNSET 0xFF
 
42
#define RUNNING_STATUS_RUNNING 4
 
43
 
 
44
GST_DEBUG_CATEGORY_STATIC (mpegts_base_debug);
 
45
#define GST_CAT_DEFAULT mpegts_base_debug
 
46
 
 
47
static GQuark QUARK_PROGRAMS;
 
48
static GQuark QUARK_PROGRAM_NUMBER;
 
49
static GQuark QUARK_PID;
 
50
static GQuark QUARK_PCR_PID;
 
51
static GQuark QUARK_STREAMS;
 
52
static GQuark QUARK_STREAM_TYPE;
 
53
 
 
54
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
 
55
    GST_PAD_SINK,
 
56
    GST_PAD_ALWAYS,
 
57
    GST_STATIC_CAPS ("video/mpegts, " "systemstream = (boolean) true ")
 
58
    );
 
59
 
 
60
enum
 
61
{
 
62
  ARG_0,
 
63
  /* FILL ME */
 
64
};
 
65
 
 
66
static void mpegts_base_set_property (GObject * object, guint prop_id,
 
67
    const GValue * value, GParamSpec * pspec);
 
68
static void mpegts_base_get_property (GObject * object, guint prop_id,
 
69
    GValue * value, GParamSpec * pspec);
 
70
static void mpegts_base_dispose (GObject * object);
 
71
static void mpegts_base_finalize (GObject * object);
 
72
static void mpegts_base_free_program (MpegTSBaseProgram * program);
 
73
static void mpegts_base_free_stream (MpegTSBaseStream * ptream);
 
74
static gboolean mpegts_base_sink_activate (GstPad * pad);
 
75
static gboolean mpegts_base_sink_activate_pull (GstPad * pad, gboolean active);
 
76
static gboolean mpegts_base_sink_activate_push (GstPad * pad, gboolean active);
 
77
static GstFlowReturn mpegts_base_chain (GstPad * pad, GstBuffer * buf);
 
78
static gboolean mpegts_base_sink_event (GstPad * pad, GstEvent * event);
 
79
static GstStateChangeReturn mpegts_base_change_state (GstElement * element,
 
80
    GstStateChange transition);
 
81
static void _extra_init (GType type);
 
82
static void mpegts_base_get_tags_from_sdt (MpegTSBase * base,
 
83
    GstStructure * sdt_info);
 
84
static void mpegts_base_get_tags_from_eit (MpegTSBase * base,
 
85
    GstStructure * eit_info);
 
86
 
 
87
GST_BOILERPLATE_FULL (MpegTSBase, mpegts_base, GstElement, GST_TYPE_ELEMENT,
 
88
    _extra_init);
 
89
 
 
90
 
 
91
static const guint32 crc_tab[256] = {
 
92
  0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
 
93
  0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
 
94
  0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
 
95
  0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
 
96
  0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
 
97
  0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
 
98
  0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
 
99
  0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
 
100
  0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
 
101
  0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
 
102
  0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
 
103
  0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
 
104
  0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
 
105
  0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
 
106
  0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
 
107
  0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
 
108
  0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
 
109
  0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
 
110
  0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
 
111
  0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
 
112
  0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
 
113
  0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
 
114
  0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
 
115
  0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
 
116
  0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
 
117
  0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
 
118
  0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
 
119
  0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
 
120
  0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
 
121
  0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
 
122
  0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
 
123
  0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
 
124
  0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
 
125
  0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
 
126
  0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
 
127
  0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
 
128
  0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
 
129
  0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
 
130
  0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
 
131
  0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
 
132
  0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
 
133
  0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
 
134
  0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
 
135
};
 
136
 
 
137
/* relicenced to LGPL from fluendo ts demuxer */
 
138
static guint32
 
139
mpegts_base_calc_crc32 (guint8 * data, guint datalen)
 
140
{
 
141
  gint i;
 
142
  guint32 crc = 0xffffffff;
 
143
 
 
144
  for (i = 0; i < datalen; i++) {
 
145
    crc = (crc << 8) ^ crc_tab[((crc >> 24) ^ *data++) & 0xff];
 
146
  }
 
147
  return crc;
 
148
}
 
149
 
 
150
static void
 
151
_extra_init (GType type)
 
152
{
 
153
  QUARK_PROGRAMS = g_quark_from_string ("programs");
 
154
  QUARK_PROGRAM_NUMBER = g_quark_from_string ("program-number");
 
155
  QUARK_PID = g_quark_from_string ("pid");
 
156
  QUARK_PCR_PID = g_quark_from_string ("pcr-pid");
 
157
  QUARK_STREAMS = g_quark_from_string ("streams");
 
158
  QUARK_STREAM_TYPE = g_quark_from_string ("stream-type");
 
159
}
 
160
 
 
161
static void
 
162
mpegts_base_base_init (gpointer klass)
 
163
{
 
164
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
 
165
 
 
166
  gst_element_class_add_pad_template (element_class,
 
167
      gst_static_pad_template_get (&sink_template));
 
168
}
 
169
 
 
170
static void
 
171
mpegts_base_class_init (MpegTSBaseClass * klass)
 
172
{
 
173
  GObjectClass *gobject_class;
 
174
  GstElementClass *element_class;
 
175
 
 
176
  element_class = GST_ELEMENT_CLASS (klass);
 
177
  element_class->change_state = mpegts_base_change_state;
 
178
 
 
179
  gobject_class = G_OBJECT_CLASS (klass);
 
180
  gobject_class->set_property = mpegts_base_set_property;
 
181
  gobject_class->get_property = mpegts_base_get_property;
 
182
  gobject_class->dispose = mpegts_base_dispose;
 
183
  gobject_class->finalize = mpegts_base_finalize;
 
184
 
 
185
}
 
186
 
 
187
static void
 
188
mpegts_base_reset (MpegTSBase * base)
 
189
{
 
190
  mpegts_packetizer_clear (base->packetizer);
 
191
  memset (base->is_pes, 0, 8192);
 
192
  memset (base->known_psi, 0, 8192);
 
193
 
 
194
  /* PAT */
 
195
  base->known_psi[0] = TRUE;
 
196
 
 
197
  /* FIXME : Commenting the Following lines is to be in sync with the following
 
198
   * commit
 
199
   *
 
200
   * 61a885613316ce7657c36a6cd215b43f9dc67b79
 
201
   *     mpegtsparse: don't free PAT structure which may still be needed later
 
202
   */
 
203
 
 
204
  /* if (base->pat != NULL) */
 
205
  /*   gst_structure_free (base->pat); */
 
206
  /* base->pat = NULL; */
 
207
  /* pmt pids will be added and removed dynamically */
 
208
 
 
209
}
 
210
 
 
211
static void
 
212
mpegts_base_init (MpegTSBase * base, MpegTSBaseClass * klass)
 
213
{
 
214
  base->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
 
215
  gst_pad_set_activate_function (base->sinkpad, mpegts_base_sink_activate);
 
216
  gst_pad_set_activatepull_function (base->sinkpad,
 
217
      mpegts_base_sink_activate_pull);
 
218
  gst_pad_set_activatepush_function (base->sinkpad,
 
219
      mpegts_base_sink_activate_push);
 
220
  gst_pad_set_chain_function (base->sinkpad, mpegts_base_chain);
 
221
  gst_pad_set_event_function (base->sinkpad, mpegts_base_sink_event);
 
222
  gst_element_add_pad (GST_ELEMENT (base), base->sinkpad);
 
223
 
 
224
  base->disposed = FALSE;
 
225
  base->packetizer = mpegts_packetizer_new ();
 
226
  base->programs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
 
227
      NULL, (GDestroyNotify) mpegts_base_free_program);
 
228
 
 
229
  base->is_pes = g_new0 (gboolean, 8192);
 
230
  base->known_psi = g_new0 (gboolean, 8192);
 
231
  mpegts_base_reset (base);
 
232
  base->program_size = sizeof (MpegTSBaseProgram);
 
233
  base->stream_size = sizeof (MpegTSBaseStream);
 
234
 
 
235
  base->mode = BASE_MODE_STREAMING;
 
236
  base->first_pat_offset = -1;
 
237
}
 
238
 
 
239
static void
 
240
mpegts_base_dispose (GObject * object)
 
241
{
 
242
  MpegTSBase *base = GST_MPEGTS_BASE (object);
 
243
 
 
244
  if (!base->disposed) {
 
245
    g_object_unref (base->packetizer);
 
246
    base->disposed = TRUE;
 
247
    g_free (base->known_psi);
 
248
    g_free (base->is_pes);
 
249
  }
 
250
 
 
251
  if (G_OBJECT_CLASS (parent_class)->dispose)
 
252
    G_OBJECT_CLASS (parent_class)->dispose (object);
 
253
}
 
254
 
 
255
static void
 
256
mpegts_base_finalize (GObject * object)
 
257
{
 
258
  MpegTSBase *base = GST_MPEGTS_BASE (object);
 
259
 
 
260
  if (base->pat) {
 
261
    gst_structure_free (base->pat);
 
262
    base->pat = NULL;
 
263
  }
 
264
  g_hash_table_destroy (base->programs);
 
265
 
 
266
  if (G_OBJECT_CLASS (parent_class)->finalize)
 
267
    G_OBJECT_CLASS (parent_class)->finalize (object);
 
268
}
 
269
 
 
270
static void
 
271
mpegts_base_set_property (GObject * object, guint prop_id,
 
272
    const GValue * value, GParamSpec * pspec)
 
273
{
 
274
  /* MpegTSBase *base = GST_MPEGTS_BASE (object); */
 
275
 
 
276
  switch (prop_id) {
 
277
    default:
 
278
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
279
  }
 
280
}
 
281
 
 
282
static void
 
283
mpegts_base_get_property (GObject * object, guint prop_id,
 
284
    GValue * value, GParamSpec * pspec)
 
285
{
 
286
  /* MpegTSBase *base = GST_MPEGTS_BASE (object); */
 
287
 
 
288
  switch (prop_id) {
 
289
    default:
 
290
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
291
  }
 
292
}
 
293
 
 
294
/* returns NULL if no matching descriptor found *
 
295
 * otherwise returns a descriptor that needs to *
 
296
 * be freed */
 
297
guint8 *
 
298
mpegts_get_descriptor_from_stream (MpegTSBaseStream * stream, guint8 tag)
 
299
{
 
300
  GValueArray *descriptors = NULL;
 
301
  GstStructure *stream_info = stream->stream_info;
 
302
  guint8 *retval = NULL;
 
303
  int i;
 
304
 
 
305
  gst_structure_get (stream_info, "descriptors", G_TYPE_VALUE_ARRAY,
 
306
      &descriptors, NULL);
 
307
  if (descriptors) {
 
308
    for (i = 0; i < descriptors->n_values; i++) {
 
309
      GValue *value = g_value_array_get_nth (descriptors, i);
 
310
      GString *desc = g_value_dup_boxed (value);
 
311
      if (DESC_TAG (desc->str) == tag) {
 
312
        retval = (guint8 *) desc->str;
 
313
        g_string_free (desc, FALSE);
 
314
        break;
 
315
      } else
 
316
        g_string_free (desc, FALSE);
 
317
    }
 
318
    g_value_array_free (descriptors);
 
319
  }
 
320
  return retval;
 
321
}
 
322
 
 
323
/* returns NULL if no matching descriptor found *
 
324
 * otherwise returns a descriptor that needs to *
 
325
 * be freed */
 
326
guint8 *
 
327
mpegts_get_descriptor_from_program (MpegTSBaseProgram * program, guint8 tag)
 
328
{
 
329
  GValueArray *descriptors = NULL;
 
330
  GstStructure *program_info;
 
331
  guint8 *retval = NULL;
 
332
  int i;
 
333
 
 
334
  if (G_UNLIKELY (program == NULL))
 
335
    return NULL;
 
336
  program_info = program->pmt_info;
 
337
  gst_structure_get (program_info, "descriptors", G_TYPE_VALUE_ARRAY,
 
338
      &descriptors, NULL);
 
339
  if (descriptors) {
 
340
    for (i = 0; i < descriptors->n_values; i++) {
 
341
      GValue *value = g_value_array_get_nth (descriptors, i);
 
342
      GString *desc = g_value_dup_boxed (value);
 
343
      if (DESC_TAG (desc->str) == tag) {
 
344
        retval = (guint8 *) desc->str;
 
345
        g_string_free (desc, FALSE);
 
346
        break;
 
347
      } else
 
348
        g_string_free (desc, FALSE);
 
349
    }
 
350
    g_value_array_free (descriptors);
 
351
  }
 
352
  return retval;
 
353
}
 
354
 
 
355
MpegTSBaseProgram *
 
356
mpegts_base_add_program (MpegTSBase * base,
 
357
    gint program_number, guint16 pmt_pid)
 
358
{
 
359
  MpegTSBaseProgram *program;
 
360
 
 
361
  program = g_malloc0 (base->program_size);
 
362
  program->program_number = program_number;
 
363
  program->pmt_pid = pmt_pid;
 
364
  program->pcr_pid = G_MAXUINT16;
 
365
  program->streams = g_new0 (MpegTSBaseStream *, 0x2000);
 
366
  program->patcount = 0;
 
367
 
 
368
  g_hash_table_insert (base->programs,
 
369
      GINT_TO_POINTER (program_number), program);
 
370
 
 
371
  return program;
 
372
}
 
373
 
 
374
MpegTSBaseProgram *
 
375
mpegts_base_get_program (MpegTSBase * base, gint program_number)
 
376
{
 
377
  MpegTSBaseProgram *program;
 
378
 
 
379
  program = (MpegTSBaseProgram *) g_hash_table_lookup (base->programs,
 
380
      GINT_TO_POINTER ((gint) program_number));
 
381
 
 
382
  return program;
 
383
}
 
384
 
 
385
#if 0
 
386
static GstPad *
 
387
mpegts_base_activate_program (MpegTSBase * base, MpegTSBaseProgram * program)
 
388
{
 
389
  MpegTSBasePad *tspad;
 
390
  gchar *pad_name;
 
391
 
 
392
  pad_name = g_strdup_printf ("program_%d", program->program_number);
 
393
 
 
394
  tspad = mpegts_base_create_tspad (base, pad_name);
 
395
  tspad->program_number = program->program_number;
 
396
  tspad->program = program;
 
397
  program->tspad = tspad;
 
398
  g_free (pad_name);
 
399
  gst_pad_set_active (tspad->pad, TRUE);
 
400
  program->active = TRUE;
 
401
 
 
402
  return tspad->pad;
 
403
}
 
404
 
 
405
static GstPad *
 
406
mpegts_base_deactivate_program (MpegTSBase * base, MpegTSBaseProgram * program)
 
407
{
 
408
  MpegTSBasePad *tspad;
 
409
 
 
410
  tspad = program->tspad;
 
411
  gst_pad_set_active (tspad->pad, FALSE);
 
412
  program->active = FALSE;
 
413
 
 
414
  /* tspad will be destroyed in GstElementClass::pad_removed */
 
415
 
 
416
  return tspad->pad;
 
417
}
 
418
#endif
 
419
 
 
420
 
 
421
static void
 
422
mpegts_base_free_program (MpegTSBaseProgram * program)
 
423
{
 
424
  guint i;
 
425
 
 
426
  if (program->pmt_info)
 
427
    gst_structure_free (program->pmt_info);
 
428
 
 
429
  for (i = 0; i < 0x2000; i++)
 
430
    if (program->streams[i])
 
431
      mpegts_base_free_stream (program->streams[i]);
 
432
  g_free (program->streams);
 
433
 
 
434
  if (program->tags)
 
435
    gst_tag_list_free (program->tags);
 
436
 
 
437
  g_free (program);
 
438
}
 
439
 
 
440
void
 
441
mpegts_base_remove_program (MpegTSBase * base, gint program_number)
 
442
{
 
443
  MpegTSBaseProgram *program;
 
444
  MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
 
445
 
 
446
  if (klass->program_stopped) {
 
447
    program =
 
448
        (MpegTSBaseProgram *) g_hash_table_lookup (base->programs,
 
449
        GINT_TO_POINTER (program_number));
 
450
    klass->program_stopped (base, program);
 
451
  }
 
452
  g_hash_table_remove (base->programs, GINT_TO_POINTER (program_number));
 
453
 
 
454
}
 
455
 
 
456
static MpegTSBaseStream *
 
457
mpegts_base_program_add_stream (MpegTSBase * base,
 
458
    MpegTSBaseProgram * program, guint16 pid, guint8 stream_type,
 
459
    GstStructure * stream_info)
 
460
{
 
461
  MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
 
462
  MpegTSBaseStream *stream;
 
463
 
 
464
  GST_DEBUG ("pid:0x%04x, stream_type:0x%03x, stream_info:%" GST_PTR_FORMAT,
 
465
      pid, stream_type, stream_info);
 
466
 
 
467
  stream = g_malloc0 (base->stream_size);
 
468
  stream->pid = pid;
 
469
  stream->stream_type = stream_type;
 
470
  stream->stream_info = stream_info;
 
471
 
 
472
  program->streams[pid] = stream;
 
473
 
 
474
  if (klass->stream_added)
 
475
    klass->stream_added (base, stream, program);
 
476
 
 
477
  return stream;
 
478
}
 
479
 
 
480
static void
 
481
mpegts_base_free_stream (MpegTSBaseStream * stream)
 
482
{
 
483
  g_free (stream);
 
484
}
 
485
 
 
486
void
 
487
mpegts_base_program_remove_stream (MpegTSBase * base,
 
488
    MpegTSBaseProgram * program, guint16 pid)
 
489
{
 
490
  MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
 
491
 
 
492
  /* If subclass needs it, inform it of the stream we are about to remove */
 
493
  if (klass->stream_removed)
 
494
    klass->stream_removed (base, program->streams[pid]);
 
495
 
 
496
  mpegts_base_free_stream (program->streams[pid]);
 
497
  program->streams[pid] = NULL;
 
498
}
 
499
 
 
500
static void
 
501
mpegts_base_deactivate_pmt (MpegTSBase * base, MpegTSBaseProgram * program)
 
502
{
 
503
  gint i;
 
504
  guint pid;
 
505
  guint stream_type;
 
506
  GstStructure *stream;
 
507
  const GValue *streams;
 
508
  const GValue *value;
 
509
  MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
 
510
 
 
511
  if (program->pmt_info) {
 
512
    /* Inform subclasses we're deactivating this program */
 
513
    if (klass->program_stopped)
 
514
      klass->program_stopped (base, program);
 
515
 
 
516
    streams = gst_structure_id_get_value (program->pmt_info, QUARK_STREAMS);
 
517
 
 
518
    for (i = 0; i < gst_value_list_get_size (streams); ++i) {
 
519
      value = gst_value_list_get_value (streams, i);
 
520
      stream = g_value_get_boxed (value);
 
521
      gst_structure_id_get (stream, QUARK_PID, G_TYPE_UINT, &pid,
 
522
          QUARK_STREAM_TYPE, G_TYPE_UINT, &stream_type, NULL);
 
523
      mpegts_base_program_remove_stream (base, program, (guint16) pid);
 
524
      base->is_pes[pid] = FALSE;
 
525
    }
 
526
    /* remove pcr stream */
 
527
    mpegts_base_program_remove_stream (base, program, program->pcr_pid);
 
528
    base->is_pes[program->pcr_pid] = FALSE;
 
529
  }
 
530
}
 
531
 
 
532
 
 
533
gboolean
 
534
mpegts_base_is_psi (MpegTSBase * base, MpegTSPacketizerPacket * packet)
 
535
{
 
536
  gboolean retval = FALSE;
 
537
  guint8 table_id;
 
538
  int i;
 
539
  static const guint8 si_tables[] =
 
540
      { 0x00, 0x01, 0x02, 0x03, 0x40, 0x41, 0x42, 0x46, 0x4A,
 
541
    0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
 
542
    0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65,
 
543
    0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
 
544
    0x72, 0x73, 0x7E, 0x7F, TABLE_ID_UNSET
 
545
  };
 
546
 
 
547
  if (base->known_psi[packet->pid])
 
548
    retval = TRUE;
 
549
 
 
550
  /* check is it is a pes pid */
 
551
  if (base->is_pes[packet->pid])
 
552
    return FALSE;
 
553
 
 
554
  if (!retval) {
 
555
    if (packet->payload_unit_start_indicator) {
 
556
      table_id = *(packet->data);
 
557
      i = 0;
 
558
      while (si_tables[i] != TABLE_ID_UNSET) {
 
559
        if (G_UNLIKELY (si_tables[i] == table_id)) {
 
560
          GST_DEBUG_OBJECT (base, "Packet has table id 0x%x", table_id);
 
561
          retval = TRUE;
 
562
          break;
 
563
        }
 
564
        i++;
 
565
      }
 
566
    } else {
 
567
      MpegTSPacketizerStream *stream = (MpegTSPacketizerStream *)
 
568
          base->packetizer->streams[packet->pid];
 
569
 
 
570
      if (stream) {
 
571
        i = 0;
 
572
        GST_DEBUG_OBJECT (base, "section table id: 0x%x",
 
573
            stream->section_table_id);
 
574
        while (si_tables[i] != TABLE_ID_UNSET) {
 
575
          if (G_UNLIKELY (si_tables[i] == stream->section_table_id)) {
 
576
            retval = TRUE;
 
577
            break;
 
578
          }
 
579
          i++;
 
580
        }
 
581
      }
 
582
    }
 
583
  }
 
584
 
 
585
  GST_LOG_OBJECT (base, "Packet of pid 0x%x is psi: %d", packet->pid, retval);
 
586
  return retval;
 
587
}
 
588
 
 
589
static void
 
590
mpegts_base_apply_pat (MpegTSBase * base, GstStructure * pat_info)
 
591
{
 
592
  const GValue *value;
 
593
  GstStructure *old_pat;
 
594
  GstStructure *program_info;
 
595
  guint program_number;
 
596
  guint pid;
 
597
  MpegTSBaseProgram *program;
 
598
  gint i;
 
599
  const GValue *programs;
 
600
  MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
 
601
 
 
602
  old_pat = base->pat;
 
603
  base->pat = gst_structure_copy (pat_info);
 
604
 
 
605
  GST_INFO_OBJECT (base, "PAT %" GST_PTR_FORMAT, pat_info);
 
606
 
 
607
  gst_element_post_message (GST_ELEMENT_CAST (base),
 
608
      gst_message_new_element (GST_OBJECT (base),
 
609
          gst_structure_copy (pat_info)));
 
610
 
 
611
  programs = gst_structure_id_get_value (pat_info, QUARK_PROGRAMS);
 
612
  /* activate the new table */
 
613
  for (i = 0; i < gst_value_list_get_size (programs); ++i) {
 
614
    value = gst_value_list_get_value (programs, i);
 
615
 
 
616
    program_info = g_value_get_boxed (value);
 
617
    gst_structure_id_get (program_info, QUARK_PROGRAM_NUMBER, G_TYPE_UINT,
 
618
        &program_number, QUARK_PID, G_TYPE_UINT, &pid, NULL);
 
619
 
 
620
    program = mpegts_base_get_program (base, program_number);
 
621
    if (program) {
 
622
      if (program->pmt_pid != pid) {
 
623
        if (program->pmt_pid != G_MAXUINT16) {
 
624
          /* pmt pid changed */
 
625
          /* FIXME: when this happens it may still be pmt pid of another
 
626
           * program, so setting to False may make it go through expensive
 
627
           * path in is_psi unnecessarily */
 
628
          base->known_psi[program->pmt_pid] = FALSE;
 
629
        }
 
630
 
 
631
        program->pmt_pid = pid;
 
632
        base->known_psi[pid] = TRUE;
 
633
      }
 
634
    } else {
 
635
      base->known_psi[pid] = TRUE;
 
636
      program = mpegts_base_add_program (base, program_number, pid);
 
637
    }
 
638
    program->patcount += 1;
 
639
  }
 
640
 
 
641
  if (old_pat) {
 
642
    /* deactivate the old table */
 
643
 
 
644
    programs = gst_structure_id_get_value (old_pat, QUARK_PROGRAMS);
 
645
    for (i = 0; i < gst_value_list_get_size (programs); ++i) {
 
646
      value = gst_value_list_get_value (programs, i);
 
647
 
 
648
      program_info = g_value_get_boxed (value);
 
649
      gst_structure_id_get (program_info,
 
650
          QUARK_PROGRAM_NUMBER, G_TYPE_UINT, &program_number,
 
651
          QUARK_PID, G_TYPE_UINT, &pid, NULL);
 
652
 
 
653
      program = mpegts_base_get_program (base, program_number);
 
654
      if (program == NULL) {
 
655
        GST_DEBUG_OBJECT (base, "broken PAT, duplicated entry for program %d",
 
656
            program_number);
 
657
        continue;
 
658
      }
 
659
 
 
660
      if (--program->patcount > 0)
 
661
        /* the program has been referenced by the new pat, keep it */
 
662
        continue;
 
663
 
 
664
      GST_INFO_OBJECT (base, "PAT removing program %" GST_PTR_FORMAT,
 
665
          program_info);
 
666
 
 
667
      if (klass->program_stopped) {
 
668
        klass->program_stopped (base, program);
 
669
      }
 
670
      mpegts_base_deactivate_pmt (base, program);
 
671
      mpegts_base_remove_program (base, program_number);
 
672
      /* FIXME: when this happens it may still be pmt pid of another
 
673
       * program, so setting to False may make it go through expensive
 
674
       * path in is_psi unnecessarily */
 
675
      base->known_psi[pid] = TRUE;
 
676
      mpegts_packetizer_remove_stream (base->packetizer, pid);
 
677
    }
 
678
 
 
679
    gst_structure_free (old_pat);
 
680
  }
 
681
#if 0
 
682
  mpegts_base_sync_program_pads (base);
 
683
#endif
 
684
}
 
685
 
 
686
static void
 
687
mpegts_base_apply_pmt (MpegTSBase * base,
 
688
    guint16 pmt_pid, GstStructure * pmt_info)
 
689
{
 
690
  MpegTSBaseProgram *program;
 
691
  guint program_number;
 
692
  guint pcr_pid;
 
693
  guint pid;
 
694
  guint stream_type;
 
695
  GstStructure *stream;
 
696
  gint i;
 
697
  const GValue *new_streams;
 
698
  const GValue *value;
 
699
  MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
 
700
 
 
701
  if (G_UNLIKELY (base->first_pat_offset == -1)) {
 
702
    GST_WARNING ("Got pmt without pat first. Returning");
 
703
    /* remove the stream since we won't get another PMT otherwise */
 
704
    mpegts_packetizer_remove_stream (base->packetizer, pmt_pid);
 
705
    return;
 
706
  }
 
707
 
 
708
  gst_structure_id_get (pmt_info,
 
709
      QUARK_PROGRAM_NUMBER, G_TYPE_UINT, &program_number,
 
710
      QUARK_PCR_PID, G_TYPE_UINT, &pcr_pid, NULL);
 
711
  new_streams = gst_structure_id_get_value (pmt_info, QUARK_STREAMS);
 
712
 
 
713
  program = mpegts_base_get_program (base, program_number);
 
714
  if (program) {
 
715
    /* deactivate old pmt */ ;
 
716
    mpegts_base_deactivate_pmt (base, program);
 
717
    if (program->pmt_info)
 
718
      gst_structure_free (program->pmt_info);
 
719
    program->pmt_info = NULL;
 
720
  } else {
 
721
    /* no PAT?? */
 
722
    base->known_psi[pmt_pid] = TRUE;
 
723
    program = mpegts_base_add_program (base, program_number, pid);
 
724
  }
 
725
 
 
726
  /* activate new pmt */
 
727
  program->pmt_info = gst_structure_copy (pmt_info);
 
728
  program->pmt_pid = pmt_pid;
 
729
  program->pcr_pid = pcr_pid;
 
730
  mpegts_base_program_add_stream (base, program, (guint16) pcr_pid, -1, NULL);
 
731
  base->is_pes[pcr_pid] = TRUE;
 
732
 
 
733
  for (i = 0; i < gst_value_list_get_size (new_streams); ++i) {
 
734
    value = gst_value_list_get_value (new_streams, i);
 
735
    stream = g_value_get_boxed (value);
 
736
 
 
737
    gst_structure_id_get (stream, QUARK_PID, G_TYPE_UINT, &pid,
 
738
        QUARK_STREAM_TYPE, G_TYPE_UINT, &stream_type, NULL);
 
739
    base->is_pes[pid] = TRUE;
 
740
    mpegts_base_program_add_stream (base, program,
 
741
        (guint16) pid, (guint8) stream_type, stream);
 
742
 
 
743
  }
 
744
 
 
745
  if (klass->program_started != NULL) {
 
746
    klass->program_started (base, program);
 
747
  }
 
748
 
 
749
  GST_DEBUG_OBJECT (base, "new pmt %" GST_PTR_FORMAT, pmt_info);
 
750
 
 
751
  gst_element_post_message (GST_ELEMENT_CAST (base),
 
752
      gst_message_new_element (GST_OBJECT (base),
 
753
          gst_structure_copy (pmt_info)));
 
754
}
 
755
 
 
756
static void
 
757
mpegts_base_apply_nit (MpegTSBase * base,
 
758
    guint16 pmt_pid, GstStructure * nit_info)
 
759
{
 
760
  GST_DEBUG_OBJECT (base, "NIT %" GST_PTR_FORMAT, nit_info);
 
761
 
 
762
  gst_element_post_message (GST_ELEMENT_CAST (base),
 
763
      gst_message_new_element (GST_OBJECT (base),
 
764
          gst_structure_copy (nit_info)));
 
765
}
 
766
 
 
767
static void
 
768
mpegts_base_apply_sdt (MpegTSBase * base,
 
769
    guint16 pmt_pid, GstStructure * sdt_info)
 
770
{
 
771
  GST_DEBUG_OBJECT (base, "SDT %" GST_PTR_FORMAT, sdt_info);
 
772
 
 
773
  mpegts_base_get_tags_from_sdt (base, sdt_info);
 
774
 
 
775
  gst_element_post_message (GST_ELEMENT_CAST (base),
 
776
      gst_message_new_element (GST_OBJECT (base),
 
777
          gst_structure_copy (sdt_info)));
 
778
}
 
779
 
 
780
static void
 
781
mpegts_base_apply_eit (MpegTSBase * base,
 
782
    guint16 pmt_pid, GstStructure * eit_info)
 
783
{
 
784
  GST_DEBUG_OBJECT (base, "EIT %" GST_PTR_FORMAT, eit_info);
 
785
 
 
786
  mpegts_base_get_tags_from_eit (base, eit_info);
 
787
 
 
788
  gst_element_post_message (GST_ELEMENT_CAST (base),
 
789
      gst_message_new_element (GST_OBJECT (base),
 
790
          gst_structure_copy (eit_info)));
 
791
}
 
792
 
 
793
static void
 
794
mpegts_base_apply_tdt (MpegTSBase * base,
 
795
    guint16 tdt_pid, GstStructure * tdt_info)
 
796
{
 
797
  gst_element_post_message (GST_ELEMENT_CAST (base),
 
798
      gst_message_new_element (GST_OBJECT (base),
 
799
          gst_structure_copy (tdt_info)));
 
800
 
 
801
  GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base,
 
802
      gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM,
 
803
          gst_structure_copy (tdt_info)));
 
804
}
 
805
 
 
806
 
 
807
gboolean
 
808
mpegts_base_handle_psi (MpegTSBase * base, MpegTSPacketizerSection * section)
 
809
{
 
810
  gboolean res = TRUE;
 
811
  GstStructure *structure = NULL;
 
812
 
 
813
  /* table ids 0x70 - 0x73 do not have a crc */
 
814
  if (G_LIKELY (section->table_id < 0x70 || section->table_id > 0x73)) {
 
815
    if (G_UNLIKELY (mpegts_base_calc_crc32 (GST_BUFFER_DATA (section->buffer),
 
816
                GST_BUFFER_SIZE (section->buffer)) != 0)) {
 
817
      GST_WARNING_OBJECT (base, "bad crc in psi pid 0x%x", section->pid);
 
818
      return FALSE;
 
819
    }
 
820
  }
 
821
 
 
822
  switch (section->table_id) {
 
823
    case 0x00:
 
824
      /* PAT */
 
825
      structure = mpegts_packetizer_parse_pat (base->packetizer, section);
 
826
      if (G_LIKELY (structure)) {
 
827
        mpegts_base_apply_pat (base, structure);
 
828
        if (base->first_pat_offset == -1) {
 
829
 
 
830
          base->first_pat_offset = GST_BUFFER_OFFSET (section->buffer);
 
831
          GST_DEBUG ("First PAT offset: %" G_GUINT64_FORMAT,
 
832
              base->first_pat_offset);
 
833
        }
 
834
 
 
835
      } else
 
836
        res = FALSE;
 
837
 
 
838
      break;
 
839
    case 0x02:
 
840
      structure = mpegts_packetizer_parse_pmt (base->packetizer, section);
 
841
      if (G_LIKELY (structure))
 
842
        mpegts_base_apply_pmt (base, section->pid, structure);
 
843
      else
 
844
        res = FALSE;
 
845
 
 
846
      break;
 
847
    case 0x40:
 
848
      /* NIT, actual network */
 
849
    case 0x41:
 
850
      /* NIT, other network */
 
851
      structure = mpegts_packetizer_parse_nit (base->packetizer, section);
 
852
      if (G_LIKELY (structure))
 
853
        mpegts_base_apply_nit (base, section->pid, structure);
 
854
      else
 
855
        res = FALSE;
 
856
 
 
857
      break;
 
858
    case 0x42:
 
859
    case 0x46:
 
860
      structure = mpegts_packetizer_parse_sdt (base->packetizer, section);
 
861
      if (G_LIKELY (structure))
 
862
        mpegts_base_apply_sdt (base, section->pid, structure);
 
863
      else
 
864
        res = FALSE;
 
865
      break;
 
866
    case 0x4E:
 
867
    case 0x4F:
 
868
      /* EIT, present/following */
 
869
    case 0x50:
 
870
    case 0x51:
 
871
    case 0x52:
 
872
    case 0x53:
 
873
    case 0x54:
 
874
    case 0x55:
 
875
    case 0x56:
 
876
    case 0x57:
 
877
    case 0x58:
 
878
    case 0x59:
 
879
    case 0x5A:
 
880
    case 0x5B:
 
881
    case 0x5C:
 
882
    case 0x5D:
 
883
    case 0x5E:
 
884
    case 0x5F:
 
885
    case 0x60:
 
886
    case 0x61:
 
887
    case 0x62:
 
888
    case 0x63:
 
889
    case 0x64:
 
890
    case 0x65:
 
891
    case 0x66:
 
892
    case 0x67:
 
893
    case 0x68:
 
894
    case 0x69:
 
895
    case 0x6A:
 
896
    case 0x6B:
 
897
    case 0x6C:
 
898
    case 0x6D:
 
899
    case 0x6E:
 
900
    case 0x6F:
 
901
      /* EIT, schedule */
 
902
      structure = mpegts_packetizer_parse_eit (base->packetizer, section);
 
903
      if (G_LIKELY (structure))
 
904
        mpegts_base_apply_eit (base, section->pid, structure);
 
905
      else
 
906
        res = FALSE;
 
907
      break;
 
908
    case 0x70:
 
909
      /* TDT (Time and Date table) */
 
910
      structure = mpegts_packetizer_parse_tdt (base->packetizer, section);
 
911
      if (G_LIKELY (structure))
 
912
        mpegts_base_apply_tdt (base, section->pid, structure);
 
913
      else
 
914
        res = FALSE;
 
915
      break;
 
916
    default:
 
917
      break;
 
918
  }
 
919
 
 
920
  if (structure)
 
921
    gst_structure_free (structure);
 
922
 
 
923
  return res;
 
924
}
 
925
 
 
926
static void
 
927
mpegts_base_get_tags_from_sdt (MpegTSBase * base, GstStructure * sdt_info)
 
928
{
 
929
  const GValue *services;
 
930
  guint i;
 
931
 
 
932
  services = gst_structure_get_value (sdt_info, "services");
 
933
 
 
934
  for (i = 0; i < gst_value_list_get_size (services); i++) {
 
935
    const GstStructure *service;
 
936
    const gchar *sid_str;
 
937
    gchar *tmp;
 
938
    gint program_number;
 
939
    MpegTSBaseProgram *program;
 
940
 
 
941
    service = gst_value_get_structure (gst_value_list_get_value (services, i));
 
942
 
 
943
    /* get program_number from structure name
 
944
     * which looks like service-%d */
 
945
    sid_str = gst_structure_get_name (service);
 
946
    tmp = g_strstr_len (sid_str, -1, "-");
 
947
    program_number = atoi (++tmp);
 
948
 
 
949
    program = mpegts_base_get_program (base, program_number);
 
950
    if (program && !program->tags) {
 
951
      program->tags = gst_tag_list_new_full (GST_TAG_ARTIST,
 
952
          gst_structure_get_string (service, "name"), NULL);
 
953
    }
 
954
  }
 
955
}
 
956
 
 
957
static void
 
958
mpegts_base_get_tags_from_eit (MpegTSBase * base, GstStructure * eit_info)
 
959
{
 
960
  const GValue *events;
 
961
  guint i;
 
962
  guint program_number;
 
963
  MpegTSBaseProgram *program;
 
964
  gboolean present_following;
 
965
 
 
966
  gst_structure_get_uint (eit_info, "service-id", &program_number);
 
967
  program = mpegts_base_get_program (base, program_number);
 
968
 
 
969
  gst_structure_get_boolean (eit_info, "present-following", &present_following);
 
970
 
 
971
  if (program && present_following) {
 
972
    events = gst_structure_get_value (eit_info, "events");
 
973
 
 
974
    for (i = 0; i < gst_value_list_get_size (events); i++) {
 
975
      const GstStructure *event;
 
976
      const gchar *title;
 
977
      guint status;
 
978
      guint event_id;
 
979
      guint duration;
 
980
 
 
981
      event = gst_value_get_structure (gst_value_list_get_value (events, i));
 
982
 
 
983
      title = gst_structure_get_string (event, "name");
 
984
      gst_structure_get_uint (event, "event-id", &event_id);
 
985
      gst_structure_get_uint (event, "running-status", &status);
 
986
 
 
987
      if (title && event_id != program->event_id
 
988
          && status == RUNNING_STATUS_RUNNING) {
 
989
        gst_structure_get_uint (event, "duration", &duration);
 
990
 
 
991
        program->event_id = event_id;
 
992
        program->tags = gst_tag_list_new_full (GST_TAG_TITLE,
 
993
            title, GST_TAG_DURATION, duration * GST_SECOND, NULL);
 
994
      }
 
995
    }
 
996
  }
 
997
}
 
998
 
 
999
 
 
1000
static gboolean
 
1001
mpegts_base_sink_event (GstPad * pad, GstEvent * event)
 
1002
{
 
1003
  gboolean res;
 
1004
  MpegTSBase *base = GST_MPEGTS_BASE (gst_object_get_parent (GST_OBJECT (pad)));
 
1005
 
 
1006
  GST_WARNING_OBJECT (base, "Got event %s",
 
1007
      gst_event_type_get_name (GST_EVENT_TYPE (event)));
 
1008
 
 
1009
  switch (GST_EVENT_TYPE (event)) {
 
1010
    case GST_EVENT_NEWSEGMENT:
 
1011
      /* FIXME : STORE NEW SEGMENT ! */
 
1012
      gst_event_unref (event);
 
1013
      res = FALSE;
 
1014
      break;
 
1015
    case GST_EVENT_FLUSH_STOP:
 
1016
      mpegts_packetizer_clear (base->packetizer);
 
1017
      /* Passthrough */
 
1018
    default:
 
1019
      res = GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, event);
 
1020
      gst_event_unref (event);
 
1021
  }
 
1022
 
 
1023
  gst_object_unref (base);
 
1024
  return res;
 
1025
}
 
1026
 
 
1027
static inline GstFlowReturn
 
1028
mpegts_base_push (MpegTSBase * base, MpegTSPacketizerPacket * packet,
 
1029
    MpegTSPacketizerSection * section)
 
1030
{
 
1031
  MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
 
1032
 
 
1033
  /* Call implementation */
 
1034
  if (G_UNLIKELY (klass->push == NULL)) {
 
1035
    GST_ERROR_OBJECT (base, "Class doesn't have a 'push' implementation !");
 
1036
    return GST_FLOW_ERROR;
 
1037
  }
 
1038
 
 
1039
  return klass->push (base, packet, section);
 
1040
}
 
1041
 
 
1042
static GstFlowReturn
 
1043
mpegts_base_chain (GstPad * pad, GstBuffer * buf)
 
1044
{
 
1045
  GstFlowReturn res = GST_FLOW_OK;
 
1046
  MpegTSBase *base;
 
1047
  gboolean based;
 
1048
  MpegTSPacketizerPacketReturn pret;
 
1049
  MpegTSPacketizer2 *packetizer;
 
1050
  MpegTSPacketizerPacket packet;
 
1051
 
 
1052
  base = GST_MPEGTS_BASE (gst_object_get_parent (GST_OBJECT (pad)));
 
1053
  packetizer = base->packetizer;
 
1054
 
 
1055
  mpegts_packetizer_push (base->packetizer, buf);
 
1056
  while (((pret =
 
1057
              mpegts_packetizer_next_packet (base->packetizer,
 
1058
                  &packet)) != PACKET_NEED_MORE) && res == GST_FLOW_OK) {
 
1059
    if (G_UNLIKELY (pret == PACKET_BAD))
 
1060
      /* bad header, skip the packet */
 
1061
      goto next;
 
1062
 
 
1063
    /* base PSI data */
 
1064
    if (packet.payload != NULL && mpegts_base_is_psi (base, &packet)) {
 
1065
      MpegTSPacketizerSection section;
 
1066
      based = mpegts_packetizer_push_section (packetizer, &packet, &section);
 
1067
      if (G_UNLIKELY (!based))
 
1068
        /* bad section data */
 
1069
        goto next;
 
1070
 
 
1071
      if (G_LIKELY (section.complete)) {
 
1072
        /* section complete */
 
1073
        based = mpegts_base_handle_psi (base, &section);
 
1074
        gst_buffer_unref (section.buffer);
 
1075
 
 
1076
        if (G_UNLIKELY (!based))
 
1077
          /* bad PSI table */
 
1078
          goto next;
 
1079
      }
 
1080
      /* we need to push section packet downstream */
 
1081
      res = mpegts_base_push (base, &packet, &section);
 
1082
 
 
1083
    } else if (base->is_pes[packet.pid]) {
 
1084
      /* push the packet downstream */
 
1085
      res = mpegts_base_push (base, &packet, NULL);
 
1086
    } else
 
1087
      gst_buffer_unref (packet.buffer);
 
1088
 
 
1089
  next:
 
1090
    mpegts_packetizer_clear_packet (base->packetizer, &packet);
 
1091
  }
 
1092
 
 
1093
  gst_object_unref (base);
 
1094
  return res;
 
1095
}
 
1096
 
 
1097
static GstFlowReturn
 
1098
mpegts_base_scan (MpegTSBase * base)
 
1099
{
 
1100
  GstFlowReturn ret;
 
1101
  GstBuffer *buf;
 
1102
  guint i;
 
1103
  MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
 
1104
 
 
1105
  GST_DEBUG ("Scanning for initial sync point");
 
1106
 
 
1107
  /* Find initial sync point */
 
1108
  for (i = 0; i < 10; i++) {
 
1109
    GST_DEBUG ("Grabbing %d => %d",
 
1110
        i * 50 * MPEGTS_MAX_PACKETSIZE, 50 * MPEGTS_MAX_PACKETSIZE);
 
1111
    ret = gst_pad_pull_range (base->sinkpad, i * 50 * MPEGTS_MAX_PACKETSIZE,
 
1112
        50 * MPEGTS_MAX_PACKETSIZE, &buf);
 
1113
    if (G_UNLIKELY (ret != GST_FLOW_OK))
 
1114
      goto beach;
 
1115
 
 
1116
    /* Push to packetizer */
 
1117
    mpegts_packetizer_push (base->packetizer, buf);
 
1118
 
 
1119
    if (mpegts_packetizer_has_packets (base->packetizer)) {
 
1120
      /* Mark the initial sync point and remember the packetsize */
 
1121
      base->initial_sync_point = base->seek_offset = base->packetizer->offset;
 
1122
      GST_DEBUG ("Sync point is now %" G_GUINT64_FORMAT, base->seek_offset);
 
1123
      base->packetsize = base->packetizer->packet_size;
 
1124
 
 
1125
      /* If the subclass can seek for timestamps, do that */
 
1126
      if (klass->find_timestamps) {
 
1127
        guint64 offset;
 
1128
        mpegts_packetizer_clear (base->packetizer);
 
1129
 
 
1130
        ret = klass->find_timestamps (base, 0, &offset);
 
1131
 
 
1132
        base->initial_sync_point = base->seek_offset =
 
1133
            base->packetizer->offset = base->first_pat_offset;
 
1134
        GST_DEBUG ("Sync point is now %" G_GUINT64_FORMAT, base->seek_offset);
 
1135
      }
 
1136
      goto beach;
 
1137
    }
 
1138
  }
 
1139
 
 
1140
  GST_WARNING ("Didn't find initial sync point");
 
1141
  ret = GST_FLOW_ERROR;
 
1142
 
 
1143
beach:
 
1144
  mpegts_packetizer_clear (base->packetizer);
 
1145
  return ret;
 
1146
 
 
1147
}
 
1148
 
 
1149
 
 
1150
static void
 
1151
mpegts_base_loop (MpegTSBase * base)
 
1152
{
 
1153
  GstFlowReturn ret = GST_FLOW_ERROR;
 
1154
  switch (base->mode) {
 
1155
    case BASE_MODE_SCANNING:
 
1156
      /* Find first sync point */
 
1157
      ret = mpegts_base_scan (base);
 
1158
      if (G_UNLIKELY (ret != GST_FLOW_OK))
 
1159
        goto error;
 
1160
      base->mode = BASE_MODE_STREAMING;
 
1161
      GST_DEBUG ("Changing to Streaming");
 
1162
      break;
 
1163
    case BASE_MODE_SEEKING:
 
1164
      /* FIXME : yes, we should do something here */
 
1165
      base->mode = BASE_MODE_STREAMING;
 
1166
      break;
 
1167
    case BASE_MODE_STREAMING:
 
1168
    {
 
1169
      GstBuffer *buf;
 
1170
 
 
1171
      GST_DEBUG ("Pulling data from %" G_GUINT64_FORMAT, base->seek_offset);
 
1172
 
 
1173
      ret = gst_pad_pull_range (base->sinkpad, base->seek_offset,
 
1174
          100 * base->packetsize, &buf);
 
1175
      if (G_UNLIKELY (ret != GST_FLOW_OK))
 
1176
        goto error;
 
1177
      base->seek_offset += GST_BUFFER_SIZE (buf);
 
1178
      ret = mpegts_base_chain (base->sinkpad, buf);
 
1179
      if (G_UNLIKELY (ret != GST_FLOW_OK))
 
1180
        goto error;
 
1181
    }
 
1182
      break;
 
1183
  }
 
1184
 
 
1185
  return;
 
1186
 
 
1187
error:
 
1188
  {
 
1189
    const gchar *reason = gst_flow_get_name (ret);
 
1190
    GST_DEBUG_OBJECT (base, "Pausing task, reason %s", reason);
 
1191
    if (ret == GST_FLOW_UNEXPECTED)
 
1192
      GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, gst_event_new_eos ());
 
1193
    else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) {
 
1194
      GST_ELEMENT_ERROR (base, STREAM, FAILED,
 
1195
          (_("Internal data stream error.")),
 
1196
          ("stream stopped, reason %s", reason));
 
1197
      GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, gst_event_new_eos ());
 
1198
    }
 
1199
    gst_pad_pause_task (base->sinkpad);
 
1200
  }
 
1201
}
 
1202
 
 
1203
static gboolean
 
1204
mpegts_base_sink_activate (GstPad * pad)
 
1205
{
 
1206
  if (gst_pad_check_pull_range (pad)) {
 
1207
    GST_DEBUG_OBJECT (pad, "activating pull");
 
1208
    return gst_pad_activate_pull (pad, TRUE);
 
1209
  } else {
 
1210
    GST_DEBUG_OBJECT (pad, "activating push");
 
1211
    return gst_pad_activate_push (pad, TRUE);
 
1212
  }
 
1213
}
 
1214
 
 
1215
static gboolean
 
1216
mpegts_base_sink_activate_pull (GstPad * pad, gboolean active)
 
1217
{
 
1218
  MpegTSBase *base = GST_MPEGTS_BASE (GST_OBJECT_PARENT (pad));
 
1219
  if (active) {
 
1220
    base->mode = BASE_MODE_SCANNING;
 
1221
    return gst_pad_start_task (pad, (GstTaskFunction) mpegts_base_loop, base);
 
1222
  } else
 
1223
    return gst_pad_stop_task (pad);
 
1224
}
 
1225
 
 
1226
static gboolean
 
1227
mpegts_base_sink_activate_push (GstPad * pad, gboolean active)
 
1228
{
 
1229
  return TRUE;
 
1230
}
 
1231
 
 
1232
 
 
1233
static GstStateChangeReturn
 
1234
mpegts_base_change_state (GstElement * element, GstStateChange transition)
 
1235
{
 
1236
  MpegTSBase *base;
 
1237
  GstStateChangeReturn ret;
 
1238
 
 
1239
  base = GST_MPEGTS_BASE (element);
 
1240
  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
 
1241
 
 
1242
  switch (transition) {
 
1243
    case GST_STATE_CHANGE_PAUSED_TO_READY:
 
1244
      mpegts_base_reset (base);
 
1245
      break;
 
1246
    default:
 
1247
      break;
 
1248
  }
 
1249
 
 
1250
  return ret;
 
1251
}
 
1252
 
 
1253
gboolean
 
1254
gst_mpegtsbase_plugin_init (GstPlugin * plugin)
 
1255
{
 
1256
  GST_DEBUG_CATEGORY_INIT (mpegts_base_debug, "mpegtsbase", 0,
 
1257
      "MPEG transport stream base class");
 
1258
 
 
1259
  gst_mpegtsdesc_init_debug ();
 
1260
 
 
1261
  return TRUE;
 
1262
}