mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 03:31:05 +00:00
hlsdemux: Expose EXT-X-PROGRAM-DATE-TIME as tags.
This allows an application to use timestamps associated with fragments. Patch by: Thomas Bluemel <tbluemel@control4.com> See: https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/issues/195 Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1417>
This commit is contained in:
parent
8e355d23a1
commit
a2990020b2
5 changed files with 53 additions and 11 deletions
|
@ -1166,6 +1166,13 @@ gst_hls_demux_data_received (GstAdaptiveDemux * demux,
|
||||||
buffer = tmp_buffer;
|
buffer = tmp_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hlsdemux->prog_dt) {
|
||||||
|
gst_adaptive_demux_stream_set_tags (stream,
|
||||||
|
gst_tag_list_new (GST_TAG_DATE_TIME, hlsdemux->prog_dt, NULL));
|
||||||
|
gst_date_time_unref (hlsdemux->prog_dt);
|
||||||
|
hlsdemux->prog_dt = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return gst_hls_demux_handle_buffer (demux, stream, buffer, FALSE);
|
return gst_hls_demux_handle_buffer (demux, stream, buffer, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1247,7 +1254,9 @@ gst_hls_demux_update_fragment_info (GstAdaptiveDemuxStream * stream)
|
||||||
m3u8 = gst_hls_demux_stream_get_m3u8 (hlsdemux_stream);
|
m3u8 = gst_hls_demux_stream_get_m3u8 (hlsdemux_stream);
|
||||||
|
|
||||||
forward = (stream->demux->segment.rate > 0);
|
forward = (stream->demux->segment.rate > 0);
|
||||||
file = gst_m3u8_get_next_fragment (m3u8, forward, &sequence_pos, &discont);
|
file =
|
||||||
|
gst_m3u8_get_next_fragment (m3u8, forward, &sequence_pos,
|
||||||
|
&hlsdemux->prog_dt, &discont);
|
||||||
|
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
GST_INFO_OBJECT (hlsdemux, "This playlist doesn't contain more fragments");
|
GST_INFO_OBJECT (hlsdemux, "This playlist doesn't contain more fragments");
|
||||||
|
@ -1359,6 +1368,12 @@ gst_hls_demux_reset (GstAdaptiveDemux * ademux)
|
||||||
GST_DEBUG_OBJECT (demux, "Streams aware : %d", demux->streams_aware);
|
GST_DEBUG_OBJECT (demux, "Streams aware : %d", demux->streams_aware);
|
||||||
|
|
||||||
gst_hls_demux_clear_all_pending_data (demux);
|
gst_hls_demux_clear_all_pending_data (demux);
|
||||||
|
|
||||||
|
if (demux->prog_dt) {
|
||||||
|
gst_date_time_unref (demux->prog_dt);
|
||||||
|
demux->prog_dt = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
GST_M3U8_CLIENT_UNLOCK (hlsdemux->client);
|
GST_M3U8_CLIENT_UNLOCK (hlsdemux->client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -141,6 +141,8 @@ struct _GstHLSDemux
|
||||||
GHashTable *keys;
|
GHashTable *keys;
|
||||||
GMutex keys_lock;
|
GMutex keys_lock;
|
||||||
|
|
||||||
|
GstDateTime *prog_dt;
|
||||||
|
|
||||||
/* FIXME: check locking, protected automatically by manifest_lock already? */
|
/* FIXME: check locking, protected automatically by manifest_lock already? */
|
||||||
/* The master playlist with the available variant streams */
|
/* The master playlist with the available variant streams */
|
||||||
GstHLSMasterPlaylist *master;
|
GstHLSMasterPlaylist *master;
|
||||||
|
|
|
@ -32,7 +32,8 @@
|
||||||
#define GST_CAT_DEFAULT hls_debug
|
#define GST_CAT_DEFAULT hls_debug
|
||||||
|
|
||||||
static GstM3U8MediaFile *gst_m3u8_media_file_new (gchar * uri,
|
static GstM3U8MediaFile *gst_m3u8_media_file_new (gchar * uri,
|
||||||
gchar * title, GstClockTime duration, guint sequence);
|
gchar * title, GstClockTime duration, guint sequence,
|
||||||
|
GstDateTime * program_dt);
|
||||||
static void gst_m3u8_init_file_unref (GstM3U8InitFile * self);
|
static void gst_m3u8_init_file_unref (GstM3U8InitFile * self);
|
||||||
static gchar *uri_join (const gchar * uri, const gchar * path);
|
static gchar *uri_join (const gchar * uri, const gchar * path);
|
||||||
|
|
||||||
|
@ -116,7 +117,7 @@ gst_m3u8_unref (GstM3U8 * self)
|
||||||
|
|
||||||
static GstM3U8MediaFile *
|
static GstM3U8MediaFile *
|
||||||
gst_m3u8_media_file_new (gchar * uri, gchar * title, GstClockTime duration,
|
gst_m3u8_media_file_new (gchar * uri, gchar * title, GstClockTime duration,
|
||||||
guint sequence)
|
guint sequence, GstDateTime * program_dt)
|
||||||
{
|
{
|
||||||
GstM3U8MediaFile *file;
|
GstM3U8MediaFile *file;
|
||||||
|
|
||||||
|
@ -126,6 +127,7 @@ gst_m3u8_media_file_new (gchar * uri, gchar * title, GstClockTime duration,
|
||||||
file->duration = duration;
|
file->duration = duration;
|
||||||
file->sequence = sequence;
|
file->sequence = sequence;
|
||||||
file->ref_count = 1;
|
file->ref_count = 1;
|
||||||
|
file->program_dt = program_dt;
|
||||||
|
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
@ -150,6 +152,8 @@ gst_m3u8_media_file_unref (GstM3U8MediaFile * self)
|
||||||
g_free (self->title);
|
g_free (self->title);
|
||||||
g_free (self->uri);
|
g_free (self->uri);
|
||||||
g_free (self->key);
|
g_free (self->key);
|
||||||
|
if (self->program_dt)
|
||||||
|
gst_date_time_unref (self->program_dt);
|
||||||
g_free (self);
|
g_free (self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -483,6 +487,7 @@ gboolean
|
||||||
gst_m3u8_update (GstM3U8 * self, gchar * data)
|
gst_m3u8_update (GstM3U8 * self, gchar * data)
|
||||||
{
|
{
|
||||||
gint val;
|
gint val;
|
||||||
|
GstDateTime *program_dt = NULL;
|
||||||
GstClockTime duration;
|
GstClockTime duration;
|
||||||
gchar *title, *end;
|
gchar *title, *end;
|
||||||
gboolean discontinuity = FALSE;
|
gboolean discontinuity = FALSE;
|
||||||
|
@ -558,7 +563,10 @@ gst_m3u8_update (GstM3U8 * self, gchar * data)
|
||||||
data = uri_join (self->base_uri ? self->base_uri : self->uri, data);
|
data = uri_join (self->base_uri ? self->base_uri : self->uri, data);
|
||||||
if (data != NULL) {
|
if (data != NULL) {
|
||||||
GstM3U8MediaFile *file;
|
GstM3U8MediaFile *file;
|
||||||
file = gst_m3u8_media_file_new (data, title, duration, mediasequence++);
|
file =
|
||||||
|
gst_m3u8_media_file_new (data, title, duration,
|
||||||
|
mediasequence++, program_dt);
|
||||||
|
program_dt = NULL;
|
||||||
|
|
||||||
/* set encryption params */
|
/* set encryption params */
|
||||||
file->key = current_key ? g_strdup (current_key) : NULL;
|
file->key = current_key ? g_strdup (current_key) : NULL;
|
||||||
|
@ -647,8 +655,12 @@ gst_m3u8_update (GstM3U8 * self, gchar * data)
|
||||||
self->discont_sequence++;
|
self->discont_sequence++;
|
||||||
discontinuity = TRUE;
|
discontinuity = TRUE;
|
||||||
} else if (g_str_has_prefix (data_ext_x, "PROGRAM-DATE-TIME:")) {
|
} else if (g_str_has_prefix (data_ext_x, "PROGRAM-DATE-TIME:")) {
|
||||||
/* <YYYY-MM-DDThh:mm:ssZ> */
|
if (program_dt)
|
||||||
GST_DEBUG ("FIXME parse date");
|
gst_date_time_unref (program_dt);
|
||||||
|
program_dt = gst_date_time_new_from_iso8601_string (data + 25);
|
||||||
|
if (!program_dt) {
|
||||||
|
GST_WARNING ("Could not parse program date/time");
|
||||||
|
}
|
||||||
} else if (g_str_has_prefix (data_ext_x, "ALLOW-CACHE:")) {
|
} else if (g_str_has_prefix (data_ext_x, "ALLOW-CACHE:")) {
|
||||||
self->allowcache = g_ascii_strcasecmp (data + 19, "YES") == 0;
|
self->allowcache = g_ascii_strcasecmp (data + 19, "YES") == 0;
|
||||||
} else if (g_str_has_prefix (data_ext_x, "KEY:")) {
|
} else if (g_str_has_prefix (data_ext_x, "KEY:")) {
|
||||||
|
@ -767,6 +779,11 @@ gst_m3u8_update (GstM3U8 * self, gchar * data)
|
||||||
g_free (current_key);
|
g_free (current_key);
|
||||||
current_key = NULL;
|
current_key = NULL;
|
||||||
|
|
||||||
|
if (program_dt) {
|
||||||
|
gst_date_time_unref (program_dt);
|
||||||
|
program_dt = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
self->files = g_list_reverse (self->files);
|
self->files = g_list_reverse (self->files);
|
||||||
|
|
||||||
if (last_init_file)
|
if (last_init_file)
|
||||||
|
@ -919,7 +936,8 @@ m3u8_find_next_fragment (GstM3U8 * m3u8, gboolean forward)
|
||||||
|
|
||||||
GstM3U8MediaFile *
|
GstM3U8MediaFile *
|
||||||
gst_m3u8_get_next_fragment (GstM3U8 * m3u8, gboolean forward,
|
gst_m3u8_get_next_fragment (GstM3U8 * m3u8, gboolean forward,
|
||||||
GstClockTime * sequence_position, gboolean * discont)
|
GstClockTime * sequence_position, GstDateTime ** program_dt,
|
||||||
|
gboolean * discont)
|
||||||
{
|
{
|
||||||
GstM3U8MediaFile *file = NULL;
|
GstM3U8MediaFile *file = NULL;
|
||||||
|
|
||||||
|
@ -945,6 +963,11 @@ gst_m3u8_get_next_fragment (GstM3U8 * m3u8, gboolean forward,
|
||||||
|
|
||||||
if (sequence_position)
|
if (sequence_position)
|
||||||
*sequence_position = m3u8->sequence_position;
|
*sequence_position = m3u8->sequence_position;
|
||||||
|
|
||||||
|
if (program_dt)
|
||||||
|
*program_dt =
|
||||||
|
file->program_dt ? gst_date_time_ref (file->program_dt) : NULL;
|
||||||
|
|
||||||
if (discont)
|
if (discont)
|
||||||
*discont = file->discont || (m3u8->sequence != file->sequence);
|
*discont = file->discont || (m3u8->sequence != file->sequence);
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,7 @@ struct _GstM3U8MediaFile
|
||||||
gchar *key;
|
gchar *key;
|
||||||
guint8 iv[16];
|
guint8 iv[16];
|
||||||
gint64 offset, size;
|
gint64 offset, size;
|
||||||
|
GstDateTime *program_dt; /* program date time */
|
||||||
gint ref_count; /* ATOMIC */
|
gint ref_count; /* ATOMIC */
|
||||||
GstM3U8InitFile *init_file; /* Media Initialization (hold ref) */
|
GstM3U8InitFile *init_file; /* Media Initialization (hold ref) */
|
||||||
};
|
};
|
||||||
|
@ -127,6 +128,7 @@ void gst_m3u8_set_uri (GstM3U8 * m3u8,
|
||||||
GstM3U8MediaFile * gst_m3u8_get_next_fragment (GstM3U8 * m3u8,
|
GstM3U8MediaFile * gst_m3u8_get_next_fragment (GstM3U8 * m3u8,
|
||||||
gboolean forward,
|
gboolean forward,
|
||||||
GstClockTime * sequence_position,
|
GstClockTime * sequence_position,
|
||||||
|
GstDateTime ** program_dt,
|
||||||
gboolean * discont);
|
gboolean * discont);
|
||||||
|
|
||||||
gboolean gst_m3u8_has_next_fragment (GstM3U8 * m3u8,
|
gboolean gst_m3u8_has_next_fragment (GstM3U8 * m3u8,
|
||||||
|
|
|
@ -572,7 +572,7 @@ GST_START_TEST (test_live_playlist_rotated)
|
||||||
|
|
||||||
ret = gst_m3u8_update (pl, g_strdup (LIVE_ROTATED_PLAYLIST));
|
ret = gst_m3u8_update (pl, g_strdup (LIVE_ROTATED_PLAYLIST));
|
||||||
assert_equals_int (ret, TRUE);
|
assert_equals_int (ret, TRUE);
|
||||||
file = gst_m3u8_get_next_fragment (pl, TRUE, NULL, NULL);
|
file = gst_m3u8_get_next_fragment (pl, TRUE, NULL, NULL, NULL);
|
||||||
fail_unless (file != NULL);
|
fail_unless (file != NULL);
|
||||||
gst_m3u8_media_file_unref (file);
|
gst_m3u8_media_file_unref (file);
|
||||||
|
|
||||||
|
@ -805,7 +805,7 @@ GST_START_TEST (test_get_next_fragment)
|
||||||
pl = master->default_variant->m3u8;
|
pl = master->default_variant->m3u8;
|
||||||
|
|
||||||
/* Check the next fragment */
|
/* Check the next fragment */
|
||||||
mf = gst_m3u8_get_next_fragment (pl, TRUE, ×tamp, &discontinuous);
|
mf = gst_m3u8_get_next_fragment (pl, TRUE, ×tamp, NULL, &discontinuous);
|
||||||
fail_unless (mf != NULL);
|
fail_unless (mf != NULL);
|
||||||
assert_equals_int (discontinuous, FALSE);
|
assert_equals_int (discontinuous, FALSE);
|
||||||
assert_equals_string (mf->uri, "http://media.example.com/all.ts");
|
assert_equals_string (mf->uri, "http://media.example.com/all.ts");
|
||||||
|
@ -818,7 +818,7 @@ GST_START_TEST (test_get_next_fragment)
|
||||||
gst_m3u8_advance_fragment (pl, TRUE);
|
gst_m3u8_advance_fragment (pl, TRUE);
|
||||||
|
|
||||||
/* Check next media segments */
|
/* Check next media segments */
|
||||||
mf = gst_m3u8_get_next_fragment (pl, TRUE, ×tamp, &discontinuous);
|
mf = gst_m3u8_get_next_fragment (pl, TRUE, ×tamp, NULL, &discontinuous);
|
||||||
fail_unless (mf != NULL);
|
fail_unless (mf != NULL);
|
||||||
assert_equals_int (discontinuous, FALSE);
|
assert_equals_int (discontinuous, FALSE);
|
||||||
assert_equals_string (mf->uri, "http://media.example.com/all.ts");
|
assert_equals_string (mf->uri, "http://media.example.com/all.ts");
|
||||||
|
@ -831,7 +831,7 @@ GST_START_TEST (test_get_next_fragment)
|
||||||
gst_m3u8_advance_fragment (pl, TRUE);
|
gst_m3u8_advance_fragment (pl, TRUE);
|
||||||
|
|
||||||
/* Check next media segments */
|
/* Check next media segments */
|
||||||
mf = gst_m3u8_get_next_fragment (pl, TRUE, ×tamp, &discontinuous);
|
mf = gst_m3u8_get_next_fragment (pl, TRUE, ×tamp, NULL, &discontinuous);
|
||||||
assert_equals_int (discontinuous, FALSE);
|
assert_equals_int (discontinuous, FALSE);
|
||||||
assert_equals_string (mf->uri, "http://media.example.com/all.ts");
|
assert_equals_string (mf->uri, "http://media.example.com/all.ts");
|
||||||
assert_equals_uint64 (timestamp, 20 * GST_SECOND);
|
assert_equals_uint64 (timestamp, 20 * GST_SECOND);
|
||||||
|
|
Loading…
Reference in a new issue