summaryrefslogtreecommitdiffstats
path: root/gst/mpegdemux
diff options
context:
space:
mode:
authorDave Robillard <dave@drobilla.net>2009-05-26 19:10:44 -0400
committerDave Robillard <dave@drobilla.net>2009-05-26 19:10:44 -0400
commitb75a26657febaf86c4137b4d41c068926325e316 (patch)
tree65c161824169ac09bf8418244937aec6ab77a270 /gst/mpegdemux
parent4e1d3bba9c21cb8bbfe70ffed953a8385fb7314d (diff)
parent8f70498c898a65d0938e3e104e91662ff5b693c3 (diff)
downloadgst-plugins-bad-b75a26657febaf86c4137b4d41c068926325e316.tar.gz
gst-plugins-bad-b75a26657febaf86c4137b4d41c068926325e316.tar.bz2
gst-plugins-bad-b75a26657febaf86c4137b4d41c068926325e316.zip
Merge branch 'master' of git://anongit.freedesktop.org/gstreamer/gst-plugins-bad into fdo
Diffstat (limited to 'gst/mpegdemux')
-rw-r--r--gst/mpegdemux/gstmpegdefs.h4
-rw-r--r--gst/mpegdemux/gstmpegdemux.c134
-rw-r--r--gst/mpegdemux/gstmpegdemux.h5
-rw-r--r--gst/mpegdemux/gstmpegtsdemux.c375
-rw-r--r--gst/mpegdemux/gstmpegtsdemux.h22
-rw-r--r--gst/mpegdemux/gstpesfilter.c18
-rw-r--r--gst/mpegdemux/gstpesfilter.h2
-rw-r--r--gst/mpegdemux/mpegtspacketizer.c19
-rw-r--r--gst/mpegdemux/mpegtspacketizer.h2
-rw-r--r--gst/mpegdemux/mpegtsparse.c69
-rw-r--r--gst/mpegdemux/mpegtsparse.h2
11 files changed, 547 insertions, 105 deletions
diff --git a/gst/mpegdemux/gstmpegdefs.h b/gst/mpegdemux/gstmpegdefs.h
index 7f38f4de..7ad1e25c 100644
--- a/gst/mpegdemux/gstmpegdefs.h
+++ b/gst/mpegdemux/gstmpegdefs.h
@@ -170,7 +170,11 @@
#define ST_PS_AUDIO_AC3 0x81
#define ST_PS_AUDIO_DTS 0x8a
#define ST_PS_AUDIO_LPCM 0x8b
+#define ST_HDV_PRIVATE_A0 0xa0
+#define ST_HDV_PRIVATE_A1 0xa1
#define ST_PS_DVD_SUBPICTURE 0xff
+/* Blu-ray PGS subpictures */
+#define ST_BD_PGS_SUBPICTURE 0x90
/* Un-official time-code stream */
#define ST_PS_TIMECODE 0xd2
diff --git a/gst/mpegdemux/gstmpegdemux.c b/gst/mpegdemux/gstmpegdemux.c
index 439bb563..ce1d0978 100644
--- a/gst/mpegdemux/gstmpegdemux.c
+++ b/gst/mpegdemux/gstmpegdemux.c
@@ -39,6 +39,7 @@
* Fluendo, S.L. All Rights Reserved.
*
* Contributor(s): Wim Taymans <wim@fluendo.com>
+ * Jan Schmidt <thaytan@noraisin.net>
*/
#ifdef HAVE_CONFIG_H
@@ -56,6 +57,9 @@
#define SCAN_SCR_SZ 12
#define SCAN_PTS_SZ 80
+#define SEGMENT_THRESHOLD (300*GST_MSECOND)
+#define VIDEO_SEGMENT_THRESHOLD (500*GST_MSECOND)
+
typedef enum
{
SCAN_SCR,
@@ -177,6 +181,13 @@ static GstStaticPadTemplate audio_template =
"audio/x-private1-ac3;" "audio/x-private1-dts;" "audio/ac3")
);
+static GstStaticPadTemplate subpicture_template =
+GST_STATIC_PAD_TEMPLATE ("subpicture_%02x",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
+ GST_STATIC_CAPS ("video/x-dvd-subpicture")
+ );
+
static GstStaticPadTemplate private_template =
GST_STATIC_PAD_TEMPLATE ("private_%d",
GST_PAD_SRC,
@@ -209,6 +220,10 @@ static inline gboolean gst_flups_demux_scan_forward_ts (GstFluPSDemux * demux,
static inline gboolean gst_flups_demux_scan_backward_ts (GstFluPSDemux * demux,
guint64 * pos, SCAN_MODE mode, guint64 * rts);
+static void gst_flups_demux_send_segment_updates (GstFluPSDemux * demux,
+ GstClockTime new_time);
+static void gst_flups_demux_clear_times (GstFluPSDemux * demux);
+
static GstElementClass *parent_class = NULL;
/*static guint gst_flups_demux_signals[LAST_SIGNAL] = { 0 };*/
@@ -250,10 +265,14 @@ gst_flups_demux_base_init (GstFluPSDemuxClass * 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);
+ klass->subpicture_template =
+ gst_static_pad_template_get (&subpicture_template);
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);
+ gst_element_class_add_pad_template (element_class,
+ klass->subpicture_template);
gst_element_class_add_pad_template (element_class, klass->private_template);
gst_element_class_add_pad_template (element_class, klass->sink_template);
@@ -340,6 +359,7 @@ gst_flups_demux_create_stream (GstFluPSDemux * demux, gint id, gint stream_type)
gchar *name;
GstFluPSDemuxClass *klass = GST_FLUPS_DEMUX_GET_CLASS (demux);
GstCaps *caps;
+ GstClockTime threshold = SEGMENT_THRESHOLD;
name = NULL;
template = NULL;
@@ -368,6 +388,7 @@ gst_flups_demux_create_stream (GstFluPSDemux * demux, gint id, gint stream_type)
caps = gst_caps_new_simple ("video/mpeg",
"mpegversion", G_TYPE_INT, mpeg_version,
"systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+ threshold = VIDEO_SEGMENT_THRESHOLD;
break;
}
case ST_AUDIO_MPEG1:
@@ -387,6 +408,7 @@ gst_flups_demux_create_stream (GstFluPSDemux * demux, gint id, gint stream_type)
template = klass->video_template;
name = g_strdup_printf ("video_%02x", id);
caps = gst_caps_new_simple ("video/x-h264", NULL);
+ threshold = VIDEO_SEGMENT_THRESHOLD;
break;
case ST_PS_AUDIO_AC3:
template = klass->audio_template;
@@ -404,6 +426,9 @@ gst_flups_demux_create_stream (GstFluPSDemux * demux, gint id, gint stream_type)
caps = gst_caps_new_simple ("audio/x-private1-lpcm", NULL);
break;
case ST_PS_DVD_SUBPICTURE:
+ template = klass->subpicture_template;
+ name = g_strdup_printf ("subpicture_%02x", id);
+ caps = gst_caps_new_simple ("video/x-dvd-subpicture", NULL);
break;
case ST_GST_AUDIO_RAWA52:
template = klass->audio_template;
@@ -424,6 +449,7 @@ gst_flups_demux_create_stream (GstFluPSDemux * demux, gint id, gint stream_type)
stream->notlinked = FALSE;
stream->type = stream_type;
stream->pad = gst_pad_new_from_template (template, name);
+ stream->segment_thresh = threshold;
gst_pad_set_event_function (stream->pad,
GST_DEBUG_FUNCPTR (gst_flups_demux_src_event));
gst_pad_set_query_function (stream->pad,
@@ -559,6 +585,20 @@ gst_flups_demux_send_data (GstFluPSDemux * demux, GstFluPSStream * stream,
GST_TIME_ARGS (demux->src_segment.last_stop),
GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->current_scr)));
+ if (demux->src_segment.last_stop != GST_CLOCK_TIME_NONE) {
+ GstClockTime new_time = demux->base_time + demux->src_segment.last_stop;
+
+ if (stream->last_ts == GST_CLOCK_TIME_NONE || stream->last_ts < new_time) {
+#if 0
+ g_print ("last_ts update on pad %s to time %" GST_TIME_FORMAT "\n",
+ GST_PAD_NAME (stream->pad), GST_TIME_ARGS (cur_scr_time));
+#endif
+ stream->last_ts = new_time;
+ }
+
+ gst_flups_demux_send_segment_updates (demux, new_time);
+ }
+
/* Set the buffer discont flag, and clear discont state on the stream */
if (stream->discont) {
GST_DEBUG_OBJECT (demux, "marking discont buffer");
@@ -731,12 +771,76 @@ gst_flups_demux_flush (GstFluPSDemux * demux)
gst_adapter_clear (demux->adapter);
gst_adapter_clear (demux->rev_adapter);
gst_pes_filter_drain (&demux->filter);
+ gst_flups_demux_clear_times (demux);
demux->adapter_offset = G_MAXUINT64;
demux->current_scr = G_MAXUINT64;
demux->bytes_since_scr = 0;
}
static void
+gst_flups_demux_clear_times (GstFluPSDemux * demux)
+{
+ gint id;
+
+ /* Clear the last ts for all streams */
+ for (id = 0; id < GST_FLUPS_DEMUX_MAX_STREAMS; id++) {
+ GstFluPSStream *stream = demux->streams[id];
+
+ if (stream) {
+ stream->last_seg_start = stream->last_ts = GST_CLOCK_TIME_NONE;
+ }
+ }
+}
+
+static void
+gst_flups_demux_send_segment_updates (GstFluPSDemux * demux,
+ GstClockTime new_time)
+{
+ /* Advance all lagging streams by sending a segment update */
+ gint id;
+ GstEvent *event = NULL;
+
+ /* FIXME: Handle reverse playback */
+
+ if (new_time > demux->src_segment.stop)
+ return;
+
+ for (id = 0; id < GST_FLUPS_DEMUX_MAX_STREAMS; id++) {
+ GstFluPSStream *stream = demux->streams[id];
+
+ if (stream) {
+ if (stream->last_ts == GST_CLOCK_TIME_NONE ||
+ stream->last_ts < demux->src_segment.start)
+ stream->last_ts = demux->src_segment.start;
+ if (stream->last_ts + stream->segment_thresh < new_time) {
+#if 0
+ g_print ("Segment update to pad %s time %" GST_TIME_FORMAT " stop now %"
+ GST_TIME_FORMAT "\n", GST_PAD_NAME (stream->pad),
+ GST_TIME_ARGS (new_time), GST_TIME_ARGS (demux->src_segment.stop));
+#endif
+ GST_DEBUG_OBJECT (demux,
+ "Segment update to pad %s time %" GST_TIME_FORMAT,
+ GST_PAD_NAME (stream->pad), GST_TIME_ARGS (new_time));
+ if (event == NULL) {
+ event = gst_event_new_new_segment_full (TRUE,
+ demux->src_segment.rate, demux->src_segment.applied_rate,
+ GST_FORMAT_TIME, new_time,
+ demux->src_segment.stop,
+ demux->src_segment.time + (new_time - demux->src_segment.start));
+ }
+ gst_event_ref (event);
+ gst_pad_push_event (stream->pad, event);
+ stream->last_seg_start = stream->last_ts = new_time;
+ stream->need_segment = FALSE;
+ }
+ }
+ }
+
+ if (event)
+ gst_event_unref (event);
+}
+
+static void
gst_flups_demux_close_segment (GstFluPSDemux * demux)
{
gint id;
@@ -747,6 +851,10 @@ gst_flups_demux_close_segment (GstFluPSDemux * demux)
&demux->src_segment);
#endif
+ /* FIXME: Need to send a different segment-close to each pad where the
+ * last_seg_start != clock_time_none, as that indicates a sparse-stream
+ * event was sent there */
+
/* Close the current segment for a linear playback */
if (demux->src_segment.rate >= 0) {
/* for forward playback, we played from start to last_stop */
@@ -1306,7 +1414,7 @@ gst_flups_demux_reset_psm (GstFluPSDemux * demux)
FILL_TYPE (0x40, 0x7f, -1);
FILL_TYPE (0x80, 0x87, ST_PS_AUDIO_AC3);
FILL_TYPE (0x88, 0x9f, ST_PS_AUDIO_DTS);
- FILL_TYPE (0xa0, 0xbf, ST_PS_AUDIO_LPCM);
+ FILL_TYPE (0xa0, 0xaf, ST_PS_AUDIO_LPCM);
FILL_TYPE (0xbd, 0xbd, -1);
FILL_TYPE (0xc0, 0xdf, ST_AUDIO_MPEG1);
FILL_TYPE (0xe0, 0xef, ST_GST_VIDEO_MPEG1_OR_2);
@@ -1839,18 +1947,26 @@ gst_flups_demux_data_cb (GstPESFilter * filter, gboolean first,
}
if (G_LIKELY (stream_type == -1)) {
- /* new id */
+ /* new id is in the first byte */
id = data[offset++];
- /* Number of audio frames in this packet */
- nframes = data[offset++];
-
- GST_DEBUG_OBJECT (demux, "private type 0x%02x, %d frames", id,
- nframes);
-
- datalen -= 2;
+ datalen--;
/* and remap */
stream_type = demux->psm[id];
+
+ /* Now, if it's a subpicture stream - no more, otherwise
+ * take the first byte too, since it's the frame count in audio
+ * streams and our backwards compat convention is to strip it off */
+ if (stream_type != ST_PS_DVD_SUBPICTURE) {
+ /* Number of audio frames in this packet */
+ nframes = data[offset++];
+ datalen--;
+ GST_DEBUG_OBJECT (demux, "private type 0x%02x, %d frames", id,
+ nframes);
+ } else {
+ GST_DEBUG_OBJECT (demux, "private type 0x%02x, stream type %d", id,
+ stream_type);
+ }
}
}
if (stream_type == -1)
diff --git a/gst/mpegdemux/gstmpegdemux.h b/gst/mpegdemux/gstmpegdemux.h
index ef175f76..29b3d5e5 100644
--- a/gst/mpegdemux/gstmpegdemux.h
+++ b/gst/mpegdemux/gstmpegdemux.h
@@ -86,6 +86,10 @@ struct _GstFluPSStream
gint type;
gint size_bound;
+ GstClockTime segment_thresh;
+ GstClockTime last_seg_start;
+ GstClockTime last_ts;
+
gboolean discont;
gboolean notlinked;
gboolean need_segment;
@@ -149,6 +153,7 @@ struct _GstFluPSDemuxClass
GstPadTemplate *sink_template;
GstPadTemplate *video_template;
GstPadTemplate *audio_template;
+ GstPadTemplate *subpicture_template;
GstPadTemplate *private_template;
};
diff --git a/gst/mpegdemux/gstmpegtsdemux.c b/gst/mpegdemux/gstmpegtsdemux.c
index 4464cdf8..ef0de2c8 100644
--- a/gst/mpegdemux/gstmpegtsdemux.c
+++ b/gst/mpegdemux/gstmpegtsdemux.c
@@ -34,9 +34,9 @@
*
* 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.
+ * The Initial Developer of the Original Code is Fluendo, S.A.
+ * Portions created by Fluendo, S.L. are Copyright (C) 2005,2006,2007,2008,2009
+ * Fluendo, S.A. All Rights Reserved.
*
* Contributor(s): Wim Taymans <wim@fluendo.com>
*/
@@ -126,6 +126,13 @@ enum
PROP_M2TS
};
+#define GSTTIME_TO_BYTES(time) \
+ ((time != -1) ? gst_util_uint64_scale (MAX(0,(gint64) ((time))), \
+ demux->bitrate, GST_SECOND) : -1)
+#define BYTES_TO_GSTTIME(bytes) \
+ ((bytes != -1) ? (gst_util_uint64_scale (bytes, GST_SECOND, \
+ demux->bitrate)) : -1)
+
#define VIDEO_CAPS \
GST_STATIC_CAPS (\
"video/mpeg, " \
@@ -150,6 +157,10 @@ enum
"audio/x-dts" \
)
+/* Can also use the subpicture pads for text subtitles? */
+#define SUBPICTURE_CAPS \
+ GST_STATIC_CAPS ("subpicture/x-pgs; video/x-dvd-subpicture")
+
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
@@ -168,6 +179,12 @@ GST_STATIC_PAD_TEMPLATE ("audio_%04x",
GST_PAD_SOMETIMES,
AUDIO_CAPS);
+static GstStaticPadTemplate subpicture_template =
+GST_STATIC_PAD_TEMPLATE ("subpicture_%04x",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
+ SUBPICTURE_CAPS);
+
static GstStaticPadTemplate private_template =
GST_STATIC_PAD_TEMPLATE ("private_%04x",
GST_PAD_SRC,
@@ -189,6 +206,7 @@ static void gst_mpegts_demux_get_property (GObject * object, guint prop_id,
static gboolean gst_mpegts_demux_is_PMT (GstMpegTSDemux * demux, guint16 PID);
static gboolean gst_mpegts_demux_sink_event (GstPad * pad, GstEvent * event);
+static gboolean gst_mpegts_demux_src_event (GstPad * pad, GstEvent * event);
static GstFlowReturn gst_mpegts_demux_chain (GstPad * pad, GstBuffer * buffer);
static gboolean gst_mpegts_demux_sink_setcaps (GstPad * pad, GstCaps * caps);
@@ -242,10 +260,14 @@ gst_mpegts_demux_base_init (GstMpegTSDemuxClass * 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);
+ klass->subpicture_template =
+ gst_static_pad_template_get (&subpicture_template);
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);
+ gst_element_class_add_pad_template (element_class,
+ klass->subpicture_template);
gst_element_class_add_pad_template (element_class, klass->private_template);
gst_element_class_add_pad_template (element_class, klass->sink_template);
@@ -327,7 +349,12 @@ gst_mpegts_demux_init (GstMpegTSDemux * demux)
demux->m2ts_mode = FALSE;
demux->sync_lut = NULL;
demux->sync_lut_len = 0;
-
+ demux->bitrate = -1;
+ demux->num_packets = 0;
+ demux->pcr[0] = -1;
+ demux->pcr[1] = -1;
+ demux->cache_duration = GST_CLOCK_TIME_NONE;
+ demux->base_pts = GST_CLOCK_TIME_NONE;
#ifdef USE_LIBOIL
oil_init ();
#endif
@@ -369,8 +396,8 @@ gst_mpegts_demux_reset (GstMpegTSDemux * demux)
case PID_TYPE_ELEMENTARY:
gst_pes_filter_uninit (&stream->filter);
break;
- case PID_PROGRAM_ASSOCIATION_TABLE:
- case PID_CONDITIONAL_ACCESS_TABLE:
+ case PID_TYPE_PROGRAM_ASSOCIATION:
+ case PID_TYPE_CONDITIONAL_ACCESS:
case PID_TYPE_PROGRAM_MAP:
gst_section_filter_uninit (&stream->section_filter);
break;
@@ -607,6 +634,16 @@ gst_mpegts_demux_fill_stream (GstMpegTSStream * stream, guint8 id,
caps = gst_caps_new_simple ("private/teletext", NULL);
}
break;
+ case ST_HDV_PRIVATE_A0:
+ template = klass->private_template;
+ name = g_strdup_printf ("private_%04x", stream->PID);
+ caps = gst_caps_new_simple ("private/hdv-a0", NULL);
+ break;
+ case ST_HDV_PRIVATE_A1:
+ template = klass->private_template;
+ name = g_strdup_printf ("private_%04x", stream->PID);
+ caps = gst_caps_new_simple ("private/hdv-a1", NULL);
+ break;
case ST_PRIVATE_SECTIONS:
case ST_MHEG:
case ST_DSMCC:
@@ -652,6 +689,14 @@ gst_mpegts_demux_fill_stream (GstMpegTSStream * stream, guint8 id,
caps = gst_caps_new_simple ("audio/x-lpcm", NULL);
break;
case ST_PS_DVD_SUBPICTURE:
+ template = klass->subpicture_template;
+ name = g_strdup_printf ("subpicture_%04x", stream->PID);
+ caps = gst_caps_new_simple ("video/x-dvd-subpicture", NULL);
+ break;
+ case ST_BD_PGS_SUBPICTURE:
+ template = klass->subpicture_template;
+ name = g_strdup_printf ("subpicture_%04x", stream->PID);
+ caps = gst_caps_new_simple ("subpicture/x-pgs", NULL);
break;
default:
break;
@@ -668,6 +713,8 @@ gst_mpegts_demux_fill_stream (GstMpegTSStream * stream, guint8 id,
gst_caps_unref (caps);
gst_pad_set_query_function (stream->pad,
GST_DEBUG_FUNCPTR (gst_mpegts_demux_src_pad_query));
+ gst_pad_set_event_function (stream->pad,
+ GST_DEBUG_FUNCPTR (gst_mpegts_demux_src_event));
g_free (name);
return TRUE;
@@ -730,7 +777,7 @@ gst_mpegts_demux_send_new_segment (GstMpegTSDemux * demux,
}
base_PCR = PCR_stream->base_PCR;
- time = MPEGTIME_TO_GSTTIME (base_PCR);
+ demux->base_pts = time = MPEGTIME_TO_GSTTIME (base_PCR);
GST_DEBUG_OBJECT (demux, "segment PTS to (%" G_GUINT64_FORMAT ") time: %"
G_GUINT64_FORMAT, base_PCR, time);
@@ -828,7 +875,7 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first,
demux = stream->demux;
srcpad = stream->pad;
- GST_LOG_OBJECT (demux, "got data on PID 0x%04x", stream->PID);
+ GST_DEBUG_OBJECT (demux, "got data on PID 0x%04x", stream->PID);
if (first && filter->pts != -1) {
pts = filter->pts;
@@ -932,7 +979,7 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first,
pts = -1;
}
- GST_LOG_OBJECT (demux, "setting PTS to (%" G_GUINT64_FORMAT ") time: %"
+ GST_DEBUG_OBJECT (demux, "setting PTS to (%" G_GUINT64_FORMAT ") time: %"
GST_TIME_FORMAT " on buffer %p first buffer: %d base_time: %"
GST_TIME_FORMAT, pts, GST_TIME_ARGS (time), buffer, first,
GST_TIME_ARGS (stream->base_time));
@@ -967,8 +1014,8 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first,
goto unknown_type;
GST_DEBUG_OBJECT (demux,
- "New stream 0x%04x of type %d with caps %" GST_PTR_FORMAT, stream->PID,
- stream->stream_type, GST_PAD_CAPS (stream->pad));
+ "New stream 0x%04x of type 0x%02x with caps %" GST_PTR_FORMAT,
+ stream->PID, stream->stream_type, GST_PAD_CAPS (stream->pad));
srcpad = stream->pad;
@@ -981,7 +1028,7 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first,
gst_mpegts_demux_send_new_segment (demux, stream, pts);
}
- GST_DEBUG_OBJECT (demux, "pushing buffer");
+ GST_DEBUG_OBJECT (srcpad, "pushing buffer");
gst_buffer_set_caps (buffer, GST_PAD_CAPS (srcpad));
ret = gst_pad_push (srcpad, buffer);
ret = gst_mpegts_demux_combine_flows (demux, stream, ret);
@@ -992,7 +1039,7 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first,
unknown_type:
{
GST_DEBUG_OBJECT (demux, "got unknown stream id 0x%02x, type 0x%02x",
- filter->id, filter->type);
+ filter->id, stream->stream_type);
gst_buffer_unref (buffer);
return gst_mpegts_demux_combine_flows (demux, stream, GST_FLOW_NOT_LINKED);
}
@@ -1184,16 +1231,16 @@ gst_mpegts_stream_parse_pmt (GstMpegTSStream * stream,
if (gst_mpegts_demux_calc_crc32 (data - 3, datalen) != 0)
goto wrong_crc;
- GST_DEBUG_OBJECT (demux, "PMT section_length: %d", datalen - 3);
+ GST_LOG_OBJECT (demux, "PMT section_length: %d", datalen - 3);
PMT = &stream->PMT;
/* check if version number changed */
version_number = (data[2] & 0x3e) >> 1;
- GST_DEBUG_OBJECT (demux, "PMT version_number: %d", version_number);
+ GST_LOG_OBJECT (demux, "PMT version_number: %d", version_number);
current_next_indicator = (data[2] & 0x01);
- GST_DEBUG_OBJECT (demux, "PMT current_next_indicator %d",
+ GST_LOG_OBJECT (demux, "PMT current_next_indicator %d",
current_next_indicator);
if (current_next_indicator == 0)
goto not_yet_applicable;
@@ -1559,7 +1606,7 @@ gst_mpegts_demux_parse_adaptation_field (GstMpegTSStream * stream,
if (length > 0) {
guint8 flags = *data++;
- GST_DEBUG_OBJECT (demux, "flags 0x%02x", flags);
+ GST_LOG_OBJECT (demux, "flags 0x%02x", flags);
/* discontinuity flag */
if (flags & 0x80) {
GST_DEBUG_OBJECT (demux, "discontinuity flag set");
@@ -1578,9 +1625,12 @@ gst_mpegts_demux_parse_adaptation_field (GstMpegTSStream * stream,
pcr_ext = (pcr2 & 0x01ff);
if (pcr_ext)
pcr = (pcr * 300 + pcr_ext % 300) / 300;
- GST_DEBUG_OBJECT (demux, "have PCR %" G_GUINT64_FORMAT " on PID 0x%04x "
- "and last pcr is %" G_GUINT64_FORMAT,
- pcr, stream->PID, stream->last_PCR);
+ GST_DEBUG_OBJECT (demux,
+ "have PCR %" G_GUINT64_FORMAT "(%" GST_TIME_FORMAT ") on PID 0x%04x "
+ "and last pcr is %" G_GUINT64_FORMAT " (%" GST_TIME_FORMAT ")", pcr,
+ GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (pcr)), stream->PID,
+ stream->last_PCR,
+ GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (stream->last_PCR)));
/* pcr has been converted into units of 90Khz ticks
* so assume discont if last pcr was > 900000 (10 second) lower */
if (stream->last_PCR != -1 &&
@@ -1676,11 +1726,24 @@ gst_mpegts_demux_parse_adaptation_field (GstMpegTSStream * stream,
}
stream->last_PCR_difference = pcr - stream->last_PCR;
}
+
GST_DEBUG_OBJECT (demux,
"valid pcr: %d last PCR difference: %" G_GUINT64_FORMAT, valid_pcr,
stream->last_PCR_difference);
if (valid_pcr) {
-
+ GstMpegTSStream *PMT_stream = demux->streams[demux->current_PMT];
+
+ if (PMT_stream && PMT_stream->PMT.PCR_PID == stream->PID) {
+ if (demux->pcr[0] == -1) {
+ GST_DEBUG ("RECORDING pcr[0]:%" G_GUINT64_FORMAT, pcr);
+ demux->pcr[0] = pcr;
+ demux->num_packets = 0;
+ } /* Considering a difference of 1 sec ie 90000 ticks */
+ else if (demux->pcr[1] == -1 && ((pcr - demux->pcr[0]) >= 90000)) {
+ GST_DEBUG ("RECORDING pcr[1]:%" G_GUINT64_FORMAT, pcr);
+ demux->pcr[1] = pcr;
+ }
+ }
stream->last_PCR = pcr;
if (demux->clock && demux->clock_base != GST_CLOCK_TIME_NONE) {
@@ -1955,15 +2018,20 @@ gst_mpegts_demux_is_PMT (GstMpegTSDemux * demux, guint16 PID)
}
static FORCE_INLINE GstFlowReturn
-gst_mpegts_stream_pes_buffer_flush (GstMpegTSStream * stream)
+gst_mpegts_stream_pes_buffer_flush (GstMpegTSStream * stream, gboolean discard)
{
GstFlowReturn ret = GST_FLOW_OK;
if (stream->pes_buffer) {
- GST_BUFFER_SIZE (stream->pes_buffer) = stream->pes_buffer_used;
- ret = gst_pes_filter_push (&stream->filter, stream->pes_buffer);
- if (ret == GST_FLOW_LOST_SYNC)
+ if (discard) {
+ gst_buffer_unref (stream->pes_buffer);
stream->pes_buffer_in_sync = FALSE;
+ } else {
+ GST_BUFFER_SIZE (stream->pes_buffer) = stream->pes_buffer_used;
+ ret = gst_pes_filter_push (&stream->filter, stream->pes_buffer);
+ if (ret == GST_FLOW_LOST_SYNC)
+ stream->pes_buffer_in_sync = FALSE;
+ }
stream->pes_buffer = NULL;
}
return ret;
@@ -1985,7 +2053,7 @@ gst_mpegts_stream_pes_buffer_push (GstMpegTSStream * stream,
if (stream->pes_buffer_size < (MPEGTS_MAX_PES_BUFFER_SIZE >> 1))
stream->pes_buffer_size <<= 1;
- ret = gst_mpegts_stream_pes_buffer_flush (stream);
+ ret = gst_mpegts_stream_pes_buffer_flush (stream, FALSE);
if (ret == GST_FLOW_LOST_SYNC)
goto done;
}
@@ -2010,7 +2078,7 @@ done:
}
static FORCE_INLINE GstFlowReturn
-gst_mpegts_demux_pes_buffer_flush (GstMpegTSDemux * demux)
+gst_mpegts_demux_pes_buffer_flush (GstMpegTSDemux * demux, gboolean discard)
{
gint i;
GstFlowReturn ret = GST_FLOW_OK;
@@ -2018,7 +2086,7 @@ gst_mpegts_demux_pes_buffer_flush (GstMpegTSDemux * demux)
for (i = 0; i < MPEGTS_MAX_PID + 1; i++) {
GstMpegTSStream *stream = demux->streams[i];
if (stream && stream->pad) {
- gst_mpegts_stream_pes_buffer_flush (stream);
+ gst_mpegts_stream_pes_buffer_flush (stream, discard);
stream->pes_buffer_in_sync = FALSE;
}
}
@@ -2093,7 +2161,7 @@ gst_mpegts_demux_parse_stream (GstMpegTSDemux * demux, GstMpegTSStream * stream,
data += 3;
datalen -= 3;
- GST_DEBUG_OBJECT (demux, "afc 0x%x, pusi %d, PID 0x%04x datalen %u",
+ GST_LOG_OBJECT (demux, "afc 0x%x, pusi %d, PID 0x%04x datalen %u",
adaptation_field_control, payload_unit_start_indicator, PID, datalen);
ret = GST_FLOW_OK;
@@ -2115,13 +2183,12 @@ gst_mpegts_demux_parse_stream (GstMpegTSDemux * demux, GstMpegTSStream * stream,
data += consumed;
datalen -= consumed;
- GST_DEBUG_OBJECT (demux, "consumed: %u datalen: %u", consumed, datalen);
+ GST_LOG_OBJECT (demux, "consumed: %u datalen: %u", consumed, datalen);
}
/* If this packet has a payload, handle it */
if (adaptation_field_control & 0x1) {
- GST_DEBUG_OBJECT (demux, "Packet payload %d bytes, PID 0x%04x", datalen,
- PID);
+ GST_LOG_OBJECT (demux, "Packet payload %d bytes, PID 0x%04x", datalen, PID);
/* For unknown streams, check if the PID is in the partial PIDs
* list as an elementary stream and override the type if so
@@ -2233,7 +2300,7 @@ gst_mpegts_demux_parse_stream (GstMpegTSDemux * demux, GstMpegTSStream * stream,
"bytes of %u bytes in the PES buffer",
PID, stream->pes_buffer_used, stream->pes_buffer_size);
/* Flush buffered PES data */
- gst_mpegts_stream_pes_buffer_flush (stream);
+ gst_mpegts_stream_pes_buffer_flush (stream, FALSE);
gst_pes_filter_drain (&stream->filter);
/* Resize the buffer to half if no overflow detected and
* had been used less than half of it */
@@ -2302,7 +2369,7 @@ static FORCE_INLINE GstFlowReturn
gst_mpegts_demux_parse_transport_packet (GstMpegTSDemux * demux,
const guint8 * data)
{
- GstFlowReturn ret;
+ GstFlowReturn ret = GST_FLOW_OK;
guint16 PID;
GstMpegTSStream *stream;
@@ -2312,6 +2379,10 @@ gst_mpegts_demux_parse_transport_packet (GstMpegTSDemux * demux,
/* get PID */
PID = ((data[0] & 0x1f) << 8) | data[1];
+ /* Skip NULL packets */
+ if (G_UNLIKELY (PID == 0x1fff))
+ goto beach;
+
/* get the stream. */
stream = gst_mpegts_demux_get_stream_for_PID (demux, PID);
@@ -2319,12 +2390,153 @@ gst_mpegts_demux_parse_transport_packet (GstMpegTSDemux * demux,
ret = gst_mpegts_demux_parse_stream (demux, stream, data,
MPEGTS_NORMAL_TS_PACKETSIZE - 1);
+ if (demux->pcr[1] != -1 && demux->bitrate == -1) {
+ guint64 bitrate;
+ GST_DEBUG_OBJECT (demux, "pcr[0]:%" G_GUINT64_FORMAT, demux->pcr[0]);
+ GST_DEBUG_OBJECT (demux, "pcr[1]:%" G_GUINT64_FORMAT, demux->pcr[1]);
+ GST_DEBUG_OBJECT (demux, "diff in time %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->pcr[1] - demux->pcr[0])));
+ GST_DEBUG_OBJECT (demux, "stream->last_PCR_difference: %" G_GUINT64_FORMAT
+ ", demux->num_packets %" G_GUINT64_FORMAT,
+ demux->pcr[1] - demux->pcr[0], demux->num_packets);
+ bitrate = gst_util_uint64_scale (GST_SECOND,
+ MPEGTS_NORMAL_TS_PACKETSIZE * demux->num_packets,
+ MPEGTIME_TO_GSTTIME (demux->pcr[1] - demux->pcr[0]));
+ /* somehow... I doubt a bitrate below one packet per second is valid */
+ if (bitrate > MPEGTS_NORMAL_TS_PACKETSIZE - 1) {
+ demux->bitrate = bitrate;
+ GST_DEBUG_OBJECT (demux, "bitrate is %" G_GINT64_FORMAT
+ " bytes per second", demux->bitrate);
+ } else {
+ GST_WARNING_OBJECT (demux, "Couldn't compute valid bitrate, recomputing");
+ demux->pcr[0] = demux->pcr[1] = -1;
+ demux->num_packets = -1;
+ }
+ }
+
+beach:
+ demux->num_packets++;
return ret;
/* ERRORS */
}
static gboolean
+gst_mpegts_demux_handle_seek_push (GstMpegTSDemux * demux, GstEvent * event)
+{
+ gboolean res = FALSE;
+ gdouble rate;
+ GstFormat format;
+ GstSeekFlags flags;
+ GstSeekType start_type, stop_type;
+ gint64 start, stop, bstart, bstop;
+ GstEvent *bevent;
+
+ gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
+ &stop_type, &stop);
+
+ GST_DEBUG_OBJECT (demux, "seek event, rate: %f start: %" GST_TIME_FORMAT
+ " stop: %" GST_TIME_FORMAT, rate, GST_TIME_ARGS (start),
+ GST_TIME_ARGS (stop));
+
+ if (format == GST_FORMAT_BYTES) {
+ GST_DEBUG_OBJECT (demux, "seek not supported on format %d", format);
+ goto beach;
+ }
+
+ GST_DEBUG_OBJECT (demux, "seek - trying directly upstream first");
+
+ /* first try original format seek */
+ res = gst_pad_push_event (demux->sinkpad, gst_event_ref (event));
+ if (res == TRUE)
+ goto beach;
+ GST_DEBUG_OBJECT (demux, "seek - no upstream");
+
+ if (format != GST_FORMAT_TIME) {
+ /* From here down, we only support time based seeks */
+ GST_DEBUG_OBJECT (demux, "seek not supported on format %d", format);
+ goto beach;
+ }
+
+ /* We need to convert to byte based seek and we need a scr_rate for that. */
+ if (demux->bitrate == -1) {
+ GST_DEBUG_OBJECT (demux, "seek not possible, no bitrate");
+ goto beach;
+ }
+
+ GST_DEBUG_OBJECT (demux, "try with bitrate");
+
+ bstart = GSTTIME_TO_BYTES (start);
+ bstop = GSTTIME_TO_BYTES (stop);
+
+ GST_DEBUG_OBJECT (demux, "in bytes bstart %" G_GINT64_FORMAT " bstop %"
+ G_GINT64_FORMAT, bstart, bstop);
+ bevent = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, start_type,
+ bstart, stop_type, bstop);
+
+ res = gst_pad_push_event (demux->sinkpad, bevent);
+
+beach:
+ gst_event_unref (event);
+ return res;
+}
+
+static gboolean
+gst_mpegts_demux_src_event (GstPad * pad, GstEvent * event)
+{
+ GstMpegTSDemux *demux = GST_MPEGTS_DEMUX (gst_pad_get_parent (pad));
+ gboolean res = FALSE;
+
+ GST_DEBUG_OBJECT (demux, "got event %s",
+ gst_event_type_get_name (GST_EVENT_TYPE (event)));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEEK:
+ res = gst_mpegts_demux_handle_seek_push (demux, event);
+ break;
+ default:
+ res = gst_pad_push_event (demux->sinkpad, event);
+ break;
+ }
+
+ gst_object_unref (demux);
+
+ return res;
+}
+
+static void
+gst_mpegts_demux_flush (GstMpegTSDemux * demux, gboolean discard)
+{
+ GstMpegTSStream *PCR_stream;
+ GstMpegTSStream *PMT_stream;
+
+ GST_DEBUG_OBJECT (demux, "flushing MPEG TS demuxer (discard %d)", discard);
+
+ /* Start by flushing internal buffers */
+ gst_mpegts_demux_pes_buffer_flush (demux, discard);
+
+ /* Clear adapter */
+ gst_adapter_clear (demux->adapter);
+
+ /* Try resetting the last_PCR value as we will have a discont */
+ if (demux->current_PMT == 0)
+ goto beach;
+
+ PMT_stream = demux->streams[demux->current_PMT];
+ if (PMT_stream == NULL)
+ goto beach;
+
+ PCR_stream = demux->streams[PMT_stream->PMT.PCR_PID];
+ if (PCR_stream == NULL)
+ goto beach;
+
+ PCR_stream->last_PCR = -1;
+
+beach:
+ return;
+}
+
+static gboolean
gst_mpegts_demux_send_event (GstMpegTSDemux * demux, GstEvent * event)
{
gint i;
@@ -2347,7 +2559,7 @@ static gboolean
gst_mpegts_demux_sink_event (GstPad * pad, GstEvent * event)
{
GstMpegTSDemux *demux = GST_MPEGTS_DEMUX (gst_pad_get_parent (pad));
- gboolean res;
+ gboolean res = FALSE;
GST_DEBUG_OBJECT (demux, "got event %s",
gst_event_type_get_name (GST_EVENT_TYPE (event)));
@@ -2358,11 +2570,11 @@ gst_mpegts_demux_sink_event (GstPad * pad, GstEvent * event)
break;
case GST_EVENT_FLUSH_STOP:
gst_adapter_clear (demux->adapter);
+ gst_mpegts_demux_flush (demux, TRUE);
res = gst_mpegts_demux_send_event (demux, event);
break;
case GST_EVENT_EOS:
- /* Flush buffered PES data */
- gst_mpegts_demux_pes_buffer_flush (demux);
+ gst_mpegts_demux_flush (demux, FALSE);
/* Send the EOS event on each stream */
if (!(res = gst_mpegts_demux_send_event (demux, event))) {
/* we have no streams */
@@ -2371,15 +2583,46 @@ gst_mpegts_demux_sink_event (GstPad * pad, GstEvent * event)
}
break;
case GST_EVENT_NEWSEGMENT:
- res = gst_mpegts_demux_send_event (demux, event);
+ {
+ gboolean update;
+ gdouble rate;
+ GstFormat format;
+ gint64 start, stop, time;
+
+ gst_event_parse_new_segment (event, &update, &rate, &format,
+ &start, &stop, &time);
+
+ gst_event_unref (event);
+ GST_INFO_OBJECT (demux, "received new segment: rate %g "
+ "format %d, start: %" G_GINT64_FORMAT ", stop: %" G_GINT64_FORMAT
+ ", time: %" G_GINT64_FORMAT, rate, format, start, stop, time);
+ if (format == GST_FORMAT_BYTES && demux->bitrate != -1) {
+ gint64 tstart = 0, tstop = 0, pos = 0;
+
+ if (demux->base_pts != GST_CLOCK_TIME_NONE) {
+ tstart = tstop = demux->base_pts;
+ }
+ tstart += BYTES_TO_GSTTIME (start);
+ tstop += BYTES_TO_GSTTIME (stop);
+ pos = BYTES_TO_GSTTIME (time);
+
+ event = gst_event_new_new_segment (update, rate,
+ GST_FORMAT_TIME, tstart, tstop, pos);
+ GST_DEBUG_OBJECT (demux, "pushing time newsegment from %"
+ GST_TIME_FORMAT " to %" GST_TIME_FORMAT " pos %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (tstart), GST_TIME_ARGS (tstop), GST_TIME_ARGS (pos));
+
+ res = gst_mpegts_demux_send_event (demux, event);
+ }
break;
+ }
default:
res = gst_mpegts_demux_send_event (demux, event);
break;
}
gst_object_unref (demux);
- return TRUE;
+ return res;
}
static gboolean
@@ -2415,8 +2658,7 @@ gst_mpegts_demux_provide_clock (GstElement * element)
"MpegTSClock", NULL);
demux->clock_base = GST_CLOCK_TIME_NONE;
}
-
- return demux->clock;
+ return gst_object_ref (demux->clock);
}
return NULL;
@@ -2455,21 +2697,54 @@ gst_mpegts_demux_src_pad_query (GstPad * pad, GstQuery * query)
case GST_QUERY_DURATION:
{
GstFormat format;
- gint64 duration;
+ GstPad *peer;
- gst_query_parse_duration (query, &format, &duration);
+ gst_query_parse_duration (query, &format, NULL);
- if (format == GST_FORMAT_BYTES) {
- res = FALSE;
- } else {
- res = gst_pad_query_default (pad, query);
+ /* Try query upstream first */
+ peer = gst_pad_get_peer (demux->sinkpad);
+ if (peer) {
+ res = gst_pad_query (peer, query);
+ /* Try doing something with that query if it failed */
+ if (!res && format == GST_FORMAT_TIME && demux->bitrate != -1) {
+ /* Try using cache first */
+ if (GST_CLOCK_TIME_IS_VALID (demux->cache_duration)) {
+ GST_LOG_OBJECT (demux, "replying duration query from cache %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (demux->cache_duration));
+ gst_query_set_duration (query, GST_FORMAT_TIME,
+ demux->cache_duration);
+ res = TRUE;
+ } else { /* Query upstream and approximate */
+ GstQuery *bquery = gst_query_new_duration (GST_FORMAT_BYTES);
+ gint64 duration = 0;
+
+ /* Query peer for duration in bytes */
+ res = gst_pad_query (peer, bquery);
+ if (res) {
+ /* Convert to time format */
+ gst_query_parse_duration (bquery, &format, &duration);
+ GST_DEBUG_OBJECT (demux, "query on peer pad reported bytes %"
+ G_GUINT64_FORMAT, duration);
+ demux->cache_duration = BYTES_TO_GSTTIME (duration);
+ GST_DEBUG_OBJECT (demux, "converted to time %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (demux->cache_duration));
+ gst_query_set_duration (query, GST_FORMAT_TIME,
+ demux->cache_duration);
+ }
+ gst_query_unref (bquery);
+ }
+ } else {
+ GST_WARNING_OBJECT (demux, "unsupported query format or no bitrate "
+ "yet to approximate duration from bytes");
+ }
+ gst_object_unref (peer);
}
-
break;
}
default:
res = gst_pad_query_default (pad, query);
}
+ gst_object_unref (demux);
return res;
}
@@ -2554,9 +2829,7 @@ gst_mpegts_demux_chain (GstPad * pad, GstBuffer * buffer)
guint sync_count;
if (GST_BUFFER_IS_DISCONT (buffer)) {
- /* Flush buffered PES data */
- gst_mpegts_demux_pes_buffer_flush (demux);
- gst_adapter_clear (demux->adapter);
+ gst_mpegts_demux_flush (demux, FALSE);
}
/* first push the new buffer into the adapter */
gst_adapter_push (demux->adapter, buffer);
diff --git a/gst/mpegdemux/gstmpegtsdemux.h b/gst/mpegdemux/gstmpegtsdemux.h
index 8a4ca3d2..fde68926 100644
--- a/gst/mpegdemux/gstmpegtsdemux.h
+++ b/gst/mpegdemux/gstmpegtsdemux.h
@@ -34,9 +34,9 @@
*
* 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.
+ * The Initial Developer of the Original Code is Fluendo, S.A.
+ * Portions created by Fluendo, S.A. are Copyright (C) 2005,2006,2007,2008,2009
+ * Fluendo, S.A. All Rights Reserved.
*
* Contributor(s): Wim Taymans <wim@fluendo.com>
*/
@@ -205,6 +205,21 @@ struct _GstMpegTSDemux {
/* clocking */
GstClock * clock;
GstClockTime clock_base;
+
+ /* Additional information required for seeking.
+ * num_packets: Number of packets outputted
+ * bitrate: estimated bitrate (based on pcr and num_packets */
+ guint64 num_packets;
+ gint64 bitrate;
+
+ /* Two PCRs observations to calculate bitrate */
+ guint64 pcr[2];
+
+ /* Cached duration estimation */
+ GstClockTime cache_duration;
+
+ /* Cached base_PCR in GStreamer time. */
+ GstClockTime base_pts;
};
struct _GstMpegTSDemuxClass {
@@ -213,6 +228,7 @@ struct _GstMpegTSDemuxClass {
GstPadTemplate * sink_template;
GstPadTemplate * video_template;
GstPadTemplate * audio_template;
+ GstPadTemplate * subpicture_template;
GstPadTemplate * private_template;
};
diff --git a/gst/mpegdemux/gstpesfilter.c b/gst/mpegdemux/gstpesfilter.c
index 1295a193..b520c766 100644
--- a/gst/mpegdemux/gstpesfilter.c
+++ b/gst/mpegdemux/gstpesfilter.c
@@ -167,6 +167,9 @@ gst_pes_filter_parse (GstPESFilter * filter)
avail = MIN (avail, filter->length + 6);
}
+ if (avail < 7)
+ goto need_more_data;
+
/* read more data, either the whole packet if there is a length
* or whatever we have available if this in an unbounded packet. */
if (!(data = gst_adapter_peek (filter->adapter, avail)))
@@ -189,7 +192,8 @@ gst_pes_filter_parse (GstPESFilter * filter)
case ID_PROGRAM_STREAM_DIRECTORY:
case ID_DSMCC_STREAM:
case ID_ITU_TREC_H222_TYPE_E_STREAM:
- goto skip;
+ /* Push directly out */
+ goto push_out;
case ID_PADDING_STREAM:
GST_DEBUG ("skipping padding stream");
goto skip;
@@ -197,9 +201,6 @@ gst_pes_filter_parse (GstPESFilter * filter)
break;
}
- if (datalen < 1)
- goto need_more_data;
-
filter->pts = filter->dts = -1;
/* stuffing bits, first two bits are '10' for mpeg2 pes so this code is
@@ -404,6 +405,7 @@ gst_pes_filter_parse (GstPESFilter * filter)
goto lost_sync;
}
+push_out:
{
GstBuffer *out;
guint16 consumed;
@@ -563,14 +565,8 @@ gst_pes_filter_process (GstPESFilter * filter)
ret = GST_FLOW_OK;
} else {
GstBuffer *out;
- guint8 *data;
-
- data = gst_adapter_take (filter->adapter, avail);
- out = gst_buffer_new ();
- GST_BUFFER_DATA (out) = data;
- GST_BUFFER_SIZE (out) = avail;
- GST_BUFFER_MALLOCDATA (out) = data;
+ out = gst_adapter_take_buffer (filter->adapter, avail);
ret = gst_pes_filter_data_push (filter, filter->first, out);
filter->first = FALSE;
diff --git a/gst/mpegdemux/gstpesfilter.h b/gst/mpegdemux/gstpesfilter.h
index b35d8746..ccc8461d 100644
--- a/gst/mpegdemux/gstpesfilter.h
+++ b/gst/mpegdemux/gstpesfilter.h
@@ -84,8 +84,6 @@ struct _GstPESFilter {
gboolean unbounded_packet;
guint16 length;
- guint8 type;
-
gint64 pts;
gint64 dts;
};
diff --git a/gst/mpegdemux/mpegtspacketizer.c b/gst/mpegdemux/mpegtspacketizer.c
index 1abbf1fe..b986fa60 100644
--- a/gst/mpegdemux/mpegtspacketizer.c
+++ b/gst/mpegdemux/mpegtspacketizer.c
@@ -241,7 +241,8 @@ mpegts_packetizer_parse_section_header (MpegTSPacketizer * packetizer,
data = GST_BUFFER_DATA (section->buffer);
section->table_id = *data++;
- if ((data[0] & 0x80) == 0)
+ /* if table_id is 0 (pat) then ignore the subtable extension */
+ if ((data[0] & 0x80) == 0 || section->table_id == 0)
section->subtable_extension = 0;
else
section->subtable_extension = GST_READ_UINT16_BE (data + 2);
@@ -1844,6 +1845,22 @@ mpegts_packetizer_clear (MpegTSPacketizer * packetizer)
gst_adapter_clear (packetizer->adapter);
}
+void
+mpegts_packetizer_remove_stream (MpegTSPacketizer * packetizer, gint16 pid)
+{
+ MpegTSPacketizerStream *stream =
+ (MpegTSPacketizerStream *) g_hash_table_lookup (packetizer->streams,
+ GINT_TO_POINTER ((gint) pid));
+ if (stream) {
+ GST_INFO ("Removing stream for PID %d", pid);
+
+ g_hash_table_remove (packetizer->streams, GINT_TO_POINTER ((gint) pid));
+
+ g_object_unref (stream->section_adapter);
+ g_free (stream);
+ }
+}
+
MpegTSPacketizer *
mpegts_packetizer_new ()
{
diff --git a/gst/mpegdemux/mpegtspacketizer.h b/gst/mpegdemux/mpegtspacketizer.h
index c54228af..97e15cf2 100644
--- a/gst/mpegdemux/mpegtspacketizer.h
+++ b/gst/mpegdemux/mpegtspacketizer.h
@@ -116,6 +116,8 @@ gboolean mpegts_packetizer_next_packet (MpegTSPacketizer *packetizer,
MpegTSPacketizerPacket *packet);
void mpegts_packetizer_clear_packet (MpegTSPacketizer *packetizer,
MpegTSPacketizerPacket *packet);
+void mpegts_packetizer_remove_stream(MpegTSPacketizer *packetizer,
+ gint16 pid);
gboolean mpegts_packetizer_push_section (MpegTSPacketizer *packetzer,
MpegTSPacketizerPacket *packet, MpegTSPacketizerSection *section);
diff --git a/gst/mpegdemux/mpegtsparse.c b/gst/mpegdemux/mpegtsparse.c
index 3a2d647d..976935f2 100644
--- a/gst/mpegdemux/mpegtsparse.c
+++ b/gst/mpegdemux/mpegtsparse.c
@@ -266,12 +266,15 @@ mpegts_parse_init (MpegTSParse * parse, MpegTSParseClass * klass)
gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad);
parse->disposed = FALSE;
+ parse->need_sync_program_pads = FALSE;
parse->packetizer = mpegts_packetizer_new ();
parse->program_numbers = g_strdup ("");
parse->pads_to_add = NULL;
+ parse->pads_to_remove = NULL;
parse->programs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL, (GDestroyNotify) mpegts_parse_free_program);
parse->psi_pids = g_hash_table_new (g_direct_hash, g_direct_equal);
+ parse->pes_pids = g_hash_table_new (g_direct_hash, g_direct_equal);
mpegts_parse_reset (parse);
}
@@ -301,6 +304,7 @@ mpegts_parse_finalize (GObject * object)
}
g_hash_table_destroy (parse->programs);
g_hash_table_destroy (parse->psi_pids);
+ g_hash_table_destroy (parse->pes_pids);
if (G_OBJECT_CLASS (parent_class)->finalize)
G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -348,7 +352,7 @@ mpegts_parse_add_program (MpegTSParse * parse,
program->pcr_pid = G_MAXUINT16;
program->streams = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL, (GDestroyNotify) mpegts_parse_free_stream);
- program->patcount = 1;
+ program->patcount = 0;
program->selected = 0;
program->active = FALSE;
@@ -422,22 +426,30 @@ mpegts_parse_remove_program (MpegTSParse * parse, gint program_number)
}
static void
-mpegts_parse_sync_program_pads (MpegTSParse * parse,
- GList * to_add, GList * to_remove)
+mpegts_parse_sync_program_pads (MpegTSParse * parse)
{
GList *walk;
- for (walk = to_remove; walk; walk = walk->next)
+ GST_INFO_OBJECT (parse, "begin sync pads");
+ for (walk = parse->pads_to_remove; walk; walk = walk->next)
gst_element_remove_pad (GST_ELEMENT (parse), GST_PAD (walk->data));
- for (walk = to_add; walk; walk = walk->next)
+ for (walk = parse->pads_to_add; walk; walk = walk->next)
gst_element_add_pad (GST_ELEMENT (parse), GST_PAD (walk->data));
- if (to_add)
- g_list_free (to_add);
+ if (parse->pads_to_add)
+ g_list_free (parse->pads_to_add);
+
+ if (parse->pads_to_remove)
+ g_list_free (parse->pads_to_remove);
+
+ GST_OBJECT_LOCK (parse);
+ parse->pads_to_remove = NULL;
+ parse->pads_to_add = NULL;
+ parse->need_sync_program_pads = FALSE;
+ GST_OBJECT_UNLOCK (parse);
- if (to_remove)
- g_list_free (to_remove);
+ GST_INFO_OBJECT (parse, "end sync pads");
}
@@ -493,9 +505,6 @@ static void
mpegts_parse_reset_selected_programs (MpegTSParse * parse,
gchar * program_numbers)
{
- GList *pads_to_add = NULL;
- GList *pads_to_remove = NULL;
-
GST_OBJECT_LOCK (parse);
if (parse->program_numbers)
g_free (parse->program_numbers);
@@ -526,13 +535,9 @@ mpegts_parse_reset_selected_programs (MpegTSParse * parse,
g_hash_table_foreach (parse->programs,
foreach_program_activate_or_deactivate, parse);
- pads_to_add = parse->pads_to_add;
- parse->pads_to_add = NULL;
- pads_to_remove = parse->pads_to_remove;
- parse->pads_to_remove = NULL;
+ if (parse->pads_to_remove || parse->pads_to_add)
+ parse->need_sync_program_pads = TRUE;
GST_OBJECT_UNLOCK (parse);
-
- mpegts_parse_sync_program_pads (parse, pads_to_add, pads_to_remove);
}
static void
@@ -804,6 +809,10 @@ mpegts_parse_is_psi (MpegTSParse * parse, MpegTSPacketizerPacket * packet)
if (g_hash_table_lookup (parse->psi_pids,
GINT_TO_POINTER ((gint) packet->pid)) != NULL)
retval = TRUE;
+ /* check is it is a pes pid */
+ if (g_hash_table_lookup (parse->pes_pids,
+ GINT_TO_POINTER ((gint) packet->pid)) != NULL)
+ return FALSE;
if (!retval) {
if (packet->payload_unit_start_indicator) {
table_id = *(packet->data);
@@ -850,8 +859,6 @@ mpegts_parse_apply_pat (MpegTSParse * parse, GstStructure * pat_info)
guint pid;
MpegTSParseProgram *program;
gint i;
- GList *pads_to_add = NULL;
- GList *pads_to_remove = NULL;
const GValue *programs;
gchar *dbg;
@@ -889,14 +896,12 @@ mpegts_parse_apply_pat (MpegTSParse * parse, GstStructure * pat_info)
g_hash_table_insert (parse->psi_pids,
GINT_TO_POINTER ((gint) pid), GINT_TO_POINTER (1));
}
-
- program->patcount += 1;
} else {
g_hash_table_insert (parse->psi_pids,
GINT_TO_POINTER ((gint) pid), GINT_TO_POINTER (1));
program = mpegts_parse_add_program (parse, program_number, pid);
}
-
+ program->patcount += 1;
if (program->selected && !program->active)
parse->pads_to_add = g_list_append (parse->pads_to_add,
mpegts_parse_activate_program (parse, program));
@@ -937,18 +942,15 @@ mpegts_parse_apply_pat (MpegTSParse * parse, GstStructure * pat_info)
mpegts_parse_remove_program (parse, program_number);
g_hash_table_remove (parse->psi_pids, GINT_TO_POINTER ((gint) pid));
+ mpegts_packetizer_remove_stream (parse->packetizer, pid);
}
gst_structure_free (old_pat);
}
- pads_to_add = parse->pads_to_add;
- parse->pads_to_add = NULL;
- pads_to_remove = parse->pads_to_remove;
- parse->pads_to_remove = NULL;
GST_OBJECT_UNLOCK (parse);
- mpegts_parse_sync_program_pads (parse, pads_to_add, pads_to_remove);
+ mpegts_parse_sync_program_pads (parse);
}
static void
@@ -983,10 +985,13 @@ mpegts_parse_apply_pmt (MpegTSParse * parse,
gst_structure_get_uint (stream, "pid", &pid);
gst_structure_get_uint (stream, "stream-type", &stream_type);
mpegts_parse_program_remove_stream (parse, program, (guint16) pid);
+ g_hash_table_remove (parse->pes_pids, GINT_TO_POINTER ((gint) pid));
}
/* remove pcr stream */
mpegts_parse_program_remove_stream (parse, program, program->pcr_pid);
+ g_hash_table_remove (parse->pes_pids,
+ GINT_TO_POINTER ((gint) program->pcr_pid));
gst_structure_free (program->pmt_info);
program->pmt_info = NULL;
@@ -1003,6 +1008,8 @@ mpegts_parse_apply_pmt (MpegTSParse * parse,
program->pmt_pid = pmt_pid;
program->pcr_pid = pcr_pid;
mpegts_parse_program_add_stream (parse, program, (guint16) pcr_pid, -1);
+ g_hash_table_insert (parse->pes_pids, GINT_TO_POINTER ((gint) pcr_pid),
+ GINT_TO_POINTER (1));
for (i = 0; i < gst_value_list_get_size (new_streams); ++i) {
value = gst_value_list_get_value (new_streams, i);
@@ -1012,6 +1019,9 @@ mpegts_parse_apply_pmt (MpegTSParse * parse,
gst_structure_get_uint (stream, "stream-type", &stream_type);
mpegts_parse_program_add_stream (parse, program,
(guint16) pid, (guint8) stream_type);
+ g_hash_table_insert (parse->pes_pids, GINT_TO_POINTER ((gint) pid),
+ GINT_TO_POINTER ((gint) 1));
+
}
GST_OBJECT_UNLOCK (parse);
@@ -1226,6 +1236,9 @@ mpegts_parse_chain (GstPad * pad, GstBuffer * buf)
mpegts_packetizer_clear_packet (parse->packetizer, &packet);
}
+ if (parse->need_sync_program_pads)
+ mpegts_parse_sync_program_pads (parse);
+
gst_object_unref (parse);
return res;
}
diff --git a/gst/mpegdemux/mpegtsparse.h b/gst/mpegdemux/mpegtsparse.h
index 34a78634..36466b81 100644
--- a/gst/mpegdemux/mpegtsparse.h
+++ b/gst/mpegdemux/mpegtsparse.h
@@ -60,7 +60,9 @@ struct _MpegTSParse {
GstStructure *pat;
MpegTSPacketizer *packetizer;
GHashTable *psi_pids;
+ GHashTable *pes_pids;
gboolean disposed;
+ gboolean need_sync_program_pads;
};
struct _MpegTSParseClass {