gstmpegdemux.c 100 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
 /*
  * This library is licensed under 2 different licenses and you
  * can choose to use it under the terms of either one of them. The
  * two licenses are the MPL 1.1 and the LGPL.
  *
  * MPL:
  *
  * The contents of this file are subject to the Mozilla Public License
  * Version 1.1 (the "License"); you may not use this file except in
  * compliance with the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/.
  *
  * Software distributed under the License is distributed on an "AS IS"
  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
  * License for the specific language governing rights and limitations
  * under the License.
  *
  * LGPL:
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Library General Public License for more details.
  *
  * You should have received a copy of the GNU Library General Public
  * License along with this library; if not, write to the
Tim-Philipp Müller's avatar
Tim-Philipp Müller committed
32 33
  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
  * Boston, MA 02110-1301, USA.
34 35 36 37 38 39 40 41
  *
  * The Original Code is Fluendo MPEG Demuxer plugin.
  *
  * The Initial Developer of the Original Code is Fluendo, S.L.
  * Portions created by Fluendo, S.L. are Copyright (C) 2005
  * Fluendo, S.L. All Rights Reserved.
  *
  * Contributor(s): Wim Taymans <wim@fluendo.com>
42
  *                 Jan Schmidt <thaytan@noraisin.net>
43 44 45 46 47 48 49 50
  */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <string.h>

51 52
#include <gst/tag/tag.h>
#include <gst/pbutils/pbutils.h>
53
#include <gst/base/gstbytereader.h>
54

55 56 57
#include "gstmpegdefs.h"
#include "gstmpegdemux.h"

58
#define BLOCK_SZ                    32768
59 60
#define SCAN_SCR_SZ                 12
#define SCAN_PTS_SZ                 80
61

62 63 64
#define SEGMENT_THRESHOLD (300*GST_MSECOND)
#define VIDEO_SEGMENT_THRESHOLD (500*GST_MSECOND)

65 66
#define DURATION_SCAN_LIMIT         4 * 1024 * 1024

67 68 69 70 71 72
typedef enum
{
  SCAN_SCR,
  SCAN_DTS,
  SCAN_PTS
} SCAN_MODE;
73 74 75

/* We clamp scr delta with 0 so negative bytes won't be possible */
#define GSTTIME_TO_BYTES(time) \
76
  ((time != -1) ? gst_util_uint64_scale (MAX(0,(gint64) (GSTTIME_TO_MPEGTIME(time))), demux->scr_rate_n, demux->scr_rate_d) : -1)
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
#define BYTES_TO_GSTTIME(bytes) ((bytes != -1) ? MPEGTIME_TO_GSTTIME(gst_util_uint64_scale (bytes, demux->scr_rate_d, demux->scr_rate_n)) : -1)

#define ADAPTER_OFFSET_FLUSH(_bytes_) demux->adapter_offset += (_bytes_)

GST_DEBUG_CATEGORY_STATIC (gstflupsdemux_debug);
#define GST_CAT_DEFAULT (gstflupsdemux_debug)

/* MPEG2Demux signals and args */
enum
{
  /* FILL ME */
  LAST_SIGNAL
};

enum
{
93
  PROP_0,
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
  /* FILL ME */
};

static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("video/mpeg, "
        "mpegversion = (int) { 1, 2 }, "
        "systemstream = (boolean) TRUE;" "video/x-cdxa")
    );

static GstStaticPadTemplate video_template =
    GST_STATIC_PAD_TEMPLATE ("video_%02x",
    GST_PAD_SRC,
    GST_PAD_SOMETIMES,
    GST_STATIC_CAPS ("video/mpeg, "
110 111
        "mpegversion = (int) { 1, 2, 4 }, " "systemstream = (boolean) FALSE, "
        "parsed = (boolean) FALSE; " "video/x-h264")
112 113 114 115 116 117
    );

static GstStaticPadTemplate audio_template =
    GST_STATIC_PAD_TEMPLATE ("audio_%02x",
    GST_PAD_SRC,
    GST_PAD_SOMETIMES,
118 119
    GST_STATIC_CAPS ("audio/mpeg, mpegversion = (int) 1;"
        "audio/mpeg, mpegversion = (int) 4, stream-format = (string) { adts, loas };"
120 121 122 123
        "audio/x-private1-lpcm; "
        "audio/x-private1-ac3;" "audio/x-private1-dts;" "audio/ac3")
    );

124 125 126 127
static GstStaticPadTemplate subpicture_template =
GST_STATIC_PAD_TEMPLATE ("subpicture_%02x",
    GST_PAD_SRC,
    GST_PAD_SOMETIMES,
128
    GST_STATIC_CAPS ("subpicture/x-dvd")
129 130
    );

131 132 133 134 135 136
static GstStaticPadTemplate private_template =
GST_STATIC_PAD_TEMPLATE ("private_%d",
    GST_PAD_SRC,
    GST_PAD_SOMETIMES,
    GST_STATIC_CAPS_ANY);

137 138 139 140 141
static void gst_ps_demux_base_init (GstPsDemuxClass * klass);
static void gst_ps_demux_class_init (GstPsDemuxClass * klass);
static void gst_ps_demux_init (GstPsDemux * demux);
static void gst_ps_demux_finalize (GstPsDemux * demux);
static void gst_ps_demux_reset (GstPsDemux * demux);
142

143
static gboolean gst_ps_demux_sink_event (GstPad * pad, GstObject * parent,
Matej's avatar
Matej committed
144
    GstEvent * event);
145
static GstFlowReturn gst_ps_demux_chain (GstPad * pad, GstObject * parent,
Matej's avatar
Matej committed
146
    GstBuffer * buffer);
