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

« back to all changes in this revision

Viewing changes to gst/mpegtsdemux/mpegtsparse.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
 * 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 "mpegtsbase.h"
 
32
#include "mpegtsparse.h"
 
33
#include "gstmpegdesc.h"
 
34
 
 
35
/* latency in mseconds */
 
36
#define TS_LATENCY 700
 
37
 
 
38
#define TABLE_ID_UNSET 0xFF
 
39
#define RUNNING_STATUS_RUNNING 4
 
40
 
 
41
GST_DEBUG_CATEGORY_STATIC (mpegts_parse_debug);
 
42
#define GST_CAT_DEFAULT mpegts_parse_debug
 
43
 
 
44
typedef struct _MpegTSParsePad MpegTSParsePad;
 
45
 
 
46
typedef struct
 
47
{
 
48
  MpegTSBaseProgram program;
 
49
  gint selected;
 
50
  gboolean active;
 
51
  MpegTSParsePad *tspad;
 
52
} MpegTSParseProgram;
 
53
 
 
54
struct _MpegTSParsePad
 
55
{
 
56
  GstPad *pad;
 
57
 
 
58
  /* the program number that the peer wants on this pad */
 
59
  gint program_number;
 
60
  MpegTSParseProgram *program;
 
61
 
 
62
  /* set to FALSE before a push and TRUE after */
 
63
  gboolean pushed;
 
64
 
 
65
  /* the return of the latest push */
 
66
  GstFlowReturn flow_return;
 
67
 
 
68
  GstTagList *tags;
 
69
  guint event_id;
 
70
};
 
71
 
 
72
static GstStaticPadTemplate src_template =
 
73
GST_STATIC_PAD_TEMPLATE ("src%d", GST_PAD_SRC,
 
74
    GST_PAD_REQUEST,
 
75
    GST_STATIC_CAPS ("video/mpegts, " "systemstream = (boolean) true ")
 
76
    );
 
77
 
 
78
static GstStaticPadTemplate program_template =
 
79
GST_STATIC_PAD_TEMPLATE ("program_%d", GST_PAD_SRC,
 
80
    GST_PAD_SOMETIMES,
 
81
    GST_STATIC_CAPS ("video/mpegts, " "systemstream = (boolean) true ")
 
82
    );
 
83
 
 
84
enum
 
85
{
 
86
  ARG_0,
 
87
  PROP_PROGRAM_NUMBERS,
 
88
  /* FILL ME */
 
89
};
 
90
 
 
91
static void
 
92
mpegts_parse_program_started (MpegTSBase * base, MpegTSBaseProgram * program);
 
93
static void
 
94
mpegts_parse_program_stopped (MpegTSBase * base, MpegTSBaseProgram * program);
 
95
 
 
96
static GstFlowReturn
 
97
mpegts_parse_push (MpegTSBase * base, MpegTSPacketizerPacket * packet,
 
98
    MpegTSPacketizerSection * section);
 
99
static void mpegts_parse_set_property (GObject * object, guint prop_id,
 
100
    const GValue * value, GParamSpec * pspec);
 
101
static void mpegts_parse_get_property (GObject * object, guint prop_id,
 
102
    GValue * value, GParamSpec * pspec);
 
103
static void mpegts_parse_finalize (GObject * object);
 
104
 
 
105
static MpegTSParsePad *mpegts_parse_create_tspad (MpegTSParse2 * parse,
 
106
    const gchar * name);
 
107
static void mpegts_parse_destroy_tspad (MpegTSParse2 * parse,
 
108
    MpegTSParsePad * tspad);
 
109
static GstPad *mpegts_parse_activate_program (MpegTSParse2 * parse,
 
110
    MpegTSParseProgram * program);
 
111
static void mpegts_parse_reset_selected_programs (MpegTSParse2 * parse,
 
112
    gchar * programs);
 
