summaryrefslogtreecommitdiff
path: root/ext/hls/m3u8.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/hls/m3u8.c')
-rwxr-xr-xext/hls/m3u8.c81
1 files changed, 77 insertions, 4 deletions
diff --git a/ext/hls/m3u8.c b/ext/hls/m3u8.c
index c737b3d4a..ee0a45d84 100755
--- a/ext/hls/m3u8.c
+++ b/ext/hls/m3u8.c
@@ -51,8 +51,8 @@ gst_g_list_copy_deep (GList * list, GCopyFunc func, gpointer user_data)
static GstM3U8 *gst_m3u8_new (void);
static void gst_m3u8_free (GstM3U8 * m3u8);
-static gboolean gst_m3u8_update (GstM3U8 * m3u8, gchar * data,
- gboolean * updated);
+static gboolean gst_m3u8_update (GstM3U8Client * client, GstM3U8 * m3u8,
+ gchar * data, gboolean * updated);
static GstM3U8MediaFile *gst_m3u8_media_file_new (gchar * uri,
gchar * title, GstClockTime duration, guint sequence);
static void gst_m3u8_media_file_free (GstM3U8MediaFile * self);
@@ -382,7 +382,8 @@ gst_m3u8_compare_playlist_by_bitrate (gconstpointer a, gconstpointer b)
* @data: a m3u8 playlist text data, taking ownership
*/
static gboolean
-gst_m3u8_update (GstM3U8 * self, gchar * data, gboolean * updated)
+gst_m3u8_update (GstM3U8Client * client, GstM3U8 * self, gchar * data,
+ gboolean * updated)
{
gint val;
GstClockTime duration;
@@ -723,6 +724,37 @@ gst_m3u8_update (GstM3U8 * self, gchar * data, gboolean * updated)
self->current_variant = g_list_find_custom (self->lists, top_variant_uri,
(GCompareFunc) _m3u8_compare_uri);
}
+ /* calculate the start and end times of this media playlist. */
+ if (self->files) {
+ GList *walk;
+ GstM3U8MediaFile *file;
+ GstClockTime duration = 0;
+
+ for (walk = self->files; walk; walk = walk->next) {
+ file = walk->data;
+ duration += file->duration;
+ if (file->sequence > client->highest_sequence_number) {
+ if (client->highest_sequence_number >= 0) {
+ /* if an update of the media playlist has been missed, there
+ will be a gap between self->highest_sequence_number and the
+ first sequence number in this media playlist. In this situation
+ assume that the missing fragments had a duration of
+ targetduration each */
+ client->last_file_end +=
+ (file->sequence - client->highest_sequence_number -
+ 1) * self->targetduration;
+ }
+ client->last_file_end += file->duration;
+ client->highest_sequence_number = file->sequence;
+ }
+ }
+ if (GST_M3U8_CLIENT_IS_LIVE (client)) {
+ client->first_file_start = client->last_file_end - duration;
+ GST_DEBUG ("Live playlist range %" GST_TIME_FORMAT " -> %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (client->first_file_start),
+ GST_TIME_ARGS (client->last_file_end));
+ }
+ }
return TRUE;
}
@@ -740,6 +772,7 @@ gst_m3u8_client_new (const gchar * uri, const gchar * base_uri)
client->sequence = -1;
client->sequence_position = 0;
client->update_failed_count = 0;
+ client->highest_sequence_number = -1;
g_mutex_init (&client->lock);
gst_m3u8_set_uri (client->main, g_strdup (uri), g_strdup (base_uri), NULL);
@@ -781,7 +814,7 @@ gst_m3u8_client_update (GstM3U8Client * self, gchar * data)
GST_M3U8_CLIENT_LOCK (self);
m3u8 = self->current ? self->current : self->main;
- if (!gst_m3u8_update (m3u8, data, &updated))
+ if (!gst_m3u8_update (self, m3u8, data, &updated))
goto out;
if (!updated) {
@@ -1228,3 +1261,43 @@ gst_m3u8_client_get_current_fragment_duration (GstM3U8Client * client)
GST_M3U8_CLIENT_UNLOCK (client);
return dur;
}
+
+gboolean
+gst_m3u8_client_get_seek_range (GstM3U8Client * client, gint64 * start,
+ gint64 * stop)
+{
+ GstClockTime duration = 0;
+ GList *walk;
+ GstM3U8MediaFile *file;
+ guint count;
+
+ g_return_val_if_fail (client != NULL, FALSE);
+
+ GST_M3U8_CLIENT_LOCK (client);
+
+ if (client->current == NULL || client->current->files == NULL) {
+ GST_M3U8_CLIENT_UNLOCK (client);
+ return FALSE;
+ }
+
+ count = g_list_length (client->current->files);
+
+ /* count is used to make sure the seek range is never closer than
+ GST_M3U8_LIVE_MIN_FRAGMENT_DISTANCE fragments from the end of the
+ playlist - see 6.3.3. "Playing the Playlist file" of the HLS draft */
+ for (walk = client->current->files;
+ walk && count >= GST_M3U8_LIVE_MIN_FRAGMENT_DISTANCE; walk = walk->next) {
+ file = walk->data;
+ --count;
+ duration += file->duration;
+ }
+
+ if (duration <= 0) {
+ GST_M3U8_CLIENT_UNLOCK (client);
+ return FALSE;
+ }
+ *start = client->first_file_start;
+ *stop = *start + duration;
+ GST_M3U8_CLIENT_UNLOCK (client);
+ return TRUE;
+}