147
static gboolean gst_ps_demux_sink_activate (GstPad * sinkpad,
Matej's avatar
Matej committed
148
    GstObject * parent);
149
static gboolean gst_ps_demux_sink_activate_mode (GstPad * pad,
Matej's avatar
Matej committed
150
    GstObject * parent, GstPadMode mode, gboolean active);
151
static void gst_ps_demux_loop (GstPad * pad);
152

153
static gboolean gst_ps_demux_src_event (GstPad * pad, GstObject * parent,
Matej's avatar
Matej committed
154
    GstEvent * event);
155
static gboolean gst_ps_demux_src_query (GstPad * pad, GstObject * parent,
Matej's avatar
Matej committed
156
    GstQuery * query);
157

158
static GstStateChangeReturn gst_ps_demux_change_state (GstElement * element,
159 160
    GstStateChange transition);

161
static inline gboolean gst_ps_demux_scan_forward_ts (GstPsDemux * demux,
162
    guint64 * pos, SCAN_MODE mode, guint64 * rts, gint limit);
163
static inline gboolean gst_ps_demux_scan_backward_ts (GstPsDemux * demux,
164
    guint64 * pos, SCAN_MODE mode, guint64 * rts, gint limit);
165

166
static inline void gst_ps_demux_send_gap_updates (GstPsDemux * demux,
167
    GstClockTime new_time);
168
static inline void gst_ps_demux_clear_times (GstPsDemux * demux);
169

170 171
static void gst_ps_demux_reset_psm (GstPsDemux * demux);
static void gst_ps_demux_flush (GstPsDemux * demux);
172

173 174
static GstElementClass *parent_class = NULL;

Matej's avatar
Matej committed
175 176 177 178 179
static void gst_segment_set_position (GstSegment * segment, GstFormat format,
    guint64 position);
static void gst_segment_set_duration (GstSegment * segment, GstFormat format,
    guint64 duration);

180
/*static guint gst_ps_demux_signals[LAST_SIGNAL] = { 0 };*/
181 182

GType
183
gst_ps_demux_get_type (void)
184
{
185
  static GType ps_demux_type = 0;
186

187 188 189 190
  if (!ps_demux_type) {
    static const GTypeInfo ps_demux_info = {
      sizeof (GstPsDemuxClass),
      (GBaseInitFunc) gst_ps_demux_base_init,
191
      NULL,
192
      (GClassInitFunc) gst_ps_demux_class_init,
193 194
      NULL,
      NULL,
195
      sizeof (GstPsDemux),
196
      0,
197
      (GInstanceInitFunc) gst_ps_demux_init,
Matej's avatar
Matej committed
198
      NULL
199 200
    };

201
    ps_demux_type =
202
        g_type_register_static (GST_TYPE_ELEMENT, "GstMpegPSDemux",
203
        &ps_demux_info, 0);
204

205
    GST_DEBUG_CATEGORY_INIT (gstflupsdemux_debug, "mpegpsdemux", 0,
206 207 208
        "MPEG program stream demultiplexer element");
  }

209
  return ps_demux_type;
210 211 212
}

static void
213
gst_ps_demux_base_init (GstPsDemuxClass * klass)
214 215 216 217 218 219
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);

  klass->sink_template = gst_static_pad_template_get (&sink_template);
  klass->video_template = gst_static_pad_template_get (&video_template);
  klass->audio_template = gst_static_pad_template_get (&audio_template);
220 221
  klass->subpicture_template =
      gst_static_pad_template_get (&subpicture_template);
222 223 224 225
  klass->private_template = gst_static_pad_template_get (&private_template);

  gst_element_class_add_pad_template (element_class, klass->video_template);
  gst_element_class_add_pad_template (element_class, klass->audio_template);
226 227
  gst_element_class_add_pad_template (element_class,
      klass->subpicture_template);
228 229 230
  gst_element_class_add_pad_template (element_class, klass->private_template);
  gst_element_class_add_pad_template (element_class, klass->sink_template);

231
  gst_element_class_set_static_metadata (element_class,
232
      "MPEG Program Stream Demuxer", "Codec/Demuxer",
233
      "Demultiplexes MPEG Program Streams", "Wim Taymans <wim@fluendo.com>");
234 235 236
}

static void
237
gst_ps_demux_class_init (GstPsDemuxClass * klass)
238 239 240 241 242 243 244 245 246
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;

  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);

  gobject_class = (GObjectClass *) klass;
  gstelement_class = (GstElementClass *) klass;

247
  gobject_class->finalize = (GObjectFinalizeFunc) gst_ps_demux_finalize;
248

249
  gstelement_class->change_state = gst_ps_demux_change_state;
250 251 252
}

static void
253
gst_ps_demux_init (GstPsDemux * demux)
254
{
255
  GstPsDemuxClass *klass = GST_PS_DEMUX_GET_CLASS (demux);
256 257

  demux->sinkpad = gst_pad_new_from_template (klass->sink_template, "sink");
258
  gst_pad_set_event_function (demux->sinkpad,
259
      GST_DEBUG_FUNCPTR (gst_ps_demux_sink_event));
260
  gst_pad_set_chain_function (demux->sinkpad,
261
      GST_DEBUG_FUNCPTR (gst_ps_demux_chain));
262
  gst_pad_set_activate_function (demux->sinkpad,
263
      GST_DEBUG_FUNCPTR (gst_ps_demux_sink_activate));
Matej's avatar
Matej committed
264
  gst_pad_set_activatemode_function (demux->sinkpad,
265
      GST_DEBUG_FUNCPTR (gst_ps_demux_sink_activate_mode));
266

267 268 269
  gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);

  demux->streams =