113
 
 
114
static void mpegts_parse_pad_removed (GstElement * element, GstPad * pad);
 
115
static GstPad *mpegts_parse_request_new_pad (GstElement * element,
 
116
    GstPadTemplate * templ, const gchar * name);
 
117
static void mpegts_parse_release_pad (GstElement * element, GstPad * pad);
 
118
static gboolean mpegts_parse_src_pad_query (GstPad * pad, GstQuery * query);
 
119
static gboolean push_event (MpegTSBase * base, GstEvent * event);
 
120
 
 
121
GST_BOILERPLATE (MpegTSParse2, mpegts_parse, MpegTSBase, GST_TYPE_MPEGTS_BASE);
 
122
 
 
123
static void
 
124
mpegts_parse_base_init (gpointer klass)
 
125
{
 
126
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
 
127
 
 
128
  gst_element_class_add_pad_template (element_class,
 
129
      gst_static_pad_template_get (&src_template));
 
130
  gst_element_class_add_pad_template (element_class,
 
131
      gst_static_pad_template_get (&program_template));
 
132
 
 
133
  gst_element_class_set_details_simple (element_class,
 
134
      "MPEG transport stream parser", "Codec/Parser",
 
135
      "Parses MPEG2 transport streams",
 
136
      "Alessandro Decina <alessandro@nnva.org>, "
 
137
      "Zaheer Abbas Merali <zaheerabbas at merali dot org>");
 
138
}
 
139
 
 
140
static void
 
141
mpegts_parse_class_init (MpegTSParse2Class * klass)
 
