summaryrefslogtreecommitdiff
path: root/ext/hls
diff options
context:
space:
mode:
authorSeungha Yang <sh.yang@lge.com>2017-02-01 19:55:22 +0900
committerSebastian Dröge <sebastian@centricular.com>2017-03-02 19:25:48 +0200
commitb2e9891f8a06b07fad61204bda5b814a2ad5ef88 (patch)
tree29583109d670ff0d3fd1541587f04191f96fefed /ext/hls
parent78b2169c32562d606d563a7dcd5e724162e935f5 (diff)
downloadgstreamer-plugins-bad-b2e9891f8a06b07fad61204bda5b814a2ad5ef88.tar.gz
hlsdemux: Implement adaptivedemux's _stream_seek()
_stream_seek() can be called by adaptivedemux when "restart download" condition. It's mostly caused by track switching. https://bugzilla.gnome.org/show_bug.cgi?id=776997
Diffstat (limited to 'ext/hls')
-rw-r--r--ext/hls/gsthlsdemux.c176
1 files changed, 101 insertions, 75 deletions
diff --git a/ext/hls/gsthlsdemux.c b/ext/hls/gsthlsdemux.c
index 3e9be3511..32df21476 100644
--- a/ext/hls/gsthlsdemux.c
+++ b/ext/hls/gsthlsdemux.c
@@ -90,6 +90,9 @@ static gboolean gst_hls_demux_process_manifest (GstAdaptiveDemux * demux,
GstBuffer * buf);
static GstFlowReturn gst_hls_demux_update_manifest (GstAdaptiveDemux * demux);
static gboolean gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek);
+static GstFlowReturn gst_hls_demux_stream_seek (GstAdaptiveDemuxStream *
+ stream, gboolean forward, GstSeekFlags flags, GstClockTime ts,
+ GstClockTime * final_ts);
static gboolean
gst_hls_demux_start_fragment (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream);
@@ -165,6 +168,7 @@ gst_hls_demux_class_init (GstHLSDemuxClass * klass)
adaptivedemux_class->update_manifest = gst_hls_demux_update_manifest;
adaptivedemux_class->reset = gst_hls_demux_reset;
adaptivedemux_class->seek = gst_hls_demux_seek;
+ adaptivedemux_class->stream_seek = gst_hls_demux_stream_seek;
adaptivedemux_class->stream_has_next_fragment =
gst_hls_demux_stream_has_next_fragment;
adaptivedemux_class->stream_advance_fragment = gst_hls_demux_advance_fragment;
@@ -313,12 +317,9 @@ gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek)
GstSeekType start_type, stop_type;
gint64 start, stop;
gdouble rate, old_rate;
- GList *walk, *stream_walk;
- GstClockTime current_pos, target_pos;
- gint64 current_sequence;
+ GList *walk;
+ GstClockTime current_pos, target_pos, final_pos;
guint64 bitrate;
- gboolean snap_after, snap_nearest;
- gboolean reverse;
gst_event_parse_seek (seek, &rate, &format, &flags, &start_type, &start,
&stop_type, &stop);
@@ -332,11 +333,6 @@ gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek)
bitrate = gst_hls_demux_get_bitrate (hlsdemux);
- /* properly cleanup pending decryption status */
- if (flags & GST_SEEK_FLAG_FLUSH) {
- gst_hls_demux_clear_all_pending_data (hlsdemux);
- }
-
/* Use I-frame variants for trick modes */
if (hlsdemux->master->iframe_variants != NULL
&& rate < -1.0 && old_rate >= -1.0 && old_rate <= 1.0) {
@@ -368,79 +364,109 @@ gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek)
gst_hls_demux_change_playlist (hlsdemux, bitrate, NULL);
}
- for (stream_walk = demux->streams; stream_walk != NULL;
- stream_walk = stream_walk->next) {
- GstHLSDemuxStream *hls_stream =
- GST_HLS_DEMUX_STREAM_CAST (stream_walk->data);
- GstM3U8MediaFile *file = NULL;
-
- current_sequence = 0;
- current_pos = gst_m3u8_is_live (hls_stream->playlist) ?
- hls_stream->playlist->first_file_start : 0;
- reverse = rate < 0;
- target_pos = reverse ? stop : start;
-
- /* Snap to segment boundary. Improves seek performance on slow machines. */
- snap_nearest =
- (flags & GST_SEEK_FLAG_SNAP_NEAREST) == GST_SEEK_FLAG_SNAP_NEAREST;
- snap_after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
-
- GST_M3U8_CLIENT_LOCK (hlsdemux->client);
- /* FIXME: Here we need proper discont handling */
- for (walk = hls_stream->playlist->files; walk; walk = walk->next) {
- file = walk->data;
-
- current_sequence = file->sequence;
- if ((!reverse && snap_after) || snap_nearest) {
- if (current_pos >= target_pos)
- break;
- if (snap_nearest && target_pos - current_pos < file->duration / 2)
- break;
- } else if (reverse && snap_after) {
- /* check if the next fragment is our target, in this case we want to
- * start from the previous fragment */
- GstClockTime next_pos = current_pos + file->duration;
-
- if (next_pos <= target_pos && target_pos < next_pos + file->duration) {
- break;
- }
- } else if (current_pos <= target_pos
- && target_pos < current_pos + file->duration) {
+ target_pos = rate < 0 ? stop : start;
+ final_pos = target_pos;
+
+ /* properly cleanup pending decryption status */
+ if (flags & GST_SEEK_FLAG_FLUSH) {
+ gst_hls_demux_clear_all_pending_data (hlsdemux);
+ }
+
+ for (walk = demux->streams; walk; walk = g_list_next (walk)) {
+ GstAdaptiveDemuxStream *stream =
+ GST_ADAPTIVE_DEMUX_STREAM_CAST (walk->data);
+
+ gst_hls_demux_stream_seek (stream, rate >= 0, flags, target_pos,
+ &current_pos);
+
+ /* FIXME: use minimum position always ? */
+ if (final_pos > current_pos)
+ final_pos = current_pos;
+ }
+
+ if (IS_SNAP_SEEK (flags)) {
+ if (rate >= 0)
+ gst_segment_do_seek (&demux->segment, rate, format, flags, start_type,
+ final_pos, stop_type, stop, NULL);
+ else
+ gst_segment_do_seek (&demux->segment, rate, format, flags, start_type,
+ start, stop_type, final_pos, NULL);
+ }
+
+ return TRUE;
+}
+
+static GstFlowReturn
+gst_hls_demux_stream_seek (GstAdaptiveDemuxStream * stream, gboolean forward,
+ GstSeekFlags flags, GstClockTime ts, GstClockTime * final_ts)
+{
+ GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
+ GList *walk;
+ GstClockTime current_pos;
+ gint64 current_sequence;
+ gboolean snap_after, snap_nearest;
+ GstM3U8MediaFile *file = NULL;
+
+ current_sequence = 0;
+ current_pos = gst_m3u8_is_live (hls_stream->playlist) ?
+ hls_stream->playlist->first_file_start : 0;
+
+ /* Snap to segment boundary. Improves seek performance on slow machines. */
+ snap_nearest =
+ (flags & GST_SEEK_FLAG_SNAP_NEAREST) == GST_SEEK_FLAG_SNAP_NEAREST;
+ snap_after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
+
+ GST_M3U8_CLIENT_LOCK (hlsdemux->client);
+ /* FIXME: Here we need proper discont handling */
+ for (walk = hls_stream->playlist->files; walk; walk = walk->next) {
+ file = walk->data;
+
+ current_sequence = file->sequence;
+ if ((forward && snap_after) || snap_nearest) {
+ if (current_pos >= ts)
break;
- }
- current_pos += file->duration;
- }
+ if (snap_nearest && ts - current_pos < file->duration / 2)
+ break;
+ } else if (!forward && snap_after) {
+ /* check if the next fragment is our target, in this case we want to
+ * start from the previous fragment */
+ GstClockTime next_pos = current_pos + file->duration;
- if (walk == NULL) {
- GST_DEBUG_OBJECT (demux, "seeking further than track duration");
- current_sequence++;
+ if (next_pos <= ts && ts < next_pos + file->duration) {
+ break;
+ }
+ } else if (current_pos <= ts && ts < current_pos + file->duration) {
+ break;
}
+ current_pos += file->duration;
+ }
- GST_DEBUG_OBJECT (demux, "seeking to sequence %u",
- (guint) current_sequence);
- hls_stream->reset_pts = TRUE;
- hls_stream->playlist->sequence = current_sequence;
- hls_stream->playlist->current_file = walk;
- hls_stream->playlist->sequence_position = current_pos;
- GST_M3U8_CLIENT_UNLOCK (hlsdemux->client);
+ if (walk == NULL) {
+ GST_DEBUG_OBJECT (stream->pad, "seeking further than track duration");
+ current_sequence++;
+ }
- /* Play from the end of the current selected segment */
- if (file) {
- if (reverse && IS_SNAP_SEEK (flags))
- current_pos += file->duration;
- }
+ GST_DEBUG_OBJECT (stream->pad, "seeking to sequence %u",
+ (guint) current_sequence);
+ hls_stream->reset_pts = TRUE;
+ hls_stream->playlist->sequence = current_sequence;
+ hls_stream->playlist->current_file = walk;
+ hls_stream->playlist->sequence_position = current_pos;
+ GST_M3U8_CLIENT_UNLOCK (hlsdemux->client);
- if (IS_SNAP_SEEK (flags)) {
- if (!reverse)
- gst_segment_do_seek (&demux->segment, rate, format, flags, start_type,
- current_pos, stop_type, stop, NULL);
- else
- gst_segment_do_seek (&demux->segment, rate, format, flags, start_type,
- start, stop_type, current_pos, NULL);
- }
+ /* Play from the end of the current selected segment */
+ if (file) {
+ if (!forward && IS_SNAP_SEEK (flags))
+ current_pos += file->duration;
}
- return TRUE;
+ /* update stream's segment position */
+ stream->segment.position = current_pos;
+
+ if (final_ts)
+ *final_ts = current_pos;
+
+ return GST_FLOW_OK;
}
static GstFlowReturn