270
      g_malloc0 (sizeof (GstPsStream *) * (GST_PS_DEMUX_MAX_STREAMS));
271
  demux->streams_found =
272
      g_malloc0 (sizeof (GstPsStream *) * (GST_PS_DEMUX_MAX_STREAMS));
273
  demux->found_count = 0;
274

275 276
  demux->adapter = gst_adapter_new ();
  demux->rev_adapter = gst_adapter_new ();
277
  demux->flowcombiner = gst_flow_combiner_new ();
278

279
  gst_ps_demux_reset (demux);
280 281 282
}

static void
283
gst_ps_demux_finalize (GstPsDemux * demux)
284
{
285
  gst_ps_demux_reset (demux);
286
  g_free (demux->streams);
287
  g_free (demux->streams_found);
288

289
  gst_flow_combiner_free (demux->flowcombiner);
290 291 292
  g_object_unref (demux->adapter);
  g_object_unref (demux->rev_adapter);

293 294 295 296
  G_OBJECT_CLASS (parent_class)->finalize (G_OBJECT (demux));
}

static void
297
gst_ps_demux_reset (GstPsDemux * demux)
298 299 300 301
{
  /* Clean up the streams and pads we allocated */
  gint i;

302 303
  for (i = 0; i < GST_PS_DEMUX_MAX_STREAMS; i++) {
    GstPsStream *stream = demux->streams[i];
304 305

    if (stream != NULL) {
306 307
      if (stream->pad && GST_PAD_PARENT (stream->pad)) {
        gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
308
        gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
309 310
      } else {
        gst_object_unref (stream->pad);
311
      }
312

313 314
      if (stream->pending_tags)
        gst_tag_list_unref (stream->pending_tags);
315 316 317 318
      g_free (stream);
      demux->streams[i] = NULL;
    }
  }
319
  memset (demux->streams_found, 0,
320
      sizeof (GstPsStream *) * (GST_PS_DEMUX_MAX_STREAMS));
321
  demux->found_count = 0;
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338

  gst_adapter_clear (demux->adapter);
  gst_adapter_clear (demux->rev_adapter);

  demux->adapter_offset = G_MAXUINT64;
  demux->first_scr = G_MAXUINT64;
  demux->last_scr = G_MAXUINT64;
  demux->current_scr = G_MAXUINT64;
  demux->base_time = G_MAXUINT64;
  demux->scr_rate_n = G_MAXUINT64;
  demux->scr_rate_d = G_MAXUINT64;
  demux->first_pts = G_MAXUINT64;
  demux->last_pts = G_MAXUINT64;
  demux->mux_rate = G_MAXUINT64;
  demux->next_pts = G_MAXUINT64;
  demux->next_dts = G_MAXUINT64;
  demux->need_no_more_pads = TRUE;
339
  demux->adjust_segment = TRUE;
340
  gst_ps_demux_reset_psm (demux);
341 342
  gst_segment_init (&demux->sink_segment, GST_FORMAT_UNDEFINED);
  gst_segment_init (&demux->src_segment, GST_FORMAT_TIME);
343
  gst_ps_demux_flush (demux);
344 345
  demux->have_group_id = FALSE;
  demux->group_id = G_MAXUINT;
346 347
}

