mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
adaptivedemux: handle snap seeks
Adaptive demuxers need to start downloading from specific positions (fragments) for every stream, this means that all streams can snap-seek to a different position when requested. Snap seeking in this case will be done in 2 steps: 1) do the snap seeking on the pad that received the seek event and get the final position 2) use this position to do a regular seek on the other streams to make sure they all start from the same position More arguments were added to the stream_seek function, allowing better control of how seeking is done. Knowing the flags and the playback direction allows subclasses to handle snap-seeking. And also adds a new return parameter to inform of the final selected seeking position that is used to align the other streams. https://bugzilla.gnome.org/show_bug.cgi?id=759158
This commit is contained in:
parent
f16916f7e7
commit
731ab94cc3
8 changed files with 128 additions and 36 deletions
|
@ -233,19 +233,20 @@ static gboolean gst_dash_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek);
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_dash_demux_stream_update_fragment_info (GstAdaptiveDemuxStream * stream);
|
gst_dash_demux_stream_update_fragment_info (GstAdaptiveDemuxStream * stream);
|
||||||
static GstFlowReturn gst_dash_demux_stream_seek (GstAdaptiveDemuxStream *
|
static GstFlowReturn gst_dash_demux_stream_seek (GstAdaptiveDemuxStream *
|
||||||
stream, GstClockTime ts);
|
stream, gboolean forward, GstSeekFlags flags, GstClockTime ts,
|
||||||
static gboolean
|
GstClockTime * final_ts);
|
||||||
gst_dash_demux_stream_has_next_fragment (GstAdaptiveDemuxStream * stream);
|
static gboolean gst_dash_demux_stream_has_next_fragment (GstAdaptiveDemuxStream
|
||||||
|
* stream);
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_dash_demux_stream_advance_fragment (GstAdaptiveDemuxStream * stream);
|
gst_dash_demux_stream_advance_fragment (GstAdaptiveDemuxStream * stream);
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_dash_demux_stream_advance_subfragment (GstAdaptiveDemuxStream * stream);
|
gst_dash_demux_stream_advance_subfragment (GstAdaptiveDemuxStream * stream);
|
||||||
static gboolean gst_dash_demux_stream_select_bitrate (GstAdaptiveDemuxStream *
|
static gboolean gst_dash_demux_stream_select_bitrate (GstAdaptiveDemuxStream *
|
||||||
stream, guint64 bitrate);
|
stream, guint64 bitrate);
|
||||||
static gint64
|
static gint64 gst_dash_demux_get_manifest_update_interval (GstAdaptiveDemux *
|
||||||
gst_dash_demux_get_manifest_update_interval (GstAdaptiveDemux * demux);
|
demux);
|
||||||
static GstFlowReturn
|
static GstFlowReturn gst_dash_demux_update_manifest_data (GstAdaptiveDemux *
|
||||||
gst_dash_demux_update_manifest_data (GstAdaptiveDemux * demux, GstBuffer * buf);
|
demux, GstBuffer * buf);
|
||||||
static gint64
|
static gint64
|
||||||
gst_dash_demux_stream_get_fragment_waiting_time (GstAdaptiveDemuxStream *
|
gst_dash_demux_stream_get_fragment_waiting_time (GstAdaptiveDemuxStream *
|
||||||
stream);
|
stream);
|
||||||
|
@ -1066,7 +1067,7 @@ gst_dash_demux_index_entry_search (GstSidxBoxEntry * entry, GstClockTime * ts,
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_dash_demux_stream_sidx_seek (GstDashDemuxStream * dashstream,
|
gst_dash_demux_stream_sidx_seek (GstDashDemuxStream * dashstream,
|
||||||
GstClockTime ts)
|
GstSeekFlags flags, GstClockTime ts, GstClockTime * final_ts)
|
||||||
{
|
{
|
||||||
GstSidxBox *sidx = SIDX (dashstream);
|
GstSidxBox *sidx = SIDX (dashstream);
|
||||||
GstSidxBoxEntry *entry;
|
GstSidxBoxEntry *entry;
|
||||||
|
@ -1088,24 +1089,34 @@ gst_dash_demux_stream_sidx_seek (GstDashDemuxStream * dashstream,
|
||||||
|
|
||||||
sidx->entry_index = idx;
|
sidx->entry_index = idx;
|
||||||
dashstream->sidx_index = idx;
|
dashstream->sidx_index = idx;
|
||||||
|
|
||||||
|
if (final_ts) {
|
||||||
|
if (idx == sidx->entries_count)
|
||||||
|
*final_ts = sidx->entries[idx].pts + sidx->entries[idx].duration;
|
||||||
|
else
|
||||||
|
*final_ts = sidx->entries[idx].pts;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_dash_demux_stream_seek (GstAdaptiveDemuxStream * stream, GstClockTime ts)
|
gst_dash_demux_stream_seek (GstAdaptiveDemuxStream * stream, gboolean forward,
|
||||||
|
GstSeekFlags flags, GstClockTime ts, GstClockTime * final_ts)
|
||||||
{
|
{
|
||||||
GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
|
GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
|
||||||
GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (stream->demux);
|
GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (stream->demux);
|
||||||
|
|
||||||
if (gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client)) {
|
if (gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client)) {
|
||||||
if (dashstream->sidx_parser.status == GST_ISOFF_SIDX_PARSER_FINISHED) {
|
if (dashstream->sidx_parser.status == GST_ISOFF_SIDX_PARSER_FINISHED) {
|
||||||
gst_dash_demux_stream_sidx_seek (dashstream, ts);
|
gst_dash_demux_stream_sidx_seek (dashstream, flags, ts, final_ts);
|
||||||
} else {
|
} else {
|
||||||
/* no index yet, seek when we have it */
|
/* no index yet, seek when we have it */
|
||||||
|
/* FIXME - the final_ts won't be correct here */
|
||||||
dashstream->pending_seek_ts = ts;
|
dashstream->pending_seek_ts = ts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_mpd_client_stream_seek (dashdemux->client, dashstream->active_stream, ts);
|
gst_mpd_client_stream_seek (dashdemux->client, dashstream->active_stream,
|
||||||
|
forward, flags, ts, final_ts);
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1340,7 +1351,7 @@ gst_dash_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek)
|
||||||
gst_isoff_sidx_parser_clear (&dashstream->sidx_parser);
|
gst_isoff_sidx_parser_clear (&dashstream->sidx_parser);
|
||||||
gst_isoff_sidx_parser_init (&dashstream->sidx_parser);
|
gst_isoff_sidx_parser_init (&dashstream->sidx_parser);
|
||||||
}
|
}
|
||||||
gst_dash_demux_stream_seek (iter->data, target_pos);
|
gst_dash_demux_stream_seek (iter->data, rate >= 0, 0, target_pos, NULL);
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -1438,7 +1449,8 @@ gst_dash_demux_update_manifest_data (GstAdaptiveDemux * demux,
|
||||||
GST_TIME_FORMAT, GST_TIME_ARGS (ts),
|
GST_TIME_FORMAT, GST_TIME_ARGS (ts),
|
||||||
GST_TIME_ARGS (ts + (10 * GST_USECOND)));
|
GST_TIME_ARGS (ts + (10 * GST_USECOND)));
|
||||||
ts += 10 * GST_USECOND;
|
ts += 10 * GST_USECOND;
|
||||||
gst_mpd_client_stream_seek (new_client, new_stream, ts);
|
gst_mpd_client_stream_seek (new_client, new_stream,
|
||||||
|
demux->segment.rate >= 0, 0, ts, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
demux_stream->active_stream = new_stream;
|
demux_stream->active_stream = new_stream;
|
||||||
|
@ -1598,8 +1610,9 @@ gst_dash_demux_data_received (GstAdaptiveDemux * demux,
|
||||||
/* when finished, prepare for real data streaming */
|
/* when finished, prepare for real data streaming */
|
||||||
if (dash_stream->sidx_parser.status == GST_ISOFF_SIDX_PARSER_FINISHED) {
|
if (dash_stream->sidx_parser.status == GST_ISOFF_SIDX_PARSER_FINISHED) {
|
||||||
if (GST_CLOCK_TIME_IS_VALID (dash_stream->pending_seek_ts)) {
|
if (GST_CLOCK_TIME_IS_VALID (dash_stream->pending_seek_ts)) {
|
||||||
gst_dash_demux_stream_sidx_seek (dash_stream,
|
/* FIXME, preserve seek flags */
|
||||||
dash_stream->pending_seek_ts);
|
gst_dash_demux_stream_sidx_seek (dash_stream, 0,
|
||||||
|
dash_stream->pending_seek_ts, NULL);
|
||||||
dash_stream->pending_seek_ts = GST_CLOCK_TIME_NONE;
|
dash_stream->pending_seek_ts = GST_CLOCK_TIME_NONE;
|
||||||
} else {
|
} else {
|
||||||
SIDX (dash_stream)->entry_index = dash_stream->sidx_index;
|
SIDX (dash_stream)->entry_index = dash_stream->sidx_index;
|
||||||
|
|
|
@ -4652,7 +4652,8 @@ gst_mpd_client_setup_streaming (GstMpdClient * client,
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gst_mpd_client_stream_seek (GstMpdClient * client, GstActiveStream * stream,
|
gst_mpd_client_stream_seek (GstMpdClient * client, GstActiveStream * stream,
|
||||||
GstClockTime ts)
|
gboolean forward, GstSeekFlags flags, GstClockTime ts,
|
||||||
|
GstClockTime * final_ts)
|
||||||
{
|
{
|
||||||
gint index = 0;
|
gint index = 0;
|
||||||
gint repeat_index = 0;
|
gint repeat_index = 0;
|
||||||
|
@ -4692,6 +4693,9 @@ gst_mpd_client_stream_seek (GstMpdClient * client, GstActiveStream * stream,
|
||||||
GST_DEBUG ("Seek to after last segment");
|
GST_DEBUG ("Seek to after last segment");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (final_ts)
|
||||||
|
*final_ts = selectedChunk->start + selectedChunk->duration * repeat_index;
|
||||||
} else {
|
} else {
|
||||||
GstClockTime duration =
|
GstClockTime duration =
|
||||||
gst_mpd_client_get_segment_duration (client, stream, NULL);
|
gst_mpd_client_get_segment_duration (client, stream, NULL);
|
||||||
|
@ -4716,6 +4720,8 @@ gst_mpd_client_stream_seek (GstMpdClient * client, GstActiveStream * stream,
|
||||||
GST_DEBUG ("Seek to after last segment");
|
GST_DEBUG ("Seek to after last segment");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
if (final_ts)
|
||||||
|
*final_ts = index * duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
stream->segment_repeat_index = repeat_index;
|
stream->segment_repeat_index = repeat_index;
|
||||||
|
@ -5816,7 +5822,9 @@ gst_mpd_client_seek_to_time (GstMpdClient * client, GDateTime * time)
|
||||||
|
|
||||||
ts = ts_microseconds * GST_USECOND;
|
ts = ts_microseconds * GST_USECOND;
|
||||||
for (stream = client->active_streams; stream; stream = g_list_next (stream)) {
|
for (stream = client->active_streams; stream; stream = g_list_next (stream)) {
|
||||||
ret = ret & gst_mpd_client_stream_seek (client, stream->data, ts);
|
ret =
|
||||||
|
ret & gst_mpd_client_stream_seek (client, stream->data, TRUE, 0, ts,
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -544,7 +544,7 @@ gboolean gst_mpd_client_get_next_fragment (GstMpdClient *client, guint indexStre
|
||||||
gboolean gst_mpd_client_get_next_header (GstMpdClient *client, gchar **uri, guint stream_idx, gint64 * range_start, gint64 * range_end);
|
gboolean gst_mpd_client_get_next_header (GstMpdClient *client, gchar **uri, guint stream_idx, gint64 * range_start, gint64 * range_end);
|
||||||
gboolean gst_mpd_client_get_next_header_index (GstMpdClient *client, gchar **uri, guint stream_idx, gint64 * range_start, gint64 * range_end);
|
gboolean gst_mpd_client_get_next_header_index (GstMpdClient *client, gchar **uri, guint stream_idx, gint64 * range_start, gint64 * range_end);
|
||||||
gboolean gst_mpd_client_is_live (GstMpdClient * client);
|
gboolean gst_mpd_client_is_live (GstMpdClient * client);
|
||||||
gboolean gst_mpd_client_stream_seek (GstMpdClient * client, GstActiveStream * stream, GstClockTime ts);
|
gboolean gst_mpd_client_stream_seek (GstMpdClient * client, GstActiveStream * stream, gboolean forward, GstSeekFlags flags, GstClockTime ts, GstClockTime * final_ts);
|
||||||
gboolean gst_mpd_client_seek_to_time (GstMpdClient * client, GDateTime * time);
|
gboolean gst_mpd_client_seek_to_time (GstMpdClient * client, GDateTime * time);
|
||||||
GstClockTime gst_mpd_parser_get_stream_presentation_offset (GstMpdClient *client, guint stream_idx);
|
GstClockTime gst_mpd_parser_get_stream_presentation_offset (GstMpdClient *client, guint stream_idx);
|
||||||
gchar** gst_mpd_client_get_utc_timing_sources (GstMpdClient *client, guint methods, GstMPDUTCTimingType *selected_method);
|
gchar** gst_mpd_client_get_utc_timing_sources (GstMpdClient *client, guint methods, GstMPDUTCTimingType *selected_method);
|
||||||
|
|
|
@ -122,9 +122,10 @@ static gboolean gst_mss_demux_process_manifest (GstAdaptiveDemux * demux,
|
||||||
static GstClockTime gst_mss_demux_get_duration (GstAdaptiveDemux * demux);
|
static GstClockTime gst_mss_demux_get_duration (GstAdaptiveDemux * demux);
|
||||||
static void gst_mss_demux_reset (GstAdaptiveDemux * demux);
|
static void gst_mss_demux_reset (GstAdaptiveDemux * demux);
|
||||||
static GstFlowReturn gst_mss_demux_stream_seek (GstAdaptiveDemuxStream * stream,
|
static GstFlowReturn gst_mss_demux_stream_seek (GstAdaptiveDemuxStream * stream,
|
||||||
GstClockTime ts);
|
gboolean forward, GstSeekFlags flags, GstClockTime ts,
|
||||||
static gboolean
|
GstClockTime * final_ts);
|
||||||
gst_mss_demux_stream_has_next_fragment (GstAdaptiveDemuxStream * stream);
|
static gboolean gst_mss_demux_stream_has_next_fragment (GstAdaptiveDemuxStream *
|
||||||
|
stream);
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_mss_demux_stream_advance_fragment (GstAdaptiveDemuxStream * stream);
|
gst_mss_demux_stream_advance_fragment (GstAdaptiveDemuxStream * stream);
|
||||||
static gboolean gst_mss_demux_stream_select_bitrate (GstAdaptiveDemuxStream *
|
static gboolean gst_mss_demux_stream_select_bitrate (GstAdaptiveDemuxStream *
|
||||||
|
@ -304,11 +305,12 @@ gst_mss_demux_stream_update_fragment_info (GstAdaptiveDemuxStream * stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_mss_demux_stream_seek (GstAdaptiveDemuxStream * stream, GstClockTime ts)
|
gst_mss_demux_stream_seek (GstAdaptiveDemuxStream * stream, gboolean forward,
|
||||||
|
GstSeekFlags flags, GstClockTime ts, GstClockTime * final_ts)
|
||||||
{
|
{
|
||||||
GstMssDemuxStream *mssstream = (GstMssDemuxStream *) stream;
|
GstMssDemuxStream *mssstream = (GstMssDemuxStream *) stream;
|
||||||
|
|
||||||
gst_mss_stream_seek (mssstream->manifest_stream, ts);
|
gst_mss_stream_seek (mssstream->manifest_stream, flags, ts, final_ts);
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1097,7 +1097,7 @@ gst_mss_manifest_seek (GstMssManifest * manifest, guint64 time)
|
||||||
GSList *iter;
|
GSList *iter;
|
||||||
|
|
||||||
for (iter = manifest->streams; iter; iter = g_slist_next (iter)) {
|
for (iter = manifest->streams; iter; iter = g_slist_next (iter)) {
|
||||||
gst_mss_stream_seek (iter->data, time);
|
gst_mss_stream_seek (iter->data, 0, time, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1107,7 +1107,8 @@ gst_mss_manifest_seek (GstMssManifest * manifest, guint64 time)
|
||||||
* @time: time in nanoseconds
|
* @time: time in nanoseconds
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
gst_mss_stream_seek (GstMssStream * stream, guint64 time)
|
gst_mss_stream_seek (GstMssStream * stream, GstSeekFlags flags, guint64 time,
|
||||||
|
guint64 * final_time)
|
||||||
{
|
{
|
||||||
GList *iter;
|
GList *iter;
|
||||||
guint64 timescale;
|
guint64 timescale;
|
||||||
|
@ -1148,6 +1149,19 @@ gst_mss_stream_seek (GstMssStream * stream, guint64 time)
|
||||||
GST_DEBUG ("Stream %s seeked to fragment time %" G_GUINT64_FORMAT
|
GST_DEBUG ("Stream %s seeked to fragment time %" G_GUINT64_FORMAT
|
||||||
" repetition %u", stream->url, fragment->time,
|
" repetition %u", stream->url, fragment->time,
|
||||||
stream->fragment_repetition_index);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
guint64
|
guint64
|
||||||
|
@ -1200,7 +1214,7 @@ gst_mss_stream_reload_fragments (GstMssStream * stream, xmlNodePtr streamIndex)
|
||||||
g_list_free_full (stream->fragments, g_free);
|
g_list_free_full (stream->fragments, g_free);
|
||||||
stream->fragments = g_list_reverse (builder.fragments);
|
stream->fragments = g_list_reverse (builder.fragments);
|
||||||
stream->current_fragment = stream->fragments;
|
stream->current_fragment = stream->fragments;
|
||||||
gst_mss_stream_seek (stream, current_gst_time);
|
gst_mss_stream_seek (stream, 0, current_gst_time, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ GstClockTime gst_mss_stream_get_fragment_gst_duration (GstMssStream * stream);
|
||||||
gboolean gst_mss_stream_has_next_fragment (GstMssStream * stream);
|
gboolean gst_mss_stream_has_next_fragment (GstMssStream * stream);
|
||||||
GstFlowReturn gst_mss_stream_advance_fragment (GstMssStream * stream);
|
GstFlowReturn gst_mss_stream_advance_fragment (GstMssStream * stream);
|
||||||
GstFlowReturn gst_mss_stream_regress_fragment (GstMssStream * stream);
|
GstFlowReturn gst_mss_stream_regress_fragment (GstMssStream * stream);
|
||||||
void gst_mss_stream_seek (GstMssStream * stream, guint64 time);
|
void gst_mss_stream_seek (GstMssStream * stream, GstSeekFlags flags, guint64 time, guint64 * final_time);
|
||||||
const gchar * gst_mss_stream_get_lang (GstMssStream * stream);
|
const gchar * gst_mss_stream_get_lang (GstMssStream * stream);
|
||||||
|
|
||||||
const gchar * gst_mss_stream_type_name (GstMssStreamType streamtype);
|
const gchar * gst_mss_stream_type_name (GstMssStreamType streamtype);
|
||||||
|
|
|
@ -230,7 +230,8 @@ static gboolean gst_adaptive_demux_expose_streams (GstAdaptiveDemux * demux,
|
||||||
gboolean first_and_live);
|
gboolean first_and_live);
|
||||||
static gboolean gst_adaptive_demux_is_live (GstAdaptiveDemux * demux);
|
static gboolean gst_adaptive_demux_is_live (GstAdaptiveDemux * demux);
|
||||||
static GstFlowReturn gst_adaptive_demux_stream_seek (GstAdaptiveDemux * demux,
|
static GstFlowReturn gst_adaptive_demux_stream_seek (GstAdaptiveDemux * demux,
|
||||||
GstAdaptiveDemuxStream * stream, GstClockTime ts);
|
GstAdaptiveDemuxStream * stream, gboolean forward, GstSeekFlags flags,
|
||||||
|
GstClockTime ts, GstClockTime * final_ts);
|
||||||
static gboolean gst_adaptive_demux_stream_has_next_fragment (GstAdaptiveDemux *
|
static gboolean gst_adaptive_demux_stream_has_next_fragment (GstAdaptiveDemux *
|
||||||
demux, GstAdaptiveDemuxStream * stream);
|
demux, GstAdaptiveDemuxStream * stream);
|
||||||
static gboolean gst_adaptive_demux_stream_select_bitrate (GstAdaptiveDemux *
|
static gboolean gst_adaptive_demux_stream_select_bitrate (GstAdaptiveDemux *
|
||||||
|
@ -1205,6 +1206,13 @@ gst_adaptive_demux_can_seek (GstAdaptiveDemux * demux)
|
||||||
return klass->seek != NULL;
|
return klass->seek != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define IS_SNAP_SEEK(f) (f & (GST_SEEK_FLAG_SNAP_BEFORE | \
|
||||||
|
GST_SEEK_FLAG_SNAP_AFTER | \
|
||||||
|
GST_SEEK_FLAG_SNAP_NEAREST))
|
||||||
|
#define REMOVE_SNAP_FLAGS(f) (f & !(GST_SEEK_FLAG_SNAP_BEFORE | \
|
||||||
|
GST_SEEK_FLAG_SNAP_AFTER | \
|
||||||
|
GST_SEEK_FLAG_SNAP_NEAREST))
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_adaptive_demux_src_event (GstPad * pad, GstObject * parent,
|
gst_adaptive_demux_src_event (GstPad * pad, GstObject * parent,
|
||||||
GstEvent * event)
|
GstEvent * event)
|
||||||
|
@ -1215,6 +1223,8 @@ gst_adaptive_demux_src_event (GstPad * pad, GstObject * parent,
|
||||||
demux = GST_ADAPTIVE_DEMUX_CAST (parent);
|
demux = GST_ADAPTIVE_DEMUX_CAST (parent);
|
||||||
demux_class = GST_ADAPTIVE_DEMUX_GET_CLASS (demux);
|
demux_class = GST_ADAPTIVE_DEMUX_GET_CLASS (demux);
|
||||||
|
|
||||||
|
/* FIXME handle events received on pads that are to be removed */
|
||||||
|
|
||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
case GST_EVENT_SEEK:
|
case GST_EVENT_SEEK:
|
||||||
{
|
{
|
||||||
|
@ -1270,10 +1280,7 @@ gst_adaptive_demux_src_event (GstPad * pad, GstObject * parent,
|
||||||
|
|
||||||
seqnum = gst_event_get_seqnum (event);
|
seqnum = gst_event_get_seqnum (event);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (demux,
|
GST_DEBUG_OBJECT (demux, "seek event, %" GST_PTR_FORMAT, event);
|
||||||
"seek event, rate: %f type: %d start: %" GST_TIME_FORMAT " stop: %"
|
|
||||||
GST_TIME_FORMAT, rate, start_type, GST_TIME_ARGS (start),
|
|
||||||
GST_TIME_ARGS (stop));
|
|
||||||
|
|
||||||
/* 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);
|
||||||
|
@ -1309,6 +1316,52 @@ gst_adaptive_demux_src_event (GstPad * pad, GstObject * parent,
|
||||||
GST_DEBUG_OBJECT (demux, "Seeking to segment %" GST_SEGMENT_FORMAT,
|
GST_DEBUG_OBJECT (demux, "Seeking to segment %" GST_SEGMENT_FORMAT,
|
||||||
&demux->segment);
|
&demux->segment);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle snap seeks as follows:
|
||||||
|
* 1) do the snap seeking on the stream that received
|
||||||
|
* the event
|
||||||
|
* 2) use the final position on this stream to seek
|
||||||
|
* on the other streams to the same position
|
||||||
|
*
|
||||||
|
* We can't snap at all streams at the same time as
|
||||||
|
* they might end in different positions, so just
|
||||||
|
* use the one that received the event as the 'leading'
|
||||||
|
* one to do the snap seek.
|
||||||
|
*/
|
||||||
|
if (IS_SNAP_SEEK (flags) && demux_class->stream_seek) {
|
||||||
|
GstAdaptiveDemuxStream *stream =
|
||||||
|
gst_adaptive_demux_find_stream_for_pad (demux, pad);
|
||||||
|
GstClockTime ts;
|
||||||
|
GstSeekFlags stream_seek_flags = flags;
|
||||||
|
|
||||||
|
/* snap-seek on the stream that received the event and then
|
||||||
|
* use the resulting position to seek on all streams */
|
||||||
|
|
||||||
|
if (rate >= 0 && start_type != GST_SEEK_TYPE_NONE) {
|
||||||
|
ts = start;
|
||||||
|
} else if (rate < 0 && stop_type != GST_SEEK_TYPE_NONE) {
|
||||||
|
ts = stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret =
|
||||||
|
demux_class->stream_seek (stream, rate >= 0, stream_seek_flags, ts,
|
||||||
|
&ts);
|
||||||
|
|
||||||
|
/* replace event with a new one without snaping to seek on all streams */
|
||||||
|
gst_event_unref (event);
|
||||||
|
if (rate >= 0 && start_type != GST_SEEK_TYPE_NONE) {
|
||||||
|
start = ts;
|
||||||
|
} else if (rate < 0 && stop_type != GST_SEEK_TYPE_NONE) {
|
||||||
|
stop = ts;
|
||||||
|
}
|
||||||
|
event =
|
||||||
|
gst_event_new_seek (rate, format, REMOVE_SNAP_FLAGS (flags),
|
||||||
|
start_type, start, stop_type, stop);
|
||||||
|
GST_DEBUG_OBJECT (demux, "Adapted snap seek to %" GST_PTR_FORMAT,
|
||||||
|
event);
|
||||||
|
}
|
||||||
|
GST_DEBUG_OBJECT (demux, "Calling subclass seek: %" GST_PTR_FORMAT,
|
||||||
|
event);
|
||||||
ret = demux_class->seek (demux, event);
|
ret = demux_class->seek (demux, event);
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
|
@ -2686,7 +2739,8 @@ gst_adaptive_demux_stream_download_loop (GstAdaptiveDemuxStream * stream)
|
||||||
period_start = gst_adaptive_demux_get_period_start_time (demux);
|
period_start = gst_adaptive_demux_get_period_start_time (demux);
|
||||||
|
|
||||||
/* TODO check return */
|
/* TODO check return */
|
||||||
gst_adaptive_demux_stream_seek (demux, stream, ts);
|
gst_adaptive_demux_stream_seek (demux, stream, demux->segment.rate >= 0,
|
||||||
|
0, ts, &ts);
|
||||||
|
|
||||||
segment.position = ts - period_start + offset;
|
segment.position = ts - period_start + offset;
|
||||||
}
|
}
|
||||||
|
@ -3050,12 +3104,13 @@ gst_adaptive_demux_is_live (GstAdaptiveDemux * demux)
|
||||||
/* must be called with manifest_lock taken */
|
/* must be called with manifest_lock taken */
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_adaptive_demux_stream_seek (GstAdaptiveDemux * demux,
|
gst_adaptive_demux_stream_seek (GstAdaptiveDemux * demux,
|
||||||
GstAdaptiveDemuxStream * stream, GstClockTime ts)
|
GstAdaptiveDemuxStream * stream, gboolean forward, GstSeekFlags flags,
|
||||||
|
GstClockTime ts, GstClockTime * final_ts)
|
||||||
{
|
{
|
||||||
GstAdaptiveDemuxClass *klass = GST_ADAPTIVE_DEMUX_GET_CLASS (demux);
|
GstAdaptiveDemuxClass *klass = GST_ADAPTIVE_DEMUX_GET_CLASS (demux);
|
||||||
|
|
||||||
if (klass->stream_seek)
|
if (klass->stream_seek)
|
||||||
return klass->stream_seek (stream, ts);
|
return klass->stream_seek (stream, forward, flags, ts, final_ts);
|
||||||
return GST_FLOW_ERROR;
|
return GST_FLOW_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -310,7 +310,7 @@ struct _GstAdaptiveDemuxClass
|
||||||
void (*advance_period) (GstAdaptiveDemux * demux);
|
void (*advance_period) (GstAdaptiveDemux * demux);
|
||||||
|
|
||||||
void (*stream_free) (GstAdaptiveDemuxStream * stream);
|
void (*stream_free) (GstAdaptiveDemuxStream * stream);
|
||||||
GstFlowReturn (*stream_seek) (GstAdaptiveDemuxStream * stream, GstClockTime ts);
|
GstFlowReturn (*stream_seek) (GstAdaptiveDemuxStream * stream, gboolean forward, GstSeekFlags flags, GstClockTime target_ts, GstClockTime * final_ts);
|
||||||
gboolean (*stream_has_next_fragment) (GstAdaptiveDemuxStream * stream);
|
gboolean (*stream_has_next_fragment) (GstAdaptiveDemuxStream * stream);
|
||||||
GstFlowReturn (*stream_advance_fragment) (GstAdaptiveDemuxStream * stream);
|
GstFlowReturn (*stream_advance_fragment) (GstAdaptiveDemuxStream * stream);
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue