diff --git a/ext/smoothstreaming/gstmssdemux.c b/ext/smoothstreaming/gstmssdemux.c index 35f81a580c..c975e17e08 100644 --- a/ext/smoothstreaming/gstmssdemux.c +++ b/ext/smoothstreaming/gstmssdemux.c @@ -310,7 +310,8 @@ gst_mss_demux_stream_seek (GstAdaptiveDemuxStream * stream, gboolean forward, { GstMssDemuxStream *mssstream = (GstMssDemuxStream *) stream; - gst_mss_stream_seek (mssstream->manifest_stream, flags, ts, final_ts); + gst_mss_stream_seek (mssstream->manifest_stream, forward, flags, ts, + final_ts); return GST_FLOW_OK; } diff --git a/ext/smoothstreaming/gstmssmanifest.c b/ext/smoothstreaming/gstmssmanifest.c index a100477871..73c623f968 100644 --- a/ext/smoothstreaming/gstmssmanifest.c +++ b/ext/smoothstreaming/gstmssmanifest.c @@ -1089,26 +1089,32 @@ gst_mss_stream_type_name (GstMssStreamType streamtype) /** * Seeks all streams to the fragment that contains the set time * + * @forward: if this is forward playback * @time: time in nanoseconds */ void -gst_mss_manifest_seek (GstMssManifest * manifest, guint64 time) +gst_mss_manifest_seek (GstMssManifest * manifest, gboolean forward, + guint64 time) { GSList *iter; for (iter = manifest->streams; iter; iter = g_slist_next (iter)) { - gst_mss_stream_seek (iter->data, 0, time, NULL); + gst_mss_stream_seek (iter->data, forward, 0, time, NULL); } } +#define SNAP_AFTER(forward,flags) \ + ((forward && (flags & GST_SEEK_FLAG_SNAP_AFTER)) || \ + (!forward && (flags & GST_SEEK_FLAG_SNAP_BEFORE))) + /** * Seeks this stream to the fragment that contains the sample at time * * @time: time in nanoseconds */ void -gst_mss_stream_seek (GstMssStream * stream, GstSeekFlags flags, guint64 time, - guint64 * final_time) +gst_mss_stream_seek (GstMssStream * stream, gboolean forward, + GstSeekFlags flags, guint64 time, guint64 * final_time) { GList *iter; guint64 timescale; @@ -1118,48 +1124,58 @@ gst_mss_stream_seek (GstMssStream * stream, GstSeekFlags flags, guint64 time, time = gst_util_uint64_scale_round (time, timescale, GST_SECOND); GST_DEBUG ("Stream %s seeking to %" G_GUINT64_FORMAT, stream->url, time); - for (iter = stream->fragments; iter; iter = g_list_next (iter)) { - GList *next = g_list_next (iter); - if (next) { - fragment = next->data; + fragment = iter->data; + if (fragment->time + fragment->repetitions * fragment->duration > time) { + stream->current_fragment = iter; + stream->fragment_repetition_index = + (time - fragment->time) / fragment->duration; + if (((time - fragment->time) % fragment->duration) == 0) { - if (fragment->time > time) { - stream->current_fragment = iter; - break; - } - } else { - fragment = iter->data; - if (fragment->time + fragment->repetitions * fragment->duration > time) { - stream->current_fragment = iter; - } else { - stream->current_fragment = NULL; /* EOS */ + /* for reverse playback, start from the previous fragment when we are + * exactly at a limit */ + if (!forward) + stream->fragment_repetition_index--; + } else if (SNAP_AFTER (forward, flags)) + stream->fragment_repetition_index++; + + if (stream->fragment_repetition_index == fragment->repetitions) { + /* move to the next one */ + stream->fragment_repetition_index = 0; + stream->current_fragment = g_list_next (iter); + fragment = + stream->current_fragment ? stream->current_fragment->data : NULL; + + } else if (stream->fragment_repetition_index == -1) { + if (g_list_previous (iter)) { + stream->current_fragment = g_list_previous (iter); + fragment = + stream->current_fragment ? stream->current_fragment->data : NULL; + stream->fragment_repetition_index = fragment->repetitions - 1; + } else { + stream->fragment_repetition_index = 0; + } } + break; } - } - /* position inside the repetitions */ - if (stream->current_fragment) { - fragment = stream->current_fragment->data; - stream->fragment_repetition_index = - (time - fragment->time) / fragment->duration; } GST_DEBUG ("Stream %s seeked to fragment time %" G_GUINT64_FORMAT - " repetition %u", stream->url, fragment->time, + " repetition %u", stream->url, + fragment ? fragment->time : GST_CLOCK_TIME_NONE, stream->fragment_repetition_index); if (final_time) { - if (fragment) - *final_time = - fragment->time + - stream->fragment_repetition_index * fragment->duration; - else { - /* always stops on the last one */ - GstMssStreamFragment *last_fragment = iter->data; - *final_time = - last_fragment->time + - last_fragment->repetitions * last_fragment->duration; + if (fragment) { + *final_time = gst_util_uint64_scale_round (fragment->time + + stream->fragment_repetition_index * fragment->duration, + GST_SECOND, timescale); + } else { + GstMssStreamFragment *last_fragment = g_list_last (iter)->data; + *final_time = gst_util_uint64_scale_round (last_fragment->time + + last_fragment->repetitions * last_fragment->duration, + GST_SECOND, timescale); } } } @@ -1214,7 +1230,9 @@ gst_mss_stream_reload_fragments (GstMssStream * stream, xmlNodePtr streamIndex) g_list_free_full (stream->fragments, g_free); stream->fragments = g_list_reverse (builder.fragments); stream->current_fragment = stream->fragments; - gst_mss_stream_seek (stream, 0, current_gst_time, NULL); + /* TODO Verify how repositioning here works for reverse + * playback - it might start from the wrong fragment */ + gst_mss_stream_seek (stream, TRUE, 0, current_gst_time, NULL); } } diff --git a/ext/smoothstreaming/gstmssmanifest.h b/ext/smoothstreaming/gstmssmanifest.h index bc5010d557..af7419c236 100644 --- a/ext/smoothstreaming/gstmssmanifest.h +++ b/ext/smoothstreaming/gstmssmanifest.h @@ -44,7 +44,7 @@ GSList * gst_mss_manifest_get_streams (GstMssManifest * manifest); guint64 gst_mss_manifest_get_timescale (GstMssManifest * manifest); guint64 gst_mss_manifest_get_duration (GstMssManifest * manifest); GstClockTime gst_mss_manifest_get_gst_duration (GstMssManifest * manifest); -void gst_mss_manifest_seek (GstMssManifest * manifest, guint64 time); +void gst_mss_manifest_seek (GstMssManifest * manifest, gboolean forward, guint64 time); gboolean gst_mss_manifest_change_bitrate (GstMssManifest *manifest, guint64 bitrate); guint64 gst_mss_manifest_get_current_bitrate (GstMssManifest * manifest); gboolean gst_mss_manifest_is_live (GstMssManifest * manifest); @@ -67,7 +67,7 @@ GstClockTime gst_mss_stream_get_fragment_gst_duration (GstMssStream * stream); gboolean gst_mss_stream_has_next_fragment (GstMssStream * stream); GstFlowReturn gst_mss_stream_advance_fragment (GstMssStream * stream); GstFlowReturn gst_mss_stream_regress_fragment (GstMssStream * stream); -void gst_mss_stream_seek (GstMssStream * stream, GstSeekFlags flags, guint64 time, guint64 * final_time); +void gst_mss_stream_seek (GstMssStream * stream, gboolean forward, GstSeekFlags flags, guint64 time, guint64 * final_time); const gchar * gst_mss_stream_get_lang (GstMssStream * stream); const gchar * gst_mss_stream_type_name (GstMssStreamType streamtype);