348 349
static GstPsStream *
gst_ps_demux_create_stream (GstPsDemux * demux, gint id, gint stream_type)
350
{
351
  GstPsStream *stream;
352 353
  GstPadTemplate *template;
  gchar *name;
354
  GstPsDemuxClass *klass = GST_PS_DEMUX_GET_CLASS (demux);
355
  GstCaps *caps;
356
  GstClockTime threshold = SEGMENT_THRESHOLD;
357
  GstEvent *event;
358
  gchar *stream_id;
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385

  name = NULL;
  template = NULL;
  caps = NULL;

  GST_DEBUG_OBJECT (demux, "create stream id 0x%02x, type 0x%02x", id,
      stream_type);

  switch (stream_type) {
    case ST_VIDEO_MPEG1:
    case ST_VIDEO_MPEG2:
    case ST_VIDEO_MPEG4:
    case ST_GST_VIDEO_MPEG1_OR_2:
    {
      gint mpeg_version = 1;
      if (stream_type == ST_VIDEO_MPEG2 ||
          (stream_type == ST_GST_VIDEO_MPEG1_OR_2 && demux->is_mpeg2_pack)) {
        mpeg_version = 2;
      }
      if (stream_type == ST_VIDEO_MPEG4) {
        mpeg_version = 4;
      }

      template = klass->video_template;
      name = g_strdup_printf ("video_%02x", id);
      caps = gst_caps_new_simple ("video/mpeg",
          "mpegversion", G_TYPE_INT, mpeg_version,
386 387
          "systemstream", G_TYPE_BOOLEAN, FALSE,
          "parsed", G_TYPE_BOOLEAN, FALSE, NULL);
388
      threshold = VIDEO_SEGMENT_THRESHOLD;
389 390 391 392 393 394 395 396 397 398 399 400 401
      break;
    }
    case ST_AUDIO_MPEG1:
    case ST_AUDIO_MPEG2:
      template = klass->audio_template;
      name = g_strdup_printf ("audio_%02x", id);
      caps = gst_caps_new_simple ("audio/mpeg",
          "mpegversion", G_TYPE_INT, 1, NULL);
      break;
    case ST_PRIVATE_SECTIONS:
    case ST_PRIVATE_DATA:
    case ST_MHEG:
    case ST_DSMCC:
402
      break;
403
    case ST_AUDIO_AAC_ADTS:
404 405 406
      template = klass->audio_template;
      name = g_strdup_printf ("audio_%02x", id);
      caps = gst_caps_new_simple ("audio/mpeg",
407 408 409 410 411 412 413 414 415
          "mpegversion", G_TYPE_INT, 4,
          "stream-format", G_TYPE_STRING, "adts", NULL);
      break;
    case ST_AUDIO_AAC_LOAS:    // LATM/LOAS AAC syntax
      template = klass->audio_template;
      name = g_strdup_printf ("audio_%02x", id);
      caps = gst_caps_new_simple ("audio/mpeg",
          "mpegversion", G_TYPE_INT, 4,
          "stream-format", G_TYPE_STRING, "loas", NULL);
416 417 418 419
      break;
    case ST_VIDEO_H264:
      template = klass->video_template;
      name = g_strdup_printf ("video_%02x", id);
420 421
      caps = gst_caps_new_simple ("video/x-h264",
          "stream-format", G_TYPE_STRING, "byte-stream", NULL);
422
      threshold = VIDEO_SEGMENT_THRESHOLD;
423 424 425 426
      break;
    case ST_PS_AUDIO_AC3:
      template = klass->audio_template;
      name = g_strdup_printf ("audio_%02x", id);
Matej's avatar
Matej committed
427
      caps = gst_caps_new_empty_simple ("audio/x-private1-ac3");
428 429 430 431
      break;
    case ST_PS_AUDIO_DTS:
      template = klass->audio_template;
      name = g_strdup_printf ("audio_%02x", id);
Matej's avatar
Matej committed
432
      caps = gst_caps_new_empty_simple ("audio/x-private1-dts");
433 434 435 436
      break;
    case ST_PS_AUDIO_LPCM:
      template = klass->audio_template;
      name = g_strdup_printf ("audio_%02x", id);
Matej's avatar
Matej committed
437
      caps = gst_caps_new_empty_simple ("audio/x-private1-lpcm");
438 439
      break;
    case ST_PS_DVD_SUBPICTURE:
440 441
      template = klass->subpicture_template;
      name = g_strdup_printf ("subpicture_%02x", id);
442
      caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
443 444 445 446
      break;
    case ST_GST_AUDIO_RAWA52:
      template = klass->audio_template;
      name = g_strdup_printf ("audio_%02x", id);
Matej's avatar
Matej committed
447
      caps = gst_caps_new_empty_simple ("audio/ac3");
448 449 450 451 452
      break;
    default:
      break;
  }

453
  if (name == NULL || template == NULL || caps == NULL) {
454
    g_free (name);
455 456 457 458
    if (caps)
      gst_caps_unref (caps);
    return FALSE;
  }
459

460
  stream = g_new0 (GstPsStream, 1);
461 462 463 464 465
  stream->id = id;
  stream->discont = TRUE;
  stream->need_segment = TRUE;
  stream->notlinked = FALSE;
  stream->type = stream_type;
466
  stream->pending_tags = NULL;
467
  stream->pad = gst_pad_new_from_template (template, name);
468
  stream->segment_thresh = threshold;
469
  gst_pad_set_event_function (stream->pad,
470
      GST_DEBUG_FUNCPTR (gst_ps_demux_src_event));
471
  gst_pad_set_query_function (stream->pad,
472
      GST_DEBUG_FUNCPTR (gst_ps_demux_src_query));
473
  gst_pad_use_fixed_caps (stream->pad);
Matej's avatar
Matej committed
474 475

  /* needed for set_caps to work */
476 477 478 479
  if (!gst_pad_set_active (stream->pad, TRUE)) {
    GST_WARNING_OBJECT (demux, "Failed to activate pad %" GST_PTR_FORMAT,
        stream->pad);
  }
Matej's avatar
Matej committed
480

481 482 483
  stream_id =
      gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
      "%02x", id);
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500

  event = gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
  if (event) {
    if (gst_event_parse_group_id (event, &demux->group_id))
      demux->have_group_id = TRUE;
    else
      demux->have_group_id = FALSE;
    gst_event_unref (event);
  } else if (!demux->have_group_id) {
    demux->have_group_id = TRUE;
    demux->group_id = gst_util_group_id_next ();
  }
  event = gst_event_new_stream_start (stream_id);
  if (demux->have_group_id)
    gst_event_set_group_id (event, demux->group_id);

  gst_pad_push_event (stream->pad, event);
501 502
  g_free (stream_id);

503
  gst_pad_set_caps (stream->pad, caps);
504 505 506 507 508 509

  if (!stream->pending_tags)
    stream->pending_tags = gst_tag_list_new_empty ();
  gst_pb_utils_add_codec_description_to_tag_list (stream->pending_tags, NULL,
      caps);

510
  GST_DEBUG_OBJECT (demux, "create pad %s, caps %" GST_PTR_FORMAT, name, caps);
511
  gst_caps_unref (caps);
512 513 514 515 516
  g_free (name);

  return stream;
}

