mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-03 04:52:28 +00:00
mpegtsdemux: Add initial naive seeking support and fix duration query.
Sync from gst-fluendo-mpegdemux and have seeking/duration query improvements in. No support however for wrapped around pcrs etc. but a start nonetheless. Also fix indentation issues.
This commit is contained in:
parent
e8504019d8
commit
ff7b54e7da
2 changed files with 340 additions and 116 deletions
|
@ -34,9 +34,9 @@
|
||||||
*
|
*
|
||||||
* The Original Code is Fluendo MPEG Demuxer plugin.
|
* The Original Code is Fluendo MPEG Demuxer plugin.
|
||||||
*
|
*
|
||||||
* The Initial Developer of the Original Code is Fluendo, S.L.
|
* The Initial Developer of the Original Code is Fluendo, S.A.
|
||||||
* Portions created by Fluendo, S.L. are Copyright (C) 2005
|
* Portions created by Fluendo, S.L. are Copyright (C) 2005,2006,2007,2008,2009
|
||||||
* Fluendo, S.L. All Rights Reserved.
|
* Fluendo, S.A. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* Contributor(s): Wim Taymans <wim@fluendo.com>
|
* Contributor(s): Wim Taymans <wim@fluendo.com>
|
||||||
*/
|
*/
|
||||||
|
@ -126,6 +126,13 @@ enum
|
||||||
PROP_M2TS
|
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 \
|
#define VIDEO_CAPS \
|
||||||
GST_STATIC_CAPS (\
|
GST_STATIC_CAPS (\
|
||||||
"video/mpeg, " \
|
"video/mpeg, " \
|
||||||
|
@ -189,6 +196,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_is_PMT (GstMpegTSDemux * demux, guint16 PID);
|
||||||
|
|
||||||
static gboolean gst_mpegts_demux_sink_event (GstPad * pad, GstEvent * event);
|
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 GstFlowReturn gst_mpegts_demux_chain (GstPad * pad, GstBuffer * buffer);
|
||||||
static gboolean gst_mpegts_demux_sink_setcaps (GstPad * pad, GstCaps * caps);
|
static gboolean gst_mpegts_demux_sink_setcaps (GstPad * pad, GstCaps * caps);
|
||||||
|
|
||||||
|
@ -327,7 +335,12 @@ gst_mpegts_demux_init (GstMpegTSDemux * demux)
|
||||||
demux->m2ts_mode = FALSE;
|
demux->m2ts_mode = FALSE;
|
||||||
demux->sync_lut = NULL;
|
demux->sync_lut = NULL;
|
||||||
demux->sync_lut_len = 0;
|
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
|
#ifdef USE_LIBOIL
|
||||||
oil_init ();
|
oil_init ();
|
||||||
#endif
|
#endif
|
||||||
|
@ -668,6 +681,8 @@ gst_mpegts_demux_fill_stream (GstMpegTSStream * stream, guint8 id,
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
gst_pad_set_query_function (stream->pad,
|
gst_pad_set_query_function (stream->pad,
|
||||||
GST_DEBUG_FUNCPTR (gst_mpegts_demux_src_pad_query));
|
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);
|
g_free (name);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -730,7 +745,7 @@ gst_mpegts_demux_send_new_segment (GstMpegTSDemux * demux,
|
||||||
}
|
}
|
||||||
base_PCR = PCR_stream->base_PCR;
|
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: %"
|
GST_DEBUG_OBJECT (demux, "segment PTS to (%" G_GUINT64_FORMAT ") time: %"
|
||||||
G_GUINT64_FORMAT, base_PCR, time);
|
G_GUINT64_FORMAT, base_PCR, time);
|
||||||
|
@ -1680,7 +1695,13 @@ gst_mpegts_demux_parse_adaptation_field (GstMpegTSStream * stream,
|
||||||
"valid pcr: %d last PCR difference: %" G_GUINT64_FORMAT, valid_pcr,
|
"valid pcr: %d last PCR difference: %" G_GUINT64_FORMAT, valid_pcr,
|
||||||
stream->last_PCR_difference);
|
stream->last_PCR_difference);
|
||||||
if (valid_pcr) {
|
if (valid_pcr) {
|
||||||
|
if (demux->pcr[0] == -1) {
|
||||||
|
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)) {
|
||||||
|
demux->pcr[1] = pcr;
|
||||||
|
}
|
||||||
stream->last_PCR = pcr;
|
stream->last_PCR = pcr;
|
||||||
|
|
||||||
if (demux->clock && demux->clock_base != GST_CLOCK_TIME_NONE) {
|
if (demux->clock && demux->clock_base != GST_CLOCK_TIME_NONE) {
|
||||||
|
@ -1955,15 +1976,20 @@ gst_mpegts_demux_is_PMT (GstMpegTSDemux * demux, guint16 PID)
|
||||||
}
|
}
|
||||||
|
|
||||||
static FORCE_INLINE GstFlowReturn
|
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;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
|
|
||||||
if (stream->pes_buffer) {
|
if (stream->pes_buffer) {
|
||||||
GST_BUFFER_SIZE (stream->pes_buffer) = stream->pes_buffer_used;
|
if (discard) {
|
||||||
ret = gst_pes_filter_push (&stream->filter, stream->pes_buffer);
|
gst_buffer_unref (stream->pes_buffer);
|
||||||
if (ret == GST_FLOW_LOST_SYNC)
|
|
||||||
stream->pes_buffer_in_sync = FALSE;
|
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;
|
stream->pes_buffer = NULL;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1985,7 +2011,7 @@ gst_mpegts_stream_pes_buffer_push (GstMpegTSStream * stream,
|
||||||
if (stream->pes_buffer_size < (MPEGTS_MAX_PES_BUFFER_SIZE >> 1))
|
if (stream->pes_buffer_size < (MPEGTS_MAX_PES_BUFFER_SIZE >> 1))
|
||||||
stream->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)
|
if (ret == GST_FLOW_LOST_SYNC)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -2010,7 +2036,7 @@ done:
|
||||||
}
|
}
|
||||||
|
|
||||||
static FORCE_INLINE GstFlowReturn
|
static FORCE_INLINE GstFlowReturn
|
||||||
gst_mpegts_demux_pes_buffer_flush (GstMpegTSDemux * demux)
|
gst_mpegts_demux_pes_buffer_flush (GstMpegTSDemux * demux, gboolean discard)
|
||||||
{
|
{
|
||||||
gint i;
|
gint i;
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
|
@ -2018,7 +2044,7 @@ gst_mpegts_demux_pes_buffer_flush (GstMpegTSDemux * demux)
|
||||||
for (i = 0; i < MPEGTS_MAX_PID + 1; i++) {
|
for (i = 0; i < MPEGTS_MAX_PID + 1; i++) {
|
||||||
GstMpegTSStream *stream = demux->streams[i];
|
GstMpegTSStream *stream = demux->streams[i];
|
||||||
if (stream && stream->pad) {
|
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;
|
stream->pes_buffer_in_sync = FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2233,7 +2259,7 @@ gst_mpegts_demux_parse_stream (GstMpegTSDemux * demux, GstMpegTSStream * stream,
|
||||||
"bytes of %u bytes in the PES buffer",
|
"bytes of %u bytes in the PES buffer",
|
||||||
PID, stream->pes_buffer_used, stream->pes_buffer_size);
|
PID, stream->pes_buffer_used, stream->pes_buffer_size);
|
||||||
/* Flush buffered PES data */
|
/* 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);
|
gst_pes_filter_drain (&stream->filter);
|
||||||
/* Resize the buffer to half if no overflow detected and
|
/* Resize the buffer to half if no overflow detected and
|
||||||
* had been used less than half of it */
|
* had been used less than half of it */
|
||||||
|
@ -2319,11 +2345,137 @@ gst_mpegts_demux_parse_transport_packet (GstMpegTSDemux * demux,
|
||||||
ret = gst_mpegts_demux_parse_stream (demux, stream, data,
|
ret = gst_mpegts_demux_parse_stream (demux, stream, data,
|
||||||
MPEGTS_NORMAL_TS_PACKETSIZE - 1);
|
MPEGTS_NORMAL_TS_PACKETSIZE - 1);
|
||||||
|
|
||||||
|
if (demux->pcr[1] != -1 && demux->bitrate == -1) {
|
||||||
|
GST_DEBUG_OBJECT (demux, "stream->last_PCR_difference: %" G_GINT64_FORMAT
|
||||||
|
", demux->num_packets %" G_GUINT64_FORMAT,
|
||||||
|
demux->pcr[1] - demux->pcr[0], demux->num_packets);
|
||||||
|
demux->bitrate = gst_util_uint64_scale (GST_SECOND,
|
||||||
|
MPEGTS_NORMAL_TS_PACKETSIZE * demux->num_packets,
|
||||||
|
MPEGTIME_TO_GSTTIME (demux->pcr[1] - demux->pcr[0]));
|
||||||
|
GST_DEBUG_OBJECT (demux, "bitrate is %" G_GINT64_FORMAT
|
||||||
|
" bytes per second", demux->bitrate);
|
||||||
|
}
|
||||||
|
demux->num_packets++;
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* ERRORS */
|
/* 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
|
static gboolean
|
||||||
gst_mpegts_demux_send_event (GstMpegTSDemux * demux, GstEvent * event)
|
gst_mpegts_demux_send_event (GstMpegTSDemux * demux, GstEvent * event)
|
||||||
{
|
{
|
||||||
|
@ -2347,7 +2499,7 @@ static gboolean
|
||||||
gst_mpegts_demux_sink_event (GstPad * pad, GstEvent * event)
|
gst_mpegts_demux_sink_event (GstPad * pad, GstEvent * event)
|
||||||
{
|
{
|
||||||
GstMpegTSDemux *demux = GST_MPEGTS_DEMUX (gst_pad_get_parent (pad));
|
GstMpegTSDemux *demux = GST_MPEGTS_DEMUX (gst_pad_get_parent (pad));
|
||||||
gboolean res;
|
gboolean res = FALSE;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (demux, "got event %s",
|
GST_DEBUG_OBJECT (demux, "got event %s",
|
||||||
gst_event_type_get_name (GST_EVENT_TYPE (event)));
|
gst_event_type_get_name (GST_EVENT_TYPE (event)));
|
||||||
|
@ -2358,11 +2510,11 @@ gst_mpegts_demux_sink_event (GstPad * pad, GstEvent * event)
|
||||||
break;
|
break;
|
||||||
case GST_EVENT_FLUSH_STOP:
|
case GST_EVENT_FLUSH_STOP:
|
||||||
gst_adapter_clear (demux->adapter);
|
gst_adapter_clear (demux->adapter);
|
||||||
|
gst_mpegts_demux_flush (demux, TRUE);
|
||||||
res = gst_mpegts_demux_send_event (demux, event);
|
res = gst_mpegts_demux_send_event (demux, event);
|
||||||
break;
|
break;
|
||||||
case GST_EVENT_EOS:
|
case GST_EVENT_EOS:
|
||||||
/* Flush buffered PES data */
|
gst_mpegts_demux_flush (demux, FALSE);
|
||||||
gst_mpegts_demux_pes_buffer_flush (demux);
|
|
||||||
/* Send the EOS event on each stream */
|
/* Send the EOS event on each stream */
|
||||||
if (!(res = gst_mpegts_demux_send_event (demux, event))) {
|
if (!(res = gst_mpegts_demux_send_event (demux, event))) {
|
||||||
/* we have no streams */
|
/* we have no streams */
|
||||||
|
@ -2371,15 +2523,46 @@ gst_mpegts_demux_sink_event (GstPad * pad, GstEvent * event)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GST_EVENT_NEWSEGMENT:
|
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;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
res = gst_mpegts_demux_send_event (demux, event);
|
res = gst_mpegts_demux_send_event (demux, event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
gst_object_unref (demux);
|
gst_object_unref (demux);
|
||||||
|
|
||||||
return TRUE;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -2455,21 +2638,54 @@ gst_mpegts_demux_src_pad_query (GstPad * pad, GstQuery * query)
|
||||||
case GST_QUERY_DURATION:
|
case GST_QUERY_DURATION:
|
||||||
{
|
{
|
||||||
GstFormat format;
|
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) {
|
/* Try query upstream first */
|
||||||
res = FALSE;
|
peer = gst_pad_get_peer (demux->sinkpad);
|
||||||
} else {
|
if (peer) {
|
||||||
res = gst_pad_query_default (pad, query);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
res = gst_pad_query_default (pad, query);
|
res = gst_pad_query_default (pad, query);
|
||||||
}
|
}
|
||||||
|
gst_object_unref (demux);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -2554,9 +2770,7 @@ gst_mpegts_demux_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
guint sync_count;
|
guint sync_count;
|
||||||
|
|
||||||
if (GST_BUFFER_IS_DISCONT (buffer)) {
|
if (GST_BUFFER_IS_DISCONT (buffer)) {
|
||||||
/* Flush buffered PES data */
|
gst_mpegts_demux_flush (demux, FALSE);
|
||||||
gst_mpegts_demux_pes_buffer_flush (demux);
|
|
||||||
gst_adapter_clear (demux->adapter);
|
|
||||||
}
|
}
|
||||||
/* first push the new buffer into the adapter */
|
/* first push the new buffer into the adapter */
|
||||||
gst_adapter_push (demux->adapter, buffer);
|
gst_adapter_push (demux->adapter, buffer);
|
||||||
|
|
|
@ -34,9 +34,9 @@
|
||||||
*
|
*
|
||||||
* The Original Code is Fluendo MPEG Demuxer plugin.
|
* The Original Code is Fluendo MPEG Demuxer plugin.
|
||||||
*
|
*
|
||||||
* The Initial Developer of the Original Code is Fluendo, S.L.
|
* The Initial Developer of the Original Code is Fluendo, S.A.
|
||||||
* Portions created by Fluendo, S.L. are Copyright (C) 2005
|
* Portions created by Fluendo, S.A. are Copyright (C) 2005,2006,2007,2008,2009
|
||||||
* Fluendo, S.L. All Rights Reserved.
|
* Fluendo, S.A. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* Contributor(s): Wim Taymans <wim@fluendo.com>
|
* Contributor(s): Wim Taymans <wim@fluendo.com>
|
||||||
*/
|
*/
|
||||||
|
@ -52,18 +52,14 @@
|
||||||
#include "gstsectionfilter.h"
|
#include "gstsectionfilter.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
#define MPEGTS_MIN_PES_BUFFER_SIZE 4 * 1024
|
#define MPEGTS_MIN_PES_BUFFER_SIZE 4 * 1024
|
||||||
#define MPEGTS_MAX_PES_BUFFER_SIZE 256 * 1024
|
#define MPEGTS_MAX_PES_BUFFER_SIZE 256 * 1024
|
||||||
|
|
||||||
#define MPEGTS_MAX_PID 0x1fff
|
#define MPEGTS_MAX_PID 0x1fff
|
||||||
#define MPEGTS_NORMAL_TS_PACKETSIZE 188
|
#define MPEGTS_NORMAL_TS_PACKETSIZE 188
|
||||||
#define MPEGTS_M2TS_TS_PACKETSIZE 192
|
#define MPEGTS_M2TS_TS_PACKETSIZE 192
|
||||||
|
|
||||||
#define IS_MPEGTS_SYNC(data) (((data)[0] == 0x47) && \
|
#define IS_MPEGTS_SYNC(data) (((data)[0] == 0x47) && \
|
||||||
(((data)[1] & 0x80) == 0x00) && \
|
(((data)[1] & 0x80) == 0x00) && \
|
||||||
(((data)[3] & 0x10) == 0x10))
|
(((data)[3] & 0x10) == 0x10))
|
||||||
|
|
||||||
#define GST_TYPE_MPEGTS_DEMUX (gst_mpegts_demux_get_type())
|
#define GST_TYPE_MPEGTS_DEMUX (gst_mpegts_demux_get_type())
|
||||||
#define GST_MPEGTS_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
#define GST_MPEGTS_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||||
GST_TYPE_MPEGTS_DEMUX,GstMpegTSDemux))
|
GST_TYPE_MPEGTS_DEMUX,GstMpegTSDemux))
|
||||||
|
@ -75,7 +71,6 @@ G_BEGIN_DECLS
|
||||||
GST_TYPE_MPEGTS_DEMUX))
|
GST_TYPE_MPEGTS_DEMUX))
|
||||||
#define GST_IS_MPEGTS_DEMUX_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),\
|
#define GST_IS_MPEGTS_DEMUX_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),\
|
||||||
GST_TYPE_MPEGTS_DEMUX))
|
GST_TYPE_MPEGTS_DEMUX))
|
||||||
|
|
||||||
typedef struct _GstMpegTSStream GstMpegTSStream;
|
typedef struct _GstMpegTSStream GstMpegTSStream;
|
||||||
typedef struct _GstMpegTSPMTEntry GstMpegTSPMTEntry;
|
typedef struct _GstMpegTSPMTEntry GstMpegTSPMTEntry;
|
||||||
typedef struct _GstMpegTSPMT GstMpegTSPMT;
|
typedef struct _GstMpegTSPMT GstMpegTSPMT;
|
||||||
|
@ -84,142 +79,157 @@ typedef struct _GstMpegTSPAT GstMpegTSPAT;
|
||||||
typedef struct _GstMpegTSDemux GstMpegTSDemux;
|
typedef struct _GstMpegTSDemux GstMpegTSDemux;
|
||||||
typedef struct _GstMpegTSDemuxClass GstMpegTSDemuxClass;
|
typedef struct _GstMpegTSDemuxClass GstMpegTSDemuxClass;
|
||||||
|
|
||||||
struct _GstMpegTSPMTEntry {
|
struct _GstMpegTSPMTEntry
|
||||||
guint16 PID;
|
{
|
||||||
|
guint16 PID;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstMpegTSPMT {
|
struct _GstMpegTSPMT
|
||||||
guint16 program_number;
|
{
|
||||||
guint8 version_number;
|
guint16 program_number;
|
||||||
gboolean current_next_indicator;
|
guint8 version_number;
|
||||||
guint8 section_number;
|
gboolean current_next_indicator;
|
||||||
guint8 last_section_number;
|
guint8 section_number;
|
||||||
guint16 PCR_PID;
|
guint8 last_section_number;
|
||||||
guint16 program_info_length;
|
guint16 PCR_PID;
|
||||||
GstMPEGDescriptor * program_info;
|
guint16 program_info_length;
|
||||||
|
GstMPEGDescriptor *program_info;
|
||||||
|
|
||||||
GArray * entries;
|
GArray *entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstMpegTSPATEntry {
|
struct _GstMpegTSPATEntry
|
||||||
guint16 program_number;
|
{
|
||||||
guint16 PID;
|
guint16 program_number;
|
||||||
|
guint16 PID;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstMpegTSPAT {
|
struct _GstMpegTSPAT
|
||||||
guint16 transport_stream_id;
|
{
|
||||||
guint8 version_number;
|
guint16 transport_stream_id;
|
||||||
gboolean current_next_indicator;
|
guint8 version_number;
|
||||||
guint8 section_number;
|
gboolean current_next_indicator;
|
||||||
guint8 last_section_number;
|
guint8 section_number;
|
||||||
|
guint8 last_section_number;
|
||||||
|
|
||||||
GArray * entries;
|
GArray *entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum _MpegTsStreamFlags {
|
typedef enum _MpegTsStreamFlags
|
||||||
|
{
|
||||||
MPEGTS_STREAM_FLAG_STREAM_TYPE_UNKNOWN = 0x01,
|
MPEGTS_STREAM_FLAG_STREAM_TYPE_UNKNOWN = 0x01,
|
||||||
MPEGTS_STREAM_FLAG_PMT_VALID = 0x02,
|
MPEGTS_STREAM_FLAG_PMT_VALID = 0x02,
|
||||||
MPEGTS_STREAM_FLAG_IS_VIDEO = 0x04
|
MPEGTS_STREAM_FLAG_IS_VIDEO = 0x04
|
||||||
} MpegTsStreamFlags;
|
} MpegTsStreamFlags;
|
||||||
|
|
||||||
/* Information associated to a single MPEG stream. */
|
/* Information associated to a single MPEG stream. */
|
||||||
struct _GstMpegTSStream {
|
struct _GstMpegTSStream
|
||||||
GstMpegTSDemux * demux;
|
{
|
||||||
|
GstMpegTSDemux *demux;
|
||||||
|
|
||||||
MpegTsStreamFlags flags;
|
MpegTsStreamFlags flags;
|
||||||
|
|
||||||
/* PID and type */
|
/* PID and type */
|
||||||
guint16 PID;
|
guint16 PID;
|
||||||
guint8 PID_type;
|
guint8 PID_type;
|
||||||
|
|
||||||
/* adaptation_field data */
|
/* adaptation_field data */
|
||||||
guint64 last_PCR;
|
guint64 last_PCR;
|
||||||
guint64 base_PCR;
|
guint64 base_PCR;
|
||||||
guint64 last_OPCR;
|
guint64 last_OPCR;
|
||||||
guint64 last_PCR_difference;
|
guint64 last_PCR_difference;
|
||||||
gboolean discont_PCR;
|
gboolean discont_PCR;
|
||||||
GstClockTimeDiff discont_difference;
|
GstClockTimeDiff discont_difference;
|
||||||
|
|
||||||
/* for PAT streams */
|
/* for PAT streams */
|
||||||
GstMpegTSPAT PAT;
|
GstMpegTSPAT PAT;
|
||||||
|
|
||||||
/* for PMT streams */
|
/* for PMT streams */
|
||||||
GstMpegTSPMT PMT;
|
GstMpegTSPMT PMT;
|
||||||
|
|
||||||
/* for CA streams */
|
/* for CA streams */
|
||||||
|
|
||||||
/* for PAT, PMT, CA and private streams */
|
/* for PAT, PMT, CA and private streams */
|
||||||
GstSectionFilter section_filter;
|
GstSectionFilter section_filter;
|
||||||
|
|
||||||
/* for PES streams */
|
/* for PES streams */
|
||||||
guint8 id;
|
guint8 id;
|
||||||
guint8 stream_type;
|
guint8 stream_type;
|
||||||
GstBuffer * pes_buffer;
|
GstBuffer *pes_buffer;
|
||||||
guint32 pes_buffer_size;
|
guint32 pes_buffer_size;
|
||||||
guint32 pes_buffer_used;
|
guint32 pes_buffer_used;
|
||||||
gboolean pes_buffer_overflow;
|
gboolean pes_buffer_overflow;
|
||||||
gboolean pes_buffer_in_sync;
|
gboolean pes_buffer_in_sync;
|
||||||
GstPESFilter filter;
|
GstPESFilter filter;
|
||||||
GstPad * pad;
|
GstPad *pad;
|
||||||
GstFlowReturn last_ret;
|
GstFlowReturn last_ret;
|
||||||
GstMPEGDescriptor *ES_info;
|
GstMPEGDescriptor *ES_info;
|
||||||
/* needed because 33bit mpeg timestamps wrap around every (approx) 26.5 hrs */
|
/* needed because 33bit mpeg timestamps wrap around every (approx) 26.5 hrs */
|
||||||
GstClockTimeDiff base_time;
|
GstClockTimeDiff base_time;
|
||||||
GstClockTime last_time;
|
GstClockTime last_time;
|
||||||
/* pid of PMT that this stream belongs to */
|
/* pid of PMT that this stream belongs to */
|
||||||
guint16 PMT_pid;
|
guint16 PMT_pid;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstMpegTSDemux {
|
struct _GstMpegTSDemux
|
||||||
GstElement parent;
|
{
|
||||||
|
GstElement parent;
|
||||||
|
|
||||||
/* properties */
|
/* properties */
|
||||||
gboolean check_crc;
|
gboolean check_crc;
|
||||||
|
|
||||||
/* sink pad and adapter */
|
/* sink pad and adapter */
|
||||||
GstPad * sinkpad;
|
GstPad *sinkpad;
|
||||||
GstAdapter * adapter;
|
GstAdapter *adapter;
|
||||||
guint8 ** sync_lut;
|
guint8 **sync_lut;
|
||||||
guint sync_lut_len;
|
guint sync_lut_len;
|
||||||
|
|
||||||
/* current PMT PID */
|
/* current PMT PID */
|
||||||
guint16 current_PMT;
|
guint16 current_PMT;
|
||||||
|
|
||||||
/* Array of MPEGTS_MAX_PID + 1 stream entries */
|
/* Array of MPEGTS_MAX_PID + 1 stream entries */
|
||||||
GstMpegTSStream ** streams;
|
GstMpegTSStream **streams;
|
||||||
/* Array to perform pmts checks at gst_mpegts_demux_parse_adaptation_field */
|
/* Array to perform pmts checks at gst_mpegts_demux_parse_adaptation_field */
|
||||||
gboolean pmts_checked[MPEGTS_MAX_PID + 1];
|
gboolean pmts_checked[MPEGTS_MAX_PID + 1];
|
||||||
|
|
||||||
/* Array of Elementary Stream pids for ts with PMT */
|
/* Array of Elementary Stream pids for ts with PMT */
|
||||||
guint16 * elementary_pids;
|
guint16 *elementary_pids;
|
||||||
guint nb_elementary_pids;
|
guint nb_elementary_pids;
|
||||||
|
|
||||||
/* Program number to use */
|
/* Program number to use */
|
||||||
gint program_number;
|
gint program_number;
|
||||||
|
|
||||||
/* indicates that we need to close our pad group, because we've added
|
/* indicates that we need to close our pad group, because we've added
|
||||||
* at least one pad */
|
* at least one pad */
|
||||||
gboolean need_no_more_pads;
|
gboolean need_no_more_pads;
|
||||||
guint16 packetsize;
|
guint16 packetsize;
|
||||||
gboolean m2ts_mode;
|
gboolean m2ts_mode;
|
||||||
/* clocking */
|
/* clocking */
|
||||||
GstClock * clock;
|
GstClock *clock;
|
||||||
GstClockTime clock_base;
|
GstClockTime clock_base;
|
||||||
|
/* Additional information required for seeking */
|
||||||
|
guint64 num_packets;
|
||||||
|
gint64 bitrate;
|
||||||
|
/* Two PCRs observations to calculate bitrate */
|
||||||
|
gint64 pcr[2];
|
||||||
|
GstClockTime cache_duration;
|
||||||
|
/* Cached base_PCR in GStreamer time. */
|
||||||
|
GstClockTime base_pts;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstMpegTSDemuxClass {
|
struct _GstMpegTSDemuxClass
|
||||||
GstElementClass parent_class;
|
{
|
||||||
|
GstElementClass parent_class;
|
||||||
|
|
||||||
GstPadTemplate * sink_template;
|
GstPadTemplate *sink_template;
|
||||||
GstPadTemplate * video_template;
|
GstPadTemplate *video_template;
|
||||||
GstPadTemplate * audio_template;
|
GstPadTemplate *audio_template;
|
||||||
GstPadTemplate * private_template;
|
GstPadTemplate *private_template;
|
||||||
};
|
};
|
||||||
|
|
||||||
GType gst_mpegts_demux_get_type (void);
|
GType gst_mpegts_demux_get_type (void);
|
||||||
|
|
||||||
gboolean gst_mpegts_demux_plugin_init (GstPlugin *plugin);
|
gboolean gst_mpegts_demux_plugin_init (GstPlugin * plugin);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __GST_MPEGTS_DEMUX_H__ */
|
#endif /* __GST_MPEGTS_DEMUX_H__ */
|
||||||
|
|
Loading…
Reference in a new issue