From e8a6ad25462c673e7f2dd43d6b03e725bc647fc3 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Sat, 2 May 2009 18:11:06 +0200 Subject: [PATCH] asfdemux: use upstream segment and timestamps for some interpolation This should particularly help in case of upstream live src, e.g. rtspsrc, and especially so if it has to perform fallback to TCP. --- gst/asfdemux/asfpacket.c | 2 +- gst/asfdemux/gstasfdemux.c | 46 +++++++++++++++++++++++++++++++------- gst/asfdemux/gstasfdemux.h | 2 ++ 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/gst/asfdemux/asfpacket.c b/gst/asfdemux/asfpacket.c index f7972d217f..1d4bcfb4c1 100644 --- a/gst/asfdemux/asfpacket.c +++ b/gst/asfdemux/asfpacket.c @@ -191,7 +191,7 @@ gst_asf_payload_queue_for_stream (GstASFDemux * demux, AsfPayload * payload, demux->segment_ts = payload->ts; /* always note, but only determines segment when streaming */ if (demux->streaming) - gst_segment_set_seek (&demux->segment, demux->segment.rate, + gst_segment_set_seek (&demux->segment, demux->in_segment.rate, GST_FORMAT_TIME, demux->segment.flags, GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL); } diff --git a/gst/asfdemux/gstasfdemux.c b/gst/asfdemux/gstasfdemux.c index 3a92700736..10279811bd 100644 --- a/gst/asfdemux/gstasfdemux.c +++ b/gst/asfdemux/gstasfdemux.c @@ -208,6 +208,8 @@ gst_asf_demux_reset (GstASFDemux * demux) demux->activated_streams = FALSE; demux->first_ts = GST_CLOCK_TIME_NONE; demux->segment_ts = GST_CLOCK_TIME_NONE; + demux->in_gap = 0; + gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED); demux->state = GST_ASF_DEMUX_STATE_HEADER; demux->seekable = FALSE; demux->broadcast = FALSE; @@ -292,10 +294,12 @@ gst_asf_demux_sink_event (GstPad * pad, GstEvent * event) switch (GST_EVENT_TYPE (event)) { case GST_EVENT_NEWSEGMENT:{ GstFormat newsegment_format; - gint64 newsegment_start; + gint64 newsegment_start, stop, time; + gdouble rate, arate; + gboolean update; - gst_event_parse_new_segment (event, NULL, NULL, &newsegment_format, - &newsegment_start, NULL, NULL); + gst_event_parse_new_segment_full (event, &update, &rate, &arate, + &newsegment_format, &newsegment_start, &stop, &time); if (newsegment_format == GST_FORMAT_BYTES) { if (demux->packet_size && newsegment_start > demux->data_offset) @@ -307,14 +311,21 @@ gst_asf_demux_sink_event (GstPad * pad, GstEvent * event) /* do not know packet position, not really a problem */ demux->packet = -1; } else { - GST_WARNING_OBJECT (demux, "unsupported newsegment format , ignoring"); + GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring"); gst_event_unref (event); break; } + /* record upstream segment for interpolation */ + if (newsegment_format != demux->in_segment.format) + gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED); + gst_segment_set_newsegment_full (&demux->in_segment, update, rate, arate, + newsegment_format, newsegment_start, stop, time); + /* in either case, clear some state and generate newsegment later on */ GST_OBJECT_LOCK (demux); demux->segment_ts = GST_CLOCK_TIME_NONE; + demux->in_gap = GST_CLOCK_TIME_NONE; demux->need_newsegment = TRUE; gst_asf_demux_reset_stream_state_after_discont (demux); GST_OBJECT_UNLOCK (demux); @@ -1188,10 +1199,16 @@ gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force) /* wait until we had a chance to "lock on" some payload's timestamp */ if (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts)) return GST_FLOW_OK; + else { + /* safe default if insufficient upstream info */ + if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap)) + demux->in_gap = 0; + } if (demux->segment.stop == GST_CLOCK_TIME_NONE && demux->segment.duration > 0) { - demux->segment.stop = demux->segment.duration; + /* slight HACK; prevent clipping of last bit */ + demux->segment.stop = demux->segment.duration + demux->in_gap; } GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT, @@ -1240,7 +1257,11 @@ gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force) gst_buffer_set_caps (payload->buf, stream->caps); - GST_BUFFER_TIMESTAMP (payload->buf) = payload->ts; + /* (sort of) interpolate timestamps using upstream "frame of reference", + * typically useful for live src, but might (unavoidably) mess with + * position reporting if a live src is playing not so live content + * (e.g. rtspsrc taking some time to fall back to tcp) */ + GST_BUFFER_TIMESTAMP (payload->buf) = payload->ts + demux->in_gap; GST_BUFFER_DURATION (payload->buf) = payload->duration; /* FIXME: we should really set durations on buffers if we can */ @@ -1398,12 +1419,21 @@ gst_asf_demux_chain (GstPad * pad, GstBuffer * buf) demux = GST_ASF_DEMUX (GST_PAD_PARENT (pad)); - GST_LOG_OBJECT (demux, "buffer: size=%u, offset=%" G_GINT64_FORMAT, - GST_BUFFER_SIZE (buf), GST_BUFFER_OFFSET (buf)); + GST_LOG_OBJECT (demux, "buffer: size=%u, offset=%" G_GINT64_FORMAT ", time=%" + GST_TIME_FORMAT, GST_BUFFER_SIZE (buf), GST_BUFFER_OFFSET (buf), + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); if (GST_BUFFER_IS_DISCONT (buf)) gst_asf_demux_reset_stream_state_after_discont (demux); + if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap) && + GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { + demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start; + GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT + ", interpolation gap: %" GST_TIME_FORMAT, + GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap)); + } + gst_adapter_push (demux->adapter, buf); switch (demux->state) { diff --git a/gst/asfdemux/gstasfdemux.h b/gst/asfdemux/gstasfdemux.h index 86a3cfbb9c..f6b7fbcd74 100644 --- a/gst/asfdemux/gstasfdemux.h +++ b/gst/asfdemux/gstasfdemux.h @@ -170,6 +170,8 @@ struct _GstASFDemux { gboolean need_newsegment; /* do we need to send a new-segment event? */ GstClockTime segment_ts; /* streaming; timestamp for segment start */ + GstSegment in_segment; /* streaming; upstream segment info */ + GstClockTime in_gap; /* streaming; upstream initial segment gap for interpolation */ gboolean segment_running; /* if we've started the current segment */ gboolean streaming; /* TRUE if we are operating chain-based */ GstClockTime latency;