517 518
static GstPsStream *
gst_ps_demux_get_stream (GstPsDemux * demux, gint id, gint type)
519
{
520
  GstPsStream *stream = demux->streams[id];
521 522

  if (stream == NULL) {
523
    if (!(stream = gst_ps_demux_create_stream (demux, id, type)))
524 525 526 527 528
      goto unknown_stream;

    GST_DEBUG_OBJECT (demux, "adding pad for stream id 0x%02x type 0x%02x", id,
        type);

529 530
    if (demux->need_no_more_pads) {
      gst_element_add_pad (GST_ELEMENT (demux), stream->pad);
531
      gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
532 533 534 535 536 537
    } else {
      /* only likely to confuse decodebin etc, so discard */
      /* FIXME should perform full switch protocol:
       * add a whole new set of pads, drop old and no-more-pads again */
      GST_DEBUG_OBJECT (demux,
          "but already signalled no-more-pads; not adding");
538
      gst_object_ref_sink (stream->pad);
539
    }
540 541

    demux->streams[id] = stream;
542
    demux->streams_found[demux->found_count++] = stream;
543 544 545 546 547 548 549 550 551 552 553
  }
  return stream;

  /* ERROR */
unknown_stream:
  {
    GST_DEBUG_OBJECT (demux, "unknown stream id 0x%02x type 0x%02x", id, type);
    return NULL;
  }
}

554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
static GstPsStream *
gst_ps_demux_get_stream_from_pad (GstPsDemux * demux, GstPad * srcpad)
{
  gint i, count;

  count = demux->found_count;
  for (i = 0; i < count; i++) {
    GstPsStream *stream = demux->streams_found[i];

    if (stream && stream->pad == srcpad)
      return stream;
  }

  GST_DEBUG_OBJECT (srcpad, "no stream found for pad!");
  return NULL;
}

571
static inline void
572
gst_ps_demux_send_segment (GstPsDemux * demux, GstPsStream * stream,
573
    GstClockTime pts)
574 575
{
  /* discont */
576
  if (G_UNLIKELY (stream->need_segment)) {
Matej's avatar
Matej committed
577
    GstSegment segment;
578

579
    GST_DEBUG ("PTS timestamp:%" GST_TIME_FORMAT " base_time %" GST_TIME_FORMAT
580
        " src_segment.start:%" GST_TIME_FORMAT " .stop:%" GST_TIME_FORMAT,
581
        GST_TIME_ARGS (pts), GST_TIME_ARGS (demux->base_time),
582 583 584
        GST_TIME_ARGS (demux->src_segment.start),
        GST_TIME_ARGS (demux->src_segment.stop));

585 586 587 588
    /* adjust segment start if estimating a seek was off quite a bit,
     * make sure to do for all streams though to preserve a/v sync */
    /* FIXME such adjustment tends to be frowned upon */
    if (pts != GST_CLOCK_TIME_NONE && demux->adjust_segment) {
589
      if (demux->src_segment.rate > 0) {
590 591
        if (GST_CLOCK_DIFF (demux->src_segment.start, pts) > GST_SECOND)
          demux->src_segment.start = pts - demux->base_time;
592
      } else {
593 594
        if (GST_CLOCK_DIFF (demux->src_segment.stop, pts) > GST_SECOND)
          demux->src_segment.stop = pts - demux->base_time;
595 596
      }
    }
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613
    demux->adjust_segment = FALSE;

    /* we should be in sync with downstream, so start from our segment notion,
     * which also includes proper base_time etc, tweak it a bit and send */
    gst_segment_copy_into (&demux->src_segment, &segment);
    if (GST_CLOCK_TIME_IS_VALID (demux->base_time)) {
      if (GST_CLOCK_TIME_IS_VALID (segment.start))
        segment.start += demux->base_time;
      if (GST_CLOCK_TIME_IS_VALID (segment.stop))
        segment.stop += demux->base_time;
      segment.time = segment.start - demux->base_time;
    }

    GST_INFO_OBJECT (demux, "sending segment event %" GST_SEGMENT_FORMAT
        " to pad %" GST_PTR_FORMAT, &segment, stream->pad);

    gst_pad_push_event (stream->pad, gst_event_new_segment (&segment));
614 615 616

    stream->need_segment = FALSE;
  }
617 618 619 620 621 622 623 624

  if (G_UNLIKELY (stream->pending_tags)) {
    GST_DEBUG_OBJECT (demux, "Sending pending_tags %p for pad %s:%s : %"
        GST_PTR_FORMAT, stream->pending_tags,
        GST_DEBUG_PAD_NAME (stream->pad), stream->pending_tags);
    gst_pad_push_event (stream->pad, gst_event_new_tag (stream->pending_tags));
    stream->pending_tags = NULL;
  }
625 626 627
}

static GstFlowReturn
628
gst_ps_demux_send_data (GstPsDemux * demux, GstPsStream * stream,
629 630 631 632 633 634 635 636 637 638 639 640 641 642
    GstBuffer * buf)
{
  GstFlowReturn result;
  GstClockTime pts = GST_CLOCK_TIME_NONE, dts = GST_CLOCK_TIME_NONE;

  if (stream == NULL)
    goto no_stream;

  /* timestamps */
  if (G_UNLIKELY (demux->next_pts != G_MAXUINT64))
    pts = MPEGTIME_TO_GSTTIME (demux->next_pts);
  if (G_UNLIKELY (demux->next_dts != G_MAXUINT64))
    dts = MPEGTIME_TO_GSTTIME (demux->next_dts);

643
  gst_ps_demux_send_segment (demux, stream, pts);
644 645

  /* OK, sent new segment now prepare the buffer for sending */
646 647
  GST_BUFFER_PTS (buf) = pts;
  GST_BUFFER_DTS (buf) = dts;
648 649

  /* update position in the segment */
Matej's avatar
Matej committed
650
  gst_segment_set_position (&demux->src_segment, GST_FORMAT_TIME,
651
      MPEGTIME_TO_GSTTIME (demux->current_scr - demux->first_scr));
Matej's avatar
Matej committed
652

653 654
  GST_LOG_OBJECT (demux, "last stop position is now %" GST_TIME_FORMAT
      " current scr is %" GST_TIME_FORMAT,
Matej's avatar
Matej committed
655
      GST_TIME_ARGS (demux->src_segment.position),
656
      GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->current_scr)));
