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;