142
{
 
143
  GObjectClass *gobject_class;
 
144
  GstElementClass *element_class;
 
145
  MpegTSBaseClass *ts_class;
 
146
 
 
147
  element_class = GST_ELEMENT_CLASS (klass);
 
148
  element_class->pad_removed = mpegts_parse_pad_removed;
 
149
  element_class->request_new_pad = mpegts_parse_request_new_pad;
 
150
  element_class->release_pad = mpegts_parse_release_pad;
 
151
 
 
152
  gobject_class = G_OBJECT_CLASS (klass);
 
153
  gobject_class->set_property = mpegts_parse_set_property;
 
154
  gobject_class->get_property = mpegts_parse_get_property;
 
155
  gobject_class->finalize = mpegts_parse_finalize;
 
156
 
 
157
  g_object_class_install_property (gobject_class, PROP_PROGRAM_NUMBERS,
 
158
      g_param_spec_string ("program-numbers",
 
159
          "Program Numbers",
 
160
          "Colon separated list of programs", "",
 
161
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
162
 
 
163
  ts_class = GST_MPEGTS_BASE_CLASS (klass);
 
164
  ts_class->push = GST_DEBUG_FUNCPTR (mpegts_parse_push);
 
165
  ts_class->push_event = GST_DEBUG_FUNCPTR (push_event);
 
166
  ts_class->program_started = GST_DEBUG_FUNCPTR (mpegts_parse_program_started);
 
167
  ts_class->program_stopped = GST_DEBUG_FUNCPTR (mpegts_parse_program_stopped);
 
168
}
 
169
 
 
170
static void
 
171
mpegts_parse_init (MpegTSParse2 * parse, MpegTSParse2Class * klass)
 
172
{
 
173
  parse->need_sync_program_pads = FALSE;
 
174
  parse->program_numbers = g_strdup ("");
 
175
  parse->pads_to_add = NULL;
 
176
  parse->pads_to_remove = NULL;
 
177
  GST_MPEGTS_BASE (parse)->program_size = sizeof (MpegTSParseProgram);
 
178
}
 
179
 
 
180
static void
 
181
mpegts_parse_finalize (GObject * object)
 
182
{
 
183
  MpegTSParse2 *parse = GST_MPEGTS_PARSE (object);
 
184
 
 
185
  g_free (parse->program_numbers);
 
186
 
 
187
  if (G_OBJECT_CLASS (parent_class)->finalize)
 
188
    G_OBJECT_CLASS (parent_class)->finalize (object);
 
189
}
 
190
 
 
191
static void
 
192
mpegts_parse_set_property (GObject * object, guint prop_id,
 
193
    const GValue * value, GParamSpec * pspec)
 
194
{
 
195
  MpegTSParse2 *parse = GST_MPEGTS_PARSE (object);
 
196
 
 
197
  switch (prop_id) {
 
198
    case PROP_PROGRAM_NUMBERS:
 
199
      mpegts_parse_reset_selected_programs (parse, g_value_dup_string (value));
 
200
      break;
 
201
    default:
 
202
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
203
  }
 
204
}
 
205
 
 
206
static void
 
207
mpegts_parse_get_property (GObject * object, guint prop_id,
 
208
    GValue * value, GParamSpec * pspec)
 
209
{
 
210
  MpegTSParse2 *parse = GST_MPEGTS_PARSE (object);
 
211
 
 
212
  switch (prop_id) {
 
213
    case PROP_PROGRAM_NUMBERS:
 
214
      g_value_set_string (value, parse->program_numbers);
 
215
      break;
 
216
    default:
 
217
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
218
  }
 
219
}
 
220
 
 
221
static GstPad *
 
222
mpegts_parse_activate_program (MpegTSParse2 * parse,
 
223
    MpegTSParseProgram * program)
 
224
{
 
225
  MpegTSParsePad *tspad;
 
226
  gchar *pad_name;
 
227
 
 
228
  pad_name =
 
229
      g_strdup_printf ("program_%d",
 
230
      ((MpegTSBaseProgram *) program)->program_number);
 
231
 
 
232
  tspad = mpegts_parse_create_tspad (parse, pad_name);
 
233
  tspad->program_number = ((MpegTSBaseProgram *) program)->program_number;
 
234
  tspad->program = program;
 
235
  program->tspad = tspad;
 
236
  g_free (pad_name);
 
237
  gst_pad_set_active (tspad->pad, TRUE);
 
238
  program->active = TRUE;
 
239
 
 
240
  return tspad->pad;
 
241
}
 
242
 
 
243
static gboolean
 
244
push_event (MpegTSBase * base, GstEvent * event)
 
245
{
 
246
  MpegTSParse2 *parse = (MpegTSParse2 *) base;
 
247
  GList *tmp;
 
248
 
 
249
  for (tmp = GST_ELEMENT_CAST (parse)->srcpads; tmp; tmp = tmp->next) {
 
250
    GstPad *pad = (GstPad *) tmp->data;
 
251
    if (pad) {
 
252
      gst_event_ref (event);
 
253
      gst_pad_push_event (pad, event);
 
254
    }
 
255
  }
 
256
  return TRUE;
 
257
}
 
258
 
 
259
static GstPad *
 
260
mpegts_parse_deactivate_program (MpegTSParse2 * parse,
 
261
    MpegTSParseProgram * program)
 
262
{
 
263
  MpegTSParsePad *tspad;
 
264
 
 
265
  tspad = program->tspad;
 
266
  gst_pad_set_active (tspad->pad, FALSE);
 
267
  program->active = FALSE;
 
268
 
 
269
  /* tspad will be destroyed in GstElementClass::pad_removed */
 
270
 
 
271
  return tspad->pad;
 
272
}
 
273
 
 
274
static void
 
275
mpegts_parse_sync_program_pads (MpegTSParse2 * parse)
 
276
{
 
277
  GList *walk;
 
278
 
 
279
  GST_INFO_OBJECT (parse, "begin sync pads");
 
280
  for (walk = parse->pads_to_remove; walk; walk = walk->next)
 
281
    gst_element_remove_pad (GST_ELEMENT (parse), GST_PAD (walk->data));
 
282
 
 
283
  for (walk = parse->pads_to_add; walk; walk = walk->next)
 
284
    gst_element_add_pad (GST_ELEMENT (parse), GST_PAD (walk->data));
 
285
 
 
286
  if (parse->pads_to_add)
 
287
    g_list_free (parse->pads_to_add);
 
288
 
 
289
  if (parse->pads_to_remove)
 
290
    g_list_free (parse->pads_to_remove);
 
291
 
 
292
  GST_OBJECT_LOCK (parse);
 
293
  parse->pads_to_remove = NULL;
 
294
  parse->pads_to_add = NULL;
 
295
  parse->need_sync_program_pads = FALSE;
 
296
  GST_OBJECT_UNLOCK (parse);
 
297
 
 
298
  GST_INFO_OBJECT (parse, "end sync pads");
 
299
}
 
300
 
 
301
static void
 
302
foreach_program_activate_or_deactivate (gpointer key, gpointer value,
 
303
    gpointer data)
 
304
{
 
305
  MpegTSParse2 *parse = GST_MPEGTS_PARSE (data);
 
306
  MpegTSParseProgram *program = (MpegTSParseProgram *) value;
 
307
 
 
308
  /* at this point selected programs have program->selected == 2,
 
309
   * unselected programs thay may have to be deactivated have selected == 1 and
 
310
   * unselected inactive programs have selected == 0 */
 
311
 
 
312
  switch (--program->selected) {
 
313
    case 1:
 
314
      /* selected */
 
315
      if (!program->active
 
316
          && ((MpegTSBaseProgram *) program)->pmt_pid != G_MAXUINT16)
 
317
        parse->pads_to_add =
 
318
            g_list_append (parse->pads_to_add,
 
319
            mpegts_parse_activate_program (parse, program));
 
320
      else {
 
321
        program->selected = 2;
 
322
      }
 
323
      break;
 
324
    case 0:
 
325
      /* unselected */
 
326
      if (program->active)
 
327
        parse->pads_to_remove = g_list_append (parse->pads_to_remove,
 
328
            mpegts_parse_deactivate_program (parse, program));
 
329
      break;
 
330
    case -1:
 
331
      /* was already unselected */
 
332
      program->selected = 0;
 
333
      break;
 
334
    default:
 
335
      g_return_if_reached ();
 
336
  }
 
337
}
 
338
 
 
339
static void
 
340
mpegts_parse_reset_selected_programs (MpegTSParse2 * parse,
 
341
    gchar * program_numbers)
 
342
{
 
343
  GST_OBJECT_LOCK (parse);
 
344
  if (parse->program_numbers)
 
345
    g_free (parse->program_numbers);
 
346
 
 
347
  parse->program_numbers = program_numbers;
 
348
 
 
349
  if (*parse->program_numbers != '\0') {
 
350
    gint program_number;
 
351
    MpegTSParseProgram *program;
 
352
    gchar **progs, **walk;
 
353
 
 
354
    progs = g_strsplit (parse->program_numbers, ":", 0);
 
355
 
 
356
    walk = progs;
 
357
    while (*walk != NULL) {
 
358
      program_number = strtol (*walk, NULL, 0);
 
359
      program =
 
360
          (MpegTSParseProgram *) mpegts_base_get_program ((MpegTSBase *) parse,
 
361
          program_number);
 
362
      if (program == NULL)
 
363
        /* create the program, it will get activated once we get a PMT for it */
 
364
        program = (MpegTSParseProgram *) mpegts_base_add_program ((MpegTSBase *)
 
365
            parse, program_number, G_MAXUINT16);
 
366
      program->selected = 2;
 
367
      ++walk;
 
368
    }
 
369
    g_strfreev (progs);
 
370
  }
 
371
 
 
372
  g_hash_table_foreach (((MpegTSBase *) parse)->programs,
 
373
      foreach_program_activate_or_deactivate, parse);
 
374
 
 
375
  if (parse->pads_to_remove || parse->pads_to_add)
 
376
    parse->need_sync_program_pads = TRUE;
 
377
  GST_OBJECT_UNLOCK (parse);
 
378
}
 
379
 
 
380
 
 
381
static MpegTSParsePad *
 
382
mpegts_parse_create_tspad (MpegTSParse2 * parse, const gchar * pad_name)
 
383
{
 
384
  GstPad *pad;
 
385
  MpegTSParsePad *tspad;
 
386
 
 
387
  pad = gst_pad_new_from_static_template (&program_template, pad_name);
 
388
  gst_pad_set_query_function (pad,
 
389
      GST_DEBUG_FUNCPTR (mpegts_parse_src_pad_query));
 
390
 
 
391
  /* create our wrapper */
 
392
  tspad = g_new0 (MpegTSParsePad, 1);
 
393
  tspad->pad = pad;
 
394
  tspad->program_number = -1;
 
395
  tspad->program = NULL;
 
396
  tspad->pushed = FALSE;
 
397
  tspad->flow_return = GST_FLOW_NOT_LINKED;
 
398
  gst_pad_set_element_private (pad, tspad);
 
399
 
 
400
  return tspad;
 
401
}
 
402
 
 
403
static void
 
404
mpegts_parse_destroy_tspad (MpegTSParse2 * parse, MpegTSParsePad * tspad)
 
405
{
 
406
  if (tspad->tags) {
 
407
    gst_tag_list_free (tspad->tags);
 
408
  }
 
409
 
 
410
  /* free the wrapper */
 
411
  g_free (tspad);
 
412
}
 
413
 
 
414
static void
 
415
mpegts_parse_pad_removed (GstElement * element, GstPad * pad)
 
416
{
 
417
  MpegTSParsePad *tspad;
 
418
  MpegTSParse2 *parse = GST_MPEGTS_PARSE (element);
 
419
 
 
420
  if (gst_pad_get_direction (pad) == GST_PAD_SINK)
 
421
    return;
 
422
 
 
423
  tspad = (MpegTSParsePad *) gst_pad_get_element_private (pad);
 
424
  mpegts_parse_destroy_tspad (parse, tspad);
 
425
 
 
426
  if (GST_ELEMENT_CLASS (parent_class)->pad_removed)
 
427
    GST_ELEMENT_CLASS (parent_class)->pad_removed (element, pad);
 
428
}
 
429
 
 
430
static GstPad *
 
431
mpegts_parse_request_new_pad (GstElement * element, GstPadTemplate * template,
 
432
    const gchar * unused)
 
433
{
 
434
  MpegTSParse2 *parse;
 
435
  gchar *name;
 
436
  GstPad *pad;
 
437
 
 
438
  g_return_val_if_fail (template != NULL, NULL);
 
439
  g_return_val_if_fail (GST_IS_MPEGTS_PARSE (element), NULL);
 
440
 
 
441
  parse = GST_MPEGTS_PARSE (element);
 
442
 
 
443
  GST_OBJECT_LOCK (element);
 
444
  name = g_strdup_printf ("src%d", parse->req_pads++);
 
445
  GST_OBJECT_UNLOCK (element);
 
446
 
 
447
  pad = mpegts_parse_create_tspad (parse, name)->pad;
 
448
  gst_pad_set_active (pad, TRUE);
 
449
  gst_element_add_pad (element, pad);
 
450
  g_free (name);
 
451
 
 
452
  return pad;
 
453
}
 
454
 
 
455
static void
 
456
mpegts_parse_release_pad (GstElement * element, GstPad * pad)
 
457
{
 
458
  g_return_if_fail (GST_IS_MPEGTS_PARSE (element));
 
459
 
 
460
  gst_pad_set_active (pad, FALSE);
 
461
  /* we do the cleanup in GstElement::pad-removed */
 
462
  gst_element_remove_pad (element, pad);
 
463
}
 
464
 
 
465
static GstFlowReturn
 
466
mpegts_parse_tspad_push_section (MpegTSParse2 * parse, MpegTSParsePad * tspad,
 
467
    MpegTSPacketizerSection * section, GstBuffer * buffer)
 
468
{
 
469
  GstFlowReturn ret = GST_FLOW_NOT_LINKED;
 
470
  gboolean to_push = TRUE;
 
471
 
 
472
  if (tspad->program_number != -1) {
 
473
    if (tspad->program) {
 
474
      /* we push all sections to all pads except PMTs which we
 
475
       * only push to pads meant to receive that program number */
 
476
      if (section->table_id == 0x02) {
 
477
        /* PMT */
 
478
        if (section->subtable_extension != tspad->program_number)
 
479
          to_push = FALSE;
 
480
      }
 
481
    } else {
 
482
      /* there's a program filter on the pad but the PMT for the program has not
 
483
       * been parsed yet, ignore the pad until we get a PMT */
 
484
      to_push = FALSE;
 
485
      ret = GST_FLOW_OK;
 
486
    }
 
487
  }
 
488
  GST_DEBUG_OBJECT (parse,
 
489
      "pushing section: %d program number: %d table_id: %d", to_push,
 
490
      tspad->program_number, section->table_id);
 
491
  if (to_push) {
 
492
    ret = gst_pad_push (tspad->pad, buffer);
 
493
  } else {
 
494
    gst_buffer_unref (buffer);
 
495
    if (gst_pad_is_linked (tspad->pad))
 
496
      ret = GST_FLOW_OK;
 
497
  }
 
498
 
 
499
  return ret;
 
500
}
 
501
 
 
502
static GstFlowReturn
 
503
mpegts_parse_tspad_push (MpegTSParse2 * parse, MpegTSParsePad * tspad,
 
504
    guint16 pid, GstBuffer * buffer)
 
505
{
 
506
  GstFlowReturn ret = GST_FLOW_NOT_LINKED;
 
507
  MpegTSBaseStream **pad_pids = NULL;
 
508
 
 
509
  if (tspad->program_number != -1) {
 
510
    if (tspad->program) {
 
511
      MpegTSBaseProgram *bp = (MpegTSBaseProgram *) tspad->program;
 
512
      pad_pids = bp->streams;
 
513
      if (bp->tags) {
 
514
        gst_element_found_tags_for_pad (GST_ELEMENT_CAST (parse), tspad->pad,
 
515
            bp->tags);
 
516
        bp->tags = NULL;
 
517
      }
 
518
    } else {
 
519
      /* there's a program filter on the pad but the PMT for the program has not
 
520
       * been parsed yet, ignore the pad until we get a PMT */
 
521
      gst_buffer_unref (buffer);
 
522
      ret = GST_FLOW_OK;
 
523
      goto out;
 
524
    }
 
525
  }
 
526
 
 
527
  if (pad_pids == NULL || pad_pids[pid]) {
 
528
    /* push if there's no filter or if the pid is in the filter */
 
529
    ret = gst_pad_push (tspad->pad, buffer);
 
530
  } else {
 
531
    gst_buffer_unref (buffer);
 
532
    if (gst_pad_is_linked (tspad->pad))
 
533
      ret = GST_FLOW_OK;
 
534
  }
 
535
 
 
536
out:
 
537
  return ret;
 
538
}
 
539
 
 
540
static void
 
541
pad_clear_for_push (GstPad * pad, MpegTSParse2 * parse)
 
542
{
 
543
  MpegTSParsePad *tspad = (MpegTSParsePad *) gst_pad_get_element_private (pad);
 
544
 
 
545
  tspad->flow_return = GST_FLOW_NOT_LINKED;
 
546
  tspad->pushed = FALSE;
 
547
}
 
548
 
 
549
static GstFlowReturn
 
550
mpegts_parse_push (MpegTSBase * base, MpegTSPacketizerPacket * packet,
 
551
    MpegTSPacketizerSection * section)
 
552
{
 
553
  MpegTSParse2 *parse = (MpegTSParse2 *) base;
 
554
  guint32 pads_cookie;
 
555
  gboolean done = FALSE;
 
556
  GstPad *pad = NULL;
 
557
  MpegTSParsePad *tspad;
 
558
  guint16 pid;
 
559
  GstBuffer *buffer;
 
560
  GstFlowReturn ret;
 
561
  GList *srcpads;
 
562
 
 
563
  if (G_UNLIKELY (parse->need_sync_program_pads))
 
564
    mpegts_parse_sync_program_pads (parse);
 
565
 
 
566
  pid = packet->pid;
 
567
  buffer = gst_buffer_make_metadata_writable (packet->buffer);
 
568
  /* we have the same caps on all the src pads */
 
569
  gst_buffer_set_caps (buffer, base->packetizer->caps);
 
570
 
 
571
  GST_OBJECT_LOCK (parse);
 
572
  /* clear tspad->pushed on pads */
 
573
  g_list_foreach (GST_ELEMENT_CAST (parse)->srcpads,
 
574
      (GFunc) pad_clear_for_push, parse);
 
575
  if (GST_ELEMENT_CAST (parse)->srcpads)
 
576
    ret = GST_FLOW_NOT_LINKED;
 
577
  else
 
578
    ret = GST_FLOW_OK;
 
579
 
 
580
  /* Get cookie and source pads list */
 
581
  pads_cookie = GST_ELEMENT_CAST (parse)->pads_cookie;
 
582
  srcpads = GST_ELEMENT_CAST (parse)->srcpads;
 
583
  if (G_LIKELY (srcpads)) {
 
584
    pad = GST_PAD_CAST (srcpads->data);
 
585
    g_object_ref (pad);
 
586
  }
 
587
  GST_OBJECT_UNLOCK (parse);
 
588
 
 
589
  while (pad && !done) {
 
590
    tspad = gst_pad_get_element_private (pad);
 
591
 
 
592
    if (G_LIKELY (!tspad->pushed)) {
 
593
      /* ref the buffer as gst_pad_push takes a ref but we want to reuse the
 
594
       * same buffer for next pushes */
 
595
      gst_buffer_ref (buffer);
 
596
      if (section) {
 
597
        tspad->flow_return =
 
598
            mpegts_parse_tspad_push_section (parse, tspad, section, buffer);
 
599
      } else {
 
600
        tspad->flow_return =
 
601
            mpegts_parse_tspad_push (parse, tspad, pid, buffer);
 
602
      }
 
603
      tspad->pushed = TRUE;
 
604
 
 
605
      if (G_UNLIKELY (tspad->flow_return != GST_FLOW_OK
 
606
              && tspad->flow_return != GST_FLOW_NOT_LINKED)) {
 
607
        /* return the error upstream */
 
608
        ret = tspad->flow_return;
 
609
        done = TRUE;
 
610
      }
 
611
 
 
612
    }
 
613
 
 
614
    if (ret == GST_FLOW_NOT_LINKED)
 
615
      ret = tspad->flow_return;
 
616
 
 
617
    g_object_unref (pad);
 
618
 
 
619
    if (G_UNLIKELY (!done)) {
 
620
      GST_OBJECT_LOCK (parse);
 
621
      if (G_UNLIKELY (pads_cookie != GST_ELEMENT_CAST (parse)->pads_cookie)) {
 
622
        /* resync */
 
623
        GST_DEBUG ("resync");
 
624
        pads_cookie = GST_ELEMENT_CAST (parse)->pads_cookie;
 
625
        srcpads = GST_ELEMENT_CAST (parse)->srcpads;
 
626
      } else {
 
627
        GST_DEBUG ("getting next pad");
 
628
        /* Get next pad */
 
629
        srcpads = g_list_next (srcpads);
 
630
      }
 
631
 
 
632
      if (srcpads) {
 
633
        pad = GST_PAD_CAST (srcpads->data);
 
634
        g_object_ref (pad);
 
635
      } else
 
636
        done = TRUE;
 
637
      GST_OBJECT_UNLOCK (parse);
 
638
    }
 
639
  }
 
640
 
 
641
  gst_buffer_unref (buffer);
 
642
  packet->buffer = NULL;
 
643
 
 
644
  return ret;
 
645
}
 
646
 
 
647
static void
 
648
mpegts_parse_program_started (MpegTSBase * base, MpegTSBaseProgram * program)
 
649
{
 
650
  MpegTSParse2 *parse = GST_MPEGTS_PARSE (base);
 
651
  MpegTSParseProgram *parseprogram = (MpegTSParseProgram *) program;
 
652
  if (parseprogram->selected == 2) {
 
653
    parse->pads_to_add =
 
654
        g_list_append (parse->pads_to_add,
 
655
        mpegts_parse_activate_program (parse, parseprogram));
 
656
    parseprogram->selected = 1;
 
657
    parse->need_sync_program_pads = TRUE;
 
658
  }
 
659
 
 
660
}
 
661
 
 
662
static void
 
663
mpegts_parse_program_stopped (MpegTSBase * base, MpegTSBaseProgram * program)
 
664
{
 
665
  MpegTSParse2 *parse = GST_MPEGTS_PARSE (base);
 
666
  MpegTSParseProgram *parseprogram = (MpegTSParseProgram *) program;
 
667
 
 
668
  if (parseprogram->active) {
 
669
    parse->pads_to_remove =
 
670
        g_list_append (parse->pads_to_remove,
 
671
        mpegts_parse_deactivate_program (parse, parseprogram));
 
672
    parse->need_sync_program_pads = TRUE;
 
673
  }
 
674
}
 
675
 
 
676
static gboolean
 
677
mpegts_parse_src_pad_query (GstPad * pad, GstQuery * query)
 
678
{
 
679
  MpegTSParse2 *parse = GST_MPEGTS_PARSE (gst_pad_get_parent (pad));
 
680
  gboolean res;
 
681
 
 
682
  switch (GST_QUERY_TYPE (query)) {
 
683
    case GST_QUERY_LATENCY:
 
684
    {
 
685
      if ((res = gst_pad_peer_query (((MpegTSBase *) parse)->sinkpad, query))) {
 
686
        gboolean is_live;
 
687
        GstClockTime min_latency, max_latency;
 
688
 
 
689
        gst_query_parse_latency (query, &is_live, &min_latency, &max_latency);
 
690
        if (is_live) {
 
691
          min_latency += TS_LATENCY * GST_MSECOND;
 
692
          if (max_latency != GST_CLOCK_TIME_NONE)
 
693
            max_latency += TS_LATENCY * GST_MSECOND;
 
694
        }
 
695
 
 
696
        gst_query_set_latency (query, is_live, min_latency, max_latency);
 
697
      }
 
698
 
 
699
      break;
 
700
    }
 
701
    default:
 
702
      res = gst_pad_query_default (pad, query);
 
703
  }
 
704
  gst_object_unref (parse);
 
705
  return res;
 
706
}
 
707
 
 
708
gboolean
 
709
gst_mpegtsparse_plugin_init (GstPlugin * plugin)
 
710
{
 
711
  GST_DEBUG_CATEGORY_INIT (mpegts_parse_debug, "tsparse", 0,
 
712
      "MPEG transport stream parser");
 
713
 
 
714
  gst_mpegtsdesc_init_debug ();
 
715
 
 
716
  return gst_element_register (plugin, "tsparse",
 
717
      GST_RANK_NONE, GST_TYPE_MPEGTS_PARSE);
 
718
}