657

658 659
  if (demux->src_segment.position != GST_CLOCK_TIME_NONE &&
      demux->base_time != GST_CLOCK_TIME_NONE) {
Matej's avatar
Matej committed
660
    GstClockTime new_time = demux->base_time + demux->src_segment.position;
661 662

    if (stream->last_ts == GST_CLOCK_TIME_NONE || stream->last_ts < new_time) {
663 664 665
      GST_LOG_OBJECT (demux,
          "last_ts update on pad %s to time %" GST_TIME_FORMAT,
          GST_PAD_NAME (stream->pad), GST_TIME_ARGS (new_time));
666 667 668
      stream->last_ts = new_time;
    }

669
    gst_ps_demux_send_gap_updates (demux, new_time);
670 671
  }

672 673
  /* Set the buffer discont flag, and clear discont state on the stream */
  if (stream->discont) {
674
    GST_DEBUG_OBJECT (demux, "discont buffer to pad %" GST_PTR_FORMAT
675 676
        " with PTS %" GST_TIME_FORMAT " DTS %" GST_TIME_FORMAT,
        stream->pad, GST_TIME_ARGS (pts), GST_TIME_ARGS (dts));
677 678 679
    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);

    stream->discont = FALSE;
680 681
  } else {
    GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
682
  }
683

684 685 686
  demux->next_pts = G_MAXUINT64;
  demux->next_dts = G_MAXUINT64;

687 688 689
  GST_LOG_OBJECT (demux, "pushing stream id 0x%02x type 0x%02x, pts time: %"
      GST_TIME_FORMAT ", size %" G_GSIZE_FORMAT,
      stream->id, stream->type, GST_TIME_ARGS (pts), gst_buffer_get_size (buf));
690
  result = gst_pad_push (stream->pad, buf);
691
  GST_LOG_OBJECT (demux, "result: %s", gst_flow_get_name (result));
692 693 694 695 696 697 698 699 700 701 702 703

  return result;

  /* ERROR */
no_stream:
  {
    GST_DEBUG_OBJECT (demux, "no stream given");
    gst_buffer_unref (buf);
    return GST_FLOW_OK;
  }
}

704
static inline void
705
gst_ps_demux_mark_discont (GstPsDemux * demux, gboolean discont,
706 707
    gboolean need_segment)
{
708
  gint i, count = demux->found_count;
709 710

  /* mark discont on all streams */
711
  for (i = 0; i < count; i++) {
712
    GstPsStream *stream = demux->streams_found[i];
713

714
    if (G_LIKELY (stream)) {
715 716
      stream->discont |= discont;
      stream->need_segment |= need_segment;
717
      demux->adjust_segment |= need_segment;
718 719 720 721 722 723
      GST_DEBUG_OBJECT (demux, "marked stream as discont %d, need_segment %d",
          stream->discont, stream->need_segment);
    }
  }
}

724
static gboolean
725
gst_ps_demux_send_event (GstPsDemux * demux, GstEvent * event)
726
{
727
  gint i, count = demux->found_count;
728 729
  gboolean ret = FALSE;

730
  for (i = 0; i < count; i++) {
731
    GstPsStream *stream = demux->streams_found[i];
732

733
    if (stream) {
734 735
      if (!gst_pad_push_event (stream->pad, gst_event_ref (event))) {
        GST_DEBUG_OBJECT (stream->pad, "%s event was not handled",
736 737 738
            GST_EVENT_TYPE_NAME (event));
      } else {
        /* If at least one push returns TRUE, then we return TRUE. */
739
        GST_DEBUG_OBJECT (stream->pad, "%s event was handled",
740 741 742 743 744 745 746 747 748 749 750
            GST_EVENT_TYPE_NAME (event));
        ret = TRUE;
      }
    }
  }

  gst_event_unref (event);
  return ret;
}

