mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-07 07:58:51 +00:00
adaptivedemux: fix seeking that just updates stop position
Fixed adaptivedemux seeking without flushing that just wants to update stop position. This required protecting the segment variables with a new mutex so that the seeking thread and the download threads could safely manipulate the segment and events related to it. This contention is only locked/unlocked when starting a new download, when the first fragment of a segment is received and when seeking so, hopefully, it won't damage performance.
This commit is contained in:
parent
eaace4922c
commit
16a2f7f5c0
1 changed files with 57 additions and 9 deletions
|
@ -144,6 +144,10 @@ GST_DEBUG_CATEGORY (adaptivedemux_debug);
|
||||||
#define GST_API_LOCK(d) g_mutex_lock (GST_API_GET_LOCK (d));
|
#define GST_API_LOCK(d) g_mutex_lock (GST_API_GET_LOCK (d));
|
||||||
#define GST_API_UNLOCK(d) g_mutex_unlock (GST_API_GET_LOCK (d));
|
#define GST_API_UNLOCK(d) g_mutex_unlock (GST_API_GET_LOCK (d));
|
||||||
|
|
||||||
|
#define GST_ADAPTIVE_DEMUX_SEGMENT_GET_LOCK(d) (&GST_ADAPTIVE_DEMUX_CAST(d)->priv->segment_lock)
|
||||||
|
#define GST_ADAPTIVE_DEMUX_SEGMENT_LOCK(d) g_mutex_lock (GST_ADAPTIVE_DEMUX_SEGMENT_GET_LOCK (d))
|
||||||
|
#define GST_ADAPTIVE_DEMUX_SEGMENT_UNLOCK(d) g_mutex_unlock (GST_ADAPTIVE_DEMUX_SEGMENT_GET_LOCK (d))
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PROP_0,
|
PROP_0,
|
||||||
|
@ -188,6 +192,12 @@ struct _GstAdaptiveDemuxPrivate
|
||||||
GMutex manifest_update_lock;
|
GMutex manifest_update_lock;
|
||||||
|
|
||||||
GMutex api_lock;
|
GMutex api_lock;
|
||||||
|
|
||||||
|
/* Protects demux and stream segment information
|
||||||
|
* Needed because seeks can update segment information
|
||||||
|
* without needing to stop tasks when they just want to
|
||||||
|
* update the segment boundaries */
|
||||||
|
GMutex segment_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
static GstBinClass *parent_class = NULL;
|
static GstBinClass *parent_class = NULL;
|
||||||
|
@ -415,6 +425,7 @@ gst_adaptive_demux_init (GstAdaptiveDemux * demux,
|
||||||
|
|
||||||
g_rec_mutex_init (&demux->priv->manifest_lock);
|
g_rec_mutex_init (&demux->priv->manifest_lock);
|
||||||
g_mutex_init (&demux->priv->api_lock);
|
g_mutex_init (&demux->priv->api_lock);
|
||||||
|
g_mutex_init (&demux->priv->segment_lock);
|
||||||
|
|
||||||
pad_template =
|
pad_template =
|
||||||
gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "sink");
|
gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "sink");
|
||||||
|
@ -452,6 +463,7 @@ gst_adaptive_demux_finalize (GObject * object)
|
||||||
g_rec_mutex_clear (&priv->updates_lock);
|
g_rec_mutex_clear (&priv->updates_lock);
|
||||||
g_rec_mutex_clear (&demux->priv->manifest_lock);
|
g_rec_mutex_clear (&demux->priv->manifest_lock);
|
||||||
g_mutex_clear (&demux->priv->api_lock);
|
g_mutex_clear (&demux->priv->api_lock);
|
||||||
|
g_mutex_clear (&demux->priv->segment_lock);
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
@ -1247,9 +1259,6 @@ gst_adaptive_demux_src_event (GstPad * pad, GstObject * parent,
|
||||||
/* have a backup in case seek fails */
|
/* have a backup in case seek fails */
|
||||||
gst_segment_copy_into (&demux->segment, &oldsegment);
|
gst_segment_copy_into (&demux->segment, &oldsegment);
|
||||||
|
|
||||||
gst_segment_do_seek (&demux->segment, rate, format, flags, start_type,
|
|
||||||
start, stop_type, stop, &update);
|
|
||||||
|
|
||||||
if (flags & GST_SEEK_FLAG_FLUSH) {
|
if (flags & GST_SEEK_FLAG_FLUSH) {
|
||||||
GstEvent *fevent;
|
GstEvent *fevent;
|
||||||
|
|
||||||
|
@ -1257,8 +1266,27 @@ gst_adaptive_demux_src_event (GstPad * pad, GstObject * parent,
|
||||||
fevent = gst_event_new_flush_start ();
|
fevent = gst_event_new_flush_start ();
|
||||||
gst_event_set_seqnum (fevent, seqnum);
|
gst_event_set_seqnum (fevent, seqnum);
|
||||||
gst_adaptive_demux_push_src_event (demux, fevent);
|
gst_adaptive_demux_push_src_event (demux, fevent);
|
||||||
|
|
||||||
|
gst_adaptive_demux_stop_tasks (demux);
|
||||||
|
} else if ((rate > 0 && start_type != GST_SEEK_TYPE_NONE) ||
|
||||||
|
(rate < 0 && stop_type != GST_SEEK_TYPE_NONE)) {
|
||||||
|
|
||||||
|
gst_adaptive_demux_stop_tasks (demux);
|
||||||
}
|
}
|
||||||
gst_adaptive_demux_stop_tasks (demux);
|
|
||||||
|
GST_ADAPTIVE_DEMUX_SEGMENT_LOCK (demux);
|
||||||
|
gst_segment_do_seek (&demux->segment, rate, format, flags, start_type,
|
||||||
|
start, stop_type, stop, &update);
|
||||||
|
|
||||||
|
/* FIXME - this seems unatural, do_seek() is updating base when we
|
||||||
|
* only want the start/stop position to change, maybe do_seek() needs
|
||||||
|
* some fixing? */
|
||||||
|
if (!(flags & GST_SEEK_FLAG_FLUSH) && ((rate > 0
|
||||||
|
&& start_type == GST_SEEK_TYPE_NONE) || (rate < 0
|
||||||
|
&& stop_type == GST_SEEK_TYPE_NONE))) {
|
||||||
|
demux->segment.base = oldsegment.base;
|
||||||
|
}
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (demux, "Seeking to segment %" GST_SEGMENT_FORMAT,
|
GST_DEBUG_OBJECT (demux, "Seeking to segment %" GST_SEGMENT_FORMAT,
|
||||||
&demux->segment);
|
&demux->segment);
|
||||||
|
|
||||||
|
@ -1270,6 +1298,7 @@ gst_adaptive_demux_src_event (GstPad * pad, GstObject * parent,
|
||||||
} else {
|
} else {
|
||||||
demux->priv->segment_seqnum = seqnum;
|
demux->priv->segment_seqnum = seqnum;
|
||||||
}
|
}
|
||||||
|
GST_ADAPTIVE_DEMUX_SEGMENT_UNLOCK (demux);
|
||||||
|
|
||||||
if (flags & GST_SEEK_FLAG_FLUSH) {
|
if (flags & GST_SEEK_FLAG_FLUSH) {
|
||||||
GstEvent *fevent;
|
GstEvent *fevent;
|
||||||
|
@ -1287,6 +1316,7 @@ gst_adaptive_demux_src_event (GstPad * pad, GstObject * parent,
|
||||||
GstClockTime period_start =
|
GstClockTime period_start =
|
||||||
gst_adaptive_demux_get_period_start_time (demux);
|
gst_adaptive_demux_get_period_start_time (demux);
|
||||||
|
|
||||||
|
GST_ADAPTIVE_DEMUX_SEGMENT_LOCK (demux);
|
||||||
for (iter = demux->streams; iter; iter = g_list_next (iter)) {
|
for (iter = demux->streams; iter; iter = g_list_next (iter)) {
|
||||||
GstAdaptiveDemuxStream *stream = iter->data;
|
GstAdaptiveDemuxStream *stream = iter->data;
|
||||||
GstEvent *seg_evt;
|
GstEvent *seg_evt;
|
||||||
|
@ -1307,6 +1337,8 @@ gst_adaptive_demux_src_event (GstPad * pad, GstObject * parent,
|
||||||
gst_event_replace (&stream->pending_segment, seg_evt);
|
gst_event_replace (&stream->pending_segment, seg_evt);
|
||||||
gst_event_unref (seg_evt);
|
gst_event_unref (seg_evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GST_ADAPTIVE_DEMUX_SEGMENT_UNLOCK (demux);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restart the demux */
|
/* Restart the demux */
|
||||||
|
@ -1675,6 +1707,7 @@ gst_adaptive_demux_stream_push_buffer (GstAdaptiveDemuxStream * stream,
|
||||||
GstClockTime period_start =
|
GstClockTime period_start =
|
||||||
gst_adaptive_demux_get_period_start_time (demux);
|
gst_adaptive_demux_get_period_start_time (demux);
|
||||||
|
|
||||||
|
GST_ADAPTIVE_DEMUX_SEGMENT_LOCK (demux);
|
||||||
if (demux->segment.rate < 0)
|
if (demux->segment.rate < 0)
|
||||||
/* Set DISCONT flag for every first buffer in reverse playback mode
|
/* Set DISCONT flag for every first buffer in reverse playback mode
|
||||||
* as each fragment for its own has to be reversed */
|
* as each fragment for its own has to be reversed */
|
||||||
|
@ -1694,6 +1727,8 @@ gst_adaptive_demux_stream_push_buffer (GstAdaptiveDemuxStream * stream,
|
||||||
demux->segment.position =
|
demux->segment.position =
|
||||||
stream->segment.position - offset + period_start;
|
stream->segment.position - offset + period_start;
|
||||||
}
|
}
|
||||||
|
GST_ADAPTIVE_DEMUX_SEGMENT_UNLOCK (demux);
|
||||||
|
|
||||||
GST_LOG_OBJECT (stream->pad,
|
GST_LOG_OBJECT (stream->pad,
|
||||||
"Going to push buffer with PTS %" GST_TIME_FORMAT,
|
"Going to push buffer with PTS %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (GST_BUFFER_PTS (buffer)));
|
GST_TIME_ARGS (GST_BUFFER_PTS (buffer)));
|
||||||
|
@ -1723,8 +1758,10 @@ gst_adaptive_demux_stream_push_buffer (GstAdaptiveDemuxStream * stream,
|
||||||
stream->pending_caps = NULL;
|
stream->pending_caps = NULL;
|
||||||
}
|
}
|
||||||
if (G_UNLIKELY (stream->pending_segment)) {
|
if (G_UNLIKELY (stream->pending_segment)) {
|
||||||
|
GST_ADAPTIVE_DEMUX_SEGMENT_LOCK (demux);
|
||||||
pending_segment = stream->pending_segment;
|
pending_segment = stream->pending_segment;
|
||||||
stream->pending_segment = NULL;
|
stream->pending_segment = NULL;
|
||||||
|
GST_ADAPTIVE_DEMUX_SEGMENT_UNLOCK (demux);
|
||||||
}
|
}
|
||||||
if (G_UNLIKELY (stream->pending_tags || stream->bitrate_changed)) {
|
if (G_UNLIKELY (stream->pending_tags || stream->bitrate_changed)) {
|
||||||
GstTagList *tags = stream->pending_tags;
|
GstTagList *tags = stream->pending_tags;
|
||||||
|
@ -1864,6 +1901,7 @@ _src_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
|
||||||
GST_TIME_ARGS (GST_BUFFER_PTS (buffer)));
|
GST_TIME_ARGS (GST_BUFFER_PTS (buffer)));
|
||||||
|
|
||||||
if (GST_BUFFER_PTS_IS_VALID (buffer)) {
|
if (GST_BUFFER_PTS_IS_VALID (buffer)) {
|
||||||
|
GST_ADAPTIVE_DEMUX_SEGMENT_LOCK (demux);
|
||||||
stream->segment.position = GST_BUFFER_PTS (buffer);
|
stream->segment.position = GST_BUFFER_PTS (buffer);
|
||||||
|
|
||||||
/* Convert from position inside the stream's segment to the demuxer's
|
/* Convert from position inside the stream's segment to the demuxer's
|
||||||
|
@ -1872,6 +1910,7 @@ _src_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
|
||||||
demux->segment.position)
|
demux->segment.position)
|
||||||
demux->segment.position =
|
demux->segment.position =
|
||||||
stream->segment.position - offset + period_start;
|
stream->segment.position - offset + period_start;
|
||||||
|
GST_ADAPTIVE_DEMUX_SEGMENT_UNLOCK (demux);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -2563,9 +2602,11 @@ gst_adaptive_demux_stream_download_loop (GstAdaptiveDemuxStream * stream)
|
||||||
g_mutex_unlock (&stream->fragment_download_lock);
|
g_mutex_unlock (&stream->fragment_download_lock);
|
||||||
|
|
||||||
/* Check if we're done with our segment */
|
/* Check if we're done with our segment */
|
||||||
|
GST_ADAPTIVE_DEMUX_SEGMENT_LOCK (demux);
|
||||||
if (demux->segment.rate > 0) {
|
if (demux->segment.rate > 0) {
|
||||||
if (GST_CLOCK_TIME_IS_VALID (demux->segment.stop)
|
if (GST_CLOCK_TIME_IS_VALID (demux->segment.stop)
|
||||||
&& stream->segment.position >= stream->segment.stop) {
|
&& stream->segment.position >= stream->segment.stop) {
|
||||||
|
GST_ADAPTIVE_DEMUX_SEGMENT_UNLOCK (demux);
|
||||||
ret = GST_FLOW_EOS;
|
ret = GST_FLOW_EOS;
|
||||||
gst_task_stop (stream->download_task);
|
gst_task_stop (stream->download_task);
|
||||||
goto end_of_manifest;
|
goto end_of_manifest;
|
||||||
|
@ -2573,11 +2614,13 @@ gst_adaptive_demux_stream_download_loop (GstAdaptiveDemuxStream * stream)
|
||||||
} else {
|
} else {
|
||||||
if (GST_CLOCK_TIME_IS_VALID (demux->segment.start)
|
if (GST_CLOCK_TIME_IS_VALID (demux->segment.start)
|
||||||
&& stream->segment.position <= stream->segment.start) {
|
&& stream->segment.position <= stream->segment.start) {
|
||||||
|
GST_ADAPTIVE_DEMUX_SEGMENT_UNLOCK (demux);
|
||||||
ret = GST_FLOW_EOS;
|
ret = GST_FLOW_EOS;
|
||||||
gst_task_stop (stream->download_task);
|
gst_task_stop (stream->download_task);
|
||||||
goto end_of_manifest;
|
goto end_of_manifest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
GST_ADAPTIVE_DEMUX_SEGMENT_UNLOCK (demux);
|
||||||
|
|
||||||
/* Cleanup old streams if any */
|
/* Cleanup old streams if any */
|
||||||
if (G_UNLIKELY (demux->priv->old_streams != NULL)) {
|
if (G_UNLIKELY (demux->priv->old_streams != NULL)) {
|
||||||
|
@ -2604,16 +2647,12 @@ gst_adaptive_demux_stream_download_loop (GstAdaptiveDemuxStream * stream)
|
||||||
if (G_UNLIKELY (stream->restart_download)) {
|
if (G_UNLIKELY (stream->restart_download)) {
|
||||||
GstSegment segment;
|
GstSegment segment;
|
||||||
GstEvent *seg_event;
|
GstEvent *seg_event;
|
||||||
GstClockTime cur, ts;
|
GstClockTime cur, ts = 0;
|
||||||
gint64 pos;
|
gint64 pos;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (stream->pad,
|
GST_DEBUG_OBJECT (stream->pad,
|
||||||
"Activating stream due to reconfigure event");
|
"Activating stream due to reconfigure event");
|
||||||
|
|
||||||
cur = ts =
|
|
||||||
gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
|
|
||||||
stream->segment.position);
|
|
||||||
|
|
||||||
if (gst_pad_peer_query_position (stream->pad, GST_FORMAT_TIME, &pos)) {
|
if (gst_pad_peer_query_position (stream->pad, GST_FORMAT_TIME, &pos)) {
|
||||||
ts = (GstClockTime) pos;
|
ts = (GstClockTime) pos;
|
||||||
GST_DEBUG_OBJECT (demux, "Downstream position: %"
|
GST_DEBUG_OBJECT (demux, "Downstream position: %"
|
||||||
|
@ -2638,6 +2677,11 @@ gst_adaptive_demux_stream_download_loop (GstAdaptiveDemuxStream * stream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GST_ADAPTIVE_DEMUX_SEGMENT_LOCK (demux);
|
||||||
|
cur =
|
||||||
|
gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
|
||||||
|
stream->segment.position);
|
||||||
|
|
||||||
/* we might have already pushed this data */
|
/* we might have already pushed this data */
|
||||||
ts = MAX (ts, cur);
|
ts = MAX (ts, cur);
|
||||||
|
|
||||||
|
@ -2664,6 +2708,8 @@ gst_adaptive_demux_stream_download_loop (GstAdaptiveDemuxStream * stream)
|
||||||
* updated position */
|
* updated position */
|
||||||
seg_event = gst_event_new_segment (&stream->segment);
|
seg_event = gst_event_new_segment (&stream->segment);
|
||||||
gst_event_set_seqnum (seg_event, demux->priv->segment_seqnum);
|
gst_event_set_seqnum (seg_event, demux->priv->segment_seqnum);
|
||||||
|
GST_ADAPTIVE_DEMUX_SEGMENT_UNLOCK (demux);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (stream->pad, "Sending restart segment: %"
|
GST_DEBUG_OBJECT (stream->pad, "Sending restart segment: %"
|
||||||
GST_PTR_FORMAT, seg_event);
|
GST_PTR_FORMAT, seg_event);
|
||||||
gst_pad_push_event (stream->pad, seg_event);
|
gst_pad_push_event (stream->pad, seg_event);
|
||||||
|
@ -3084,6 +3130,7 @@ gst_adaptive_demux_stream_advance_fragment_unlocked (GstAdaptiveDemux * demux,
|
||||||
stream->download_total_time * GST_USECOND, NULL)));
|
stream->download_total_time * GST_USECOND, NULL)));
|
||||||
|
|
||||||
/* Don't update to the end of the segment if in reverse playback */
|
/* Don't update to the end of the segment if in reverse playback */
|
||||||
|
GST_ADAPTIVE_DEMUX_SEGMENT_LOCK (demux);
|
||||||
if (GST_CLOCK_TIME_IS_VALID (duration) && demux->segment.rate > 0) {
|
if (GST_CLOCK_TIME_IS_VALID (duration) && demux->segment.rate > 0) {
|
||||||
GstClockTime offset =
|
GstClockTime offset =
|
||||||
gst_adaptive_demux_stream_get_presentation_offset (demux, stream);
|
gst_adaptive_demux_stream_get_presentation_offset (demux, stream);
|
||||||
|
@ -3099,6 +3146,7 @@ gst_adaptive_demux_stream_advance_fragment_unlocked (GstAdaptiveDemux * demux,
|
||||||
demux->segment.position =
|
demux->segment.position =
|
||||||
stream->segment.position - offset + period_start;
|
stream->segment.position - offset + period_start;
|
||||||
}
|
}
|
||||||
|
GST_ADAPTIVE_DEMUX_SEGMENT_UNLOCK (demux);
|
||||||
|
|
||||||
if (gst_adaptive_demux_is_live (demux)
|
if (gst_adaptive_demux_is_live (demux)
|
||||||
|| gst_adaptive_demux_stream_has_next_fragment (demux, stream)) {
|
|| gst_adaptive_demux_stream_has_next_fragment (demux, stream)) {
|
||||||
|
|
Loading…
Reference in a new issue