static gboolean
751
gst_ps_demux_handle_dvd_event (GstPsDemux * demux, GstEvent * event)
752 753 754 755 756
{
  const GstStructure *structure = gst_event_get_structure (event);
  const char *type = gst_structure_get_string (structure, "event");
  gint i;
  gchar cur_stream_name[32];
757
  GstPsStream *temp = NULL;
758
  const gchar *lang_code;
759 760 761 762 763

  if (strcmp (type, "dvd-lang-codes") == 0) {
    GST_DEBUG_OBJECT (demux, "Handling language codes event");

    /* Create a video pad to ensure have it before emit no more pads */
764
    (void) gst_ps_demux_get_stream (demux, 0xe0, ST_VIDEO_MPEG2);
765 766 767 768 769 770 771 772 773

    /* Read out the languages for audio streams and request each one that 
     * is present */
    for (i = 0; i < MAX_DVD_AUDIO_STREAMS; i++) {
      gint stream_format;
      gint stream_id;

      g_snprintf (cur_stream_name, 32, "audio-%d-format", i);
      if (!gst_structure_get_int (structure, cur_stream_name, &stream_format))
774
        continue;
775

776 777 778 779 780 781
      g_snprintf (cur_stream_name, 32, "audio-%d-stream", i);
      if (!gst_structure_get_int (structure, cur_stream_name, &stream_id))
        continue;
      if (stream_id < 0 || stream_id >= MAX_DVD_AUDIO_STREAMS)
        continue;

782 783 784
      switch (stream_format) {
        case 0x0:
          /* AC3 */
785
          stream_id += 0x80;
786 787 788
          GST_DEBUG_OBJECT (demux,
              "Audio stream %d format %d ID 0x%02x - AC3", i,
              stream_format, stream_id);
789
          temp = gst_ps_demux_get_stream (demux, stream_id, ST_PS_AUDIO_AC3);
790 791 792
          break;
        case 0x2:
        case 0x3:
793
          /* MPEG audio without and with extension stream are
794
           * treated the same */
795
          stream_id += 0xC0;
796 797 798
          GST_DEBUG_OBJECT (demux,
              "Audio stream %d format %d ID 0x%02x - MPEG audio", i,
              stream_format, stream_id);
799
          temp = gst_ps_demux_get_stream (demux, stream_id, ST_AUDIO_MPEG1);
800 801 802
          break;
        case 0x4:
          /* LPCM */
803
          stream_id += 0xA0;
804 805 806
          GST_DEBUG_OBJECT (demux,
              "Audio stream %d format %d ID 0x%02x - DVD LPCM", i,
              stream_format, stream_id);
807
          temp = gst_ps_demux_get_stream (demux, stream_id, ST_PS_AUDIO_LPCM);
808 809 810
          break;
        case 0x6:
          /* DTS */
811
          stream_id += 0x88;
812 813 814
          GST_DEBUG_OBJECT (demux,
              "Audio stream %d format %d ID 0x%02x - DTS", i,
              stream_format, stream_id);
815
          temp = gst_ps_demux_get_stream (demux, stream_id, ST_PS_AUDIO_DTS);
816 817 818 819 820 821 822
          break;
        case 0x7:
          /* FIXME: What range is SDDS? */
        default:
          GST_WARNING_OBJECT (demux,
              "Unknown audio stream format in language code event: %d",
              stream_format);
823 824
          temp = NULL;
          continue;
825
      }
826

827 828 829
      if (temp == NULL)
        continue;

830 831 832
      g_snprintf (cur_stream_name, 32, "audio-%d-language", i);
      lang_code = gst_structure_get_string (structure, cur_stream_name);
      if (lang_code) {
833
        GstTagList *list = temp->pending_tags;
834

835 836
        if (!list)
          list = gst_tag_list_new_empty ();
837 838 839 840
        gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
            GST_TAG_LANGUAGE_CODE, lang_code, NULL);
        temp->pending_tags = list;
      }
841 842 843 844
    }

    /* And subtitle streams */
    for (i = 0; i < MAX_DVD_SUBPICTURE_STREAMS; i++) {
845 846
      gint stream_id;

847
      g_snprintf (cur_stream_name, 32, "subpicture-%d-format", i);
848 849 850 851 852 853 854 855
      if (!gst_structure_get_int (structure, cur_stream_name, &stream_id))
        continue;

      g_snprintf (cur_stream_name, 32, "subpicture-%d-stream", i);
      if (!gst_structure_get_int (structure, cur_stream_name, &stream_id))
        continue;
      if (stream_id < 0 || stream_id >= MAX_DVD_SUBPICTURE_STREAMS)
        continue;
856

857 858
      GST_DEBUG_OBJECT (demux, "Subpicture stream %d ID 0x%02x", i,
          0x20 + stream_id);
859 860

      /* Retrieve the subpicture stream to force pad creation */
861
      temp = gst_ps_demux_get_stream (demux, 0x20 + stream_id,
862
          ST_PS_DVD_SUBPICTURE);
863 864
      if (temp == NULL)
        continue;
865 866 867 868

      g_snprintf (cur_stream_name, 32, "subpicture-%d-language", i);
      lang_code = gst_structure_get_string (structure, cur_stream_name);
      if (lang_code) {
869
        GstTagList *list = temp->pending_tags;
870

871 872
        if (!list)
          list = gst_tag_list_new_empty ();
873 874 875 876
        gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
            GST_TAG_LANGUAGE_CODE, lang_code, NULL);
        temp->pending_tags = list;
      }
877 878 879 880 881 882 883
    }

    GST_DEBUG_OBJECT (demux, "Created all pads from Language Codes event, "
        "signalling no-more-pads");

    gst_element_no_more_pads (GST_ELEMENT (demux));
    demux->need_no_more_pads = FALSE;
884 885 886
  } else {
    /* forward to all pads, e.g. dvd clut event */
    gst_event_ref (event);
887
    gst_ps_demux_send_event (demux, event);
888 889 890 891 892 893
  }

  gst_event_unref (event);
  return TRUE;
}

894
static void
895
gst_ps_demux_flush (GstPsDemux * demux)
896 897 898 899 900
{
  GST_DEBUG_OBJECT (demux, "flushing demuxer");
  gst_adapter_clear (demux->adapter);
  gst_adapter_clear (demux->rev_adapter);
  gst_pes_filter_drain (&demux->filter);
901
  gst_ps_demux_clear_times (demux);
902 903 904 905 906
  demux->adapter_offset = G_MAXUINT64;
  demux->current_scr = G_MAXUINT64;
  demux->bytes_since_scr = 0;
}

907
static inline void
908
gst_ps_demux_clear_times (GstPsDemux * demux)
909
{
910
  gint i, count = demux->found_count;
911

912
  gst_flow_combiner_reset (demux->flowcombiner);
913
  /* Clear the last ts for all streams */
914
  for (i = 0; i < count; i++) {
915
    GstPsStream *stream = demux->streams_found[i];
916

917
    if (G_LIKELY (stream)) {
918
      stream->last_ts = GST_CLOCK_TIME_NONE;
919 920 921 922
    }
  }
}

923
static inline void
924
gst_ps_demux_send_gap_updates (GstPsDemux * demux, GstClockTime new_start)
925
{
926
  GstClockTime base_time, stop;
927
  gint i, count = demux->found_count;
928 929
  GstEvent *event = NULL;

930
  /* Advance all lagging streams by sending a gap event */
931 932 933 934 935 936
  if ((base_time = demux->base_time) == GST_CLOCK_TIME_NONE)
    base_time = 0;

  stop = demux->src_segment.stop;
  if (stop != GST_CLOCK_TIME_NONE)
    stop += base_time;
937

938
  if (new_start > stop)
939 940
    return;

941
  /* FIXME: Handle reverse playback */
942
  for (i = 0; i < count; i++) {
943
    GstPsStream *stream = demux->streams_found[i];
944 945 946

    if (stream) {
      if (stream->last_ts == GST_CLOCK_TIME_NONE ||
947 948 949 950
          stream->last_ts < demux->src_segment.start + base_time)
        stream->last_ts = demux->src_segment.start + base_time;

      if (stream->last_ts + stream->segment_thresh < new_start) {
951
        /* should send segment info before gap event */
952
        gst_ps_demux_send_segment (demux, stream, GST_CLOCK_TIME_NONE);
953

954
        GST_LOG_OBJECT (demux,
955
            "Sending gap update to pad %s time %" GST_TIME_FORMAT,
956
            GST_PAD_NAME (stream->pad), GST_TIME_ARGS (new_start));
957 958
        event =
            gst_event_new_gap (stream->last_ts, new_start - stream->last_ts);
959
        gst_pad_push_event (stream->pad, event);
960
        stream->last_ts = new_start;
961 962 963 964 965
      }
    }
  }
}

966
static inline gboolean
967
have_open_streams (GstPsDemux * demux)
968
{
969
  return (demux->streams_found[0] != NULL);
970 971
}

972
static gboolean
973
gst_ps_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
974 975
{
  gboolean res = TRUE;
976
  GstPsDemux *demux = GST_PS_DEMUX (parent);
977 978 979

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_FLUSH_START:
980
      gst_ps_demux_send_event (demux, event);
981 982
      break;
    case GST_EVENT_FLUSH_STOP:
983
      gst_ps_demux_send_event (demux, event);
984
      gst_segment_init (&demux->sink_segment, GST_FORMAT_UNDEFINED);
985
      gst_ps_demux_flush (demux);
986
      break;
Matej's avatar
Matej committed
987
    case GST_EVENT_SEGMENT:
988
    {
Matej's avatar
Matej committed
989
      const GstSegment *segment;
990

Matej's avatar
Matej committed
991 992
      gst_event_parse_segment (event, &segment);
      gst_segment_copy_into (segment, &demux->sink_segment);
993

994 995 996
      GST_INFO_OBJECT (demux, "received segment %" GST_SEGMENT_FORMAT, segment);

      /* we need to emit a new segment */
997
      gst_ps_demux_mark_discont (demux, TRUE, TRUE);
998

Matej's avatar
Matej committed
999 1000 1001 1002 1003 1004 1005 1006 1007
      if (segment->format == GST_FORMAT_BYTES
          && demux->scr_rate_n != G_MAXUINT64
          && demux->scr_rate_d != G_MAXUINT64) {
        demux->src_segment.rate = segment->rate;
        demux->src_segment.applied_rate = segment->applied_rate;
        demux->src_segment.format = GST_FORMAT_TIME;
        demux->src_segment.start = BYTES_TO_GSTTIME (segment->start);
        demux->src_segment.stop = BYTES_TO_GSTTIME (segment->stop);
        demux->src_segment.time = BYTES_TO_GSTTIME (segment->time);
1008 1009 1010 1011 1012 1013
      } else if (segment->format == GST_FORMAT_TIME) {
        /* we expect our timeline (SCR, PTS) to match the one from upstream,
         * if not, will adjust with offset later on */
        gst_segment_copy_into (segment, &demux->src_segment);
        /* accept upstream segment without adjusting */
        demux->adjust_segment = FALSE;
1014 1015 1016 1017 1018 1019 1020 1021
      }

      gst_event_unref (event);

      break;
    }
    case GST_EVENT_EOS:
      GST_INFO_OBJECT (demux, "Received EOS");
1022
      if (!gst_ps_demux_send_event (demux, event)
1023 1024
          && !have_open_streams (demux)) {
        GST_WARNING_OBJECT (demux, "EOS and no streams open");
1025
        GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1026
            ("Internal data stream error."), ("No valid streams detected"));
1027 1028 1029 1030 1031 1032 1033 1034 1035
      }
      break;
    case GST_EVENT_CUSTOM_DOWNSTREAM:
    case GST_EVENT_CUSTOM_DOWNSTREAM_OOB:
    {
      const GstStructure *structure = gst_event_get_structure (event);

      if (structure != NULL
          && gst_structure_has_name (structure, "application/x-gst-dvd")) {
1036
        res = gst_ps_demux_handle_dvd_event (demux, event);
1037
      } else {
1038
        gst_ps_demux_send_event (demux, event);
1039 1040 1041
      }
      break;
    }
1042 1043 1044
    case GST_EVENT_CAPS:
      gst_event_unref (event);
      break;
1045
    default:
1046
      gst_ps_demux_send_event (demux, event);
1047 1048 1049 1050 1051 1052 1053
      break;
  }

  return res;
}

static gboolean
1054
gst_ps_demux_handle_seek_push (GstPsDemux * demux, GstEvent * event)
1055 1056
{
  gboolean res = FALSE;
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075
  gdouble rate;
  GstFormat format;
  GstSeekFlags flags;
  GstSeekType start_type, stop_type;
  gint64 start, stop;
  gint64 bstart, bstop;
  GstEvent *