mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-18 14:26:43 +00:00
hlsdemux2: Add parsing of partial segments
Add partial segments to each media segment, and potentially create a trailing dummy segment if there are partial segments at the end of the playlist Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3883>
This commit is contained in:
parent
fac7177354
commit
07f51396af
2 changed files with 233 additions and 6 deletions
|
@ -112,10 +112,32 @@ gst_m3u8_media_segment_unref (GstM3U8MediaSegment * self)
|
||||||
g_free (self->key);
|
g_free (self->key);
|
||||||
if (self->datetime)
|
if (self->datetime)
|
||||||
g_date_time_unref (self->datetime);
|
g_date_time_unref (self->datetime);
|
||||||
|
if (self->partial_segments)
|
||||||
|
g_ptr_array_free (self->partial_segments, TRUE);
|
||||||
g_free (self);
|
g_free (self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GstM3U8PartialSegment *
|
||||||
|
gst_m3u8_partial_segment_ref (GstM3U8PartialSegment * part)
|
||||||
|
{
|
||||||
|
g_assert (part != NULL && part->ref_count > 0);
|
||||||
|
|
||||||
|
g_atomic_int_add (&part->ref_count, 1);
|
||||||
|
return part;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_m3u8_partial_segment_unref (GstM3U8PartialSegment * part)
|
||||||
|
{
|
||||||
|
g_return_if_fail (part != NULL && part->ref_count > 0);
|
||||||
|
|
||||||
|
if (g_atomic_int_dec_and_test (&part->ref_count)) {
|
||||||
|
g_free (part->uri);
|
||||||
|
g_free (part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static GstM3U8InitFile *
|
static GstM3U8InitFile *
|
||||||
gst_m3u8_init_file_new (gchar * uri, gint64 size, gint64 offset)
|
gst_m3u8_init_file_new (gchar * uri, gint64 size, gint64 offset)
|
||||||
{
|
{
|
||||||
|
@ -343,6 +365,7 @@ gst_hls_media_playlist_new (const gchar * uri, const gchar * base_uri)
|
||||||
m3u8->version = 1;
|
m3u8->version = 1;
|
||||||
m3u8->type = GST_HLS_PLAYLIST_TYPE_UNDEFINED;
|
m3u8->type = GST_HLS_PLAYLIST_TYPE_UNDEFINED;
|
||||||
m3u8->targetduration = GST_CLOCK_TIME_NONE;
|
m3u8->targetduration = GST_CLOCK_TIME_NONE;
|
||||||
|
m3u8->partial_targetduration = GST_CLOCK_TIME_NONE;
|
||||||
m3u8->media_sequence = 0;
|
m3u8->media_sequence = 0;
|
||||||
m3u8->discont_sequence = 0;
|
m3u8->discont_sequence = 0;
|
||||||
m3u8->endlist = FALSE;
|
m3u8->endlist = FALSE;
|
||||||
|
@ -377,6 +400,8 @@ gst_hls_media_playlist_dump (GstHLSMediaPlaylist * self)
|
||||||
|
|
||||||
GST_DEBUG ("targetduration : %" GST_TIME_FORMAT,
|
GST_DEBUG ("targetduration : %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (self->targetduration));
|
GST_TIME_ARGS (self->targetduration));
|
||||||
|
GST_DEBUG ("partial segment targetduration : %" GST_TIME_FORMAT,
|
||||||
|
GST_TIME_ARGS (self->partial_targetduration));
|
||||||
GST_DEBUG ("media_sequence : %" G_GINT64_FORMAT, self->media_sequence);
|
GST_DEBUG ("media_sequence : %" G_GINT64_FORMAT, self->media_sequence);
|
||||||
GST_DEBUG ("discont_sequence : %" G_GINT64_FORMAT, self->discont_sequence);
|
GST_DEBUG ("discont_sequence : %" G_GINT64_FORMAT, self->discont_sequence);
|
||||||
|
|
||||||
|
@ -398,6 +423,7 @@ gst_hls_media_playlist_dump (GstHLSMediaPlaylist * self)
|
||||||
|
|
||||||
GST_DEBUG (" sequence:%" G_GINT64_FORMAT " discont_sequence:%"
|
GST_DEBUG (" sequence:%" G_GINT64_FORMAT " discont_sequence:%"
|
||||||
G_GINT64_FORMAT, segment->sequence, segment->discont_sequence);
|
G_GINT64_FORMAT, segment->sequence, segment->discont_sequence);
|
||||||
|
GST_DEBUG (" partial only: %s", segment->partial_only ? "YES" : "NO");
|
||||||
GST_DEBUG (" stream_time : %" GST_STIME_FORMAT,
|
GST_DEBUG (" stream_time : %" GST_STIME_FORMAT,
|
||||||
GST_STIME_ARGS (segment->stream_time));
|
GST_STIME_ARGS (segment->stream_time));
|
||||||
GST_DEBUG (" duration : %" GST_TIME_FORMAT,
|
GST_DEBUG (" duration : %" GST_TIME_FORMAT,
|
||||||
|
@ -412,6 +438,25 @@ gst_hls_media_playlist_dump (GstHLSMediaPlaylist * self)
|
||||||
}
|
}
|
||||||
GST_DEBUG (" uri : %s %" G_GUINT64_FORMAT " %" G_GINT64_FORMAT,
|
GST_DEBUG (" uri : %s %" G_GUINT64_FORMAT " %" G_GINT64_FORMAT,
|
||||||
segment->uri, segment->offset, segment->size);
|
segment->uri, segment->offset, segment->size);
|
||||||
|
|
||||||
|
GST_DEBUG (" is gap : %s", segment->is_gap ? "YES" : "NO");
|
||||||
|
|
||||||
|
if (segment->partial_segments != NULL) {
|
||||||
|
guint part_idx;
|
||||||
|
for (part_idx = 0; part_idx < segment->partial_segments->len; part_idx++) {
|
||||||
|
GstM3U8PartialSegment *part =
|
||||||
|
g_ptr_array_index (segment->partial_segments, part_idx);
|
||||||
|
GST_DEBUG (" partial segment %u:", part_idx);
|
||||||
|
GST_DEBUG (" uri : %s %" G_GUINT64_FORMAT " %"
|
||||||
|
G_GINT64_FORMAT, part->uri, part->offset, part->size);
|
||||||
|
GST_DEBUG (" stream_time : %" GST_STIME_FORMAT,
|
||||||
|
GST_STIME_ARGS (part->stream_time));
|
||||||
|
GST_DEBUG (" duration : %" GST_TIME_FORMAT,
|
||||||
|
GST_TIME_ARGS (part->duration));
|
||||||
|
GST_DEBUG (" is gap : %s", part->is_gap ? "YES" : "NO");
|
||||||
|
GST_DEBUG (" independent : %s", part->independent ? "YES" : "NO");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -479,6 +524,62 @@ gst_hls_media_playlist_postprocess_pdt (GstHLSMediaPlaylist * self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstM3U8PartialSegment *
|
||||||
|
gst_m3u8_parse_partial_segment (gchar * data, const gchar * base_uri)
|
||||||
|
{
|
||||||
|
gchar *v, *a;
|
||||||
|
gboolean have_duration = FALSE;
|
||||||
|
GstM3U8PartialSegment *part = g_new0 (GstM3U8PartialSegment, 1);
|
||||||
|
|
||||||
|
part->ref_count = 1;
|
||||||
|
part->stream_time = GST_CLOCK_STIME_NONE;
|
||||||
|
part->size = -1;
|
||||||
|
|
||||||
|
while (data != NULL && parse_attributes (&data, &a, &v)) {
|
||||||
|
if (strcmp (a, "URI") == 0) {
|
||||||
|
g_free (part->uri);
|
||||||
|
part->uri = uri_join (base_uri, v);
|
||||||
|
} else if (strcmp (a, "DURATION") == 0) {
|
||||||
|
if (!time_from_double_in_string (v, NULL, &part->duration)) {
|
||||||
|
GST_WARNING ("Can't read EXT-X-PART duration");
|
||||||
|
goto malformed_line;
|
||||||
|
}
|
||||||
|
have_duration = TRUE;
|
||||||
|
} else if (strcmp (a, "INDEPENDENT") == 0) {
|
||||||
|
part->independent = g_ascii_strcasecmp (v, "yes") == 0;
|
||||||
|
} else if (strcmp (a, "GAP") == 0) {
|
||||||
|
part->is_gap = g_ascii_strcasecmp (v, "yes") == 0;
|
||||||
|
} else if (strcmp (a, "BYTERANGE") == 0) {
|
||||||
|
if (int64_from_string (v, &v, &part->size)) {
|
||||||
|
goto malformed_line;
|
||||||
|
}
|
||||||
|
if (*v == '@' && !int64_from_string (v + 1, &v, &part->offset)) {
|
||||||
|
goto malformed_line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (part->uri == NULL || !have_duration) {
|
||||||
|
goto required_attributes_missing;
|
||||||
|
}
|
||||||
|
|
||||||
|
return part;
|
||||||
|
|
||||||
|
required_attributes_missing:
|
||||||
|
{
|
||||||
|
GST_WARNING
|
||||||
|
("EXT-X-PART description is missing required URI or DURATION attributes");
|
||||||
|
gst_m3u8_partial_segment_unref (part);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
malformed_line:
|
||||||
|
{
|
||||||
|
GST_WARNING ("Invalid EXT-X-PART entry in playlist");
|
||||||
|
gst_m3u8_partial_segment_unref (part);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse and create a new GstHLSMediaPlaylist */
|
/* Parse and create a new GstHLSMediaPlaylist */
|
||||||
GstHLSMediaPlaylist *
|
GstHLSMediaPlaylist *
|
||||||
gst_hls_media_playlist_parse (gchar * data, const gchar * uri,
|
gst_hls_media_playlist_parse (gchar * data, const gchar * uri,
|
||||||
|
@ -487,7 +588,7 @@ gst_hls_media_playlist_parse (gchar * data, const gchar * uri,
|
||||||
gchar *input_data = data;
|
gchar *input_data = data;
|
||||||
GstHLSMediaPlaylist *self;
|
GstHLSMediaPlaylist *self;
|
||||||
gint val;
|
gint val;
|
||||||
GstClockTime duration;
|
GstClockTime duration, partial_duration;
|
||||||
gchar *title, *end;
|
gchar *title, *end;
|
||||||
gboolean discontinuity = FALSE;
|
gboolean discontinuity = FALSE;
|
||||||
gchar *current_key = NULL;
|
gchar *current_key = NULL;
|
||||||
|
@ -499,6 +600,7 @@ gst_hls_media_playlist_parse (gchar * data, const gchar * uri,
|
||||||
GDateTime *date_time = NULL;
|
GDateTime *date_time = NULL;
|
||||||
GstM3U8InitFile *last_init_file = NULL;
|
GstM3U8InitFile *last_init_file = NULL;
|
||||||
GstM3U8MediaSegment *previous = NULL;
|
GstM3U8MediaSegment *previous = NULL;
|
||||||
|
GPtrArray *partial_segments = NULL;
|
||||||
gboolean is_gap = FALSE;
|
gboolean is_gap = FALSE;
|
||||||
|
|
||||||
GST_LOG ("uri: %s", uri);
|
GST_LOG ("uri: %s", uri);
|
||||||
|
@ -523,6 +625,7 @@ gst_hls_media_playlist_parse (gchar * data, const gchar * uri,
|
||||||
self->last_data = g_strdup (data);
|
self->last_data = g_strdup (data);
|
||||||
|
|
||||||
duration = 0;
|
duration = 0;
|
||||||
|
partial_duration = 0;
|
||||||
title = NULL;
|
title = NULL;
|
||||||
data += 7;
|
data += 7;
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
|
@ -552,17 +655,22 @@ gst_hls_media_playlist_parse (gchar * data, const gchar * uri,
|
||||||
data = NULL;
|
data = NULL;
|
||||||
date_time = NULL;
|
date_time = NULL;
|
||||||
duration = 0;
|
duration = 0;
|
||||||
|
partial_duration = 0;
|
||||||
g_free (title);
|
g_free (title);
|
||||||
title = NULL;
|
title = NULL;
|
||||||
discontinuity = FALSE;
|
discontinuity = FALSE;
|
||||||
size = offset = -1;
|
size = offset = -1;
|
||||||
is_gap = FALSE;
|
is_gap = FALSE;
|
||||||
|
if (partial_segments != NULL) {
|
||||||
|
g_ptr_array_free (partial_segments, TRUE);
|
||||||
|
partial_segments = NULL;
|
||||||
|
}
|
||||||
goto next_line;
|
goto next_line;
|
||||||
}
|
}
|
||||||
if (data != NULL) {
|
if (data != NULL) {
|
||||||
GstM3U8MediaSegment *file;
|
GstM3U8MediaSegment *file;
|
||||||
/* We can finally create the segment */
|
/* We can finally create the segment */
|
||||||
/* The disconinuity sequence number is only stored if the header has
|
/* The discontinuity sequence number is only stored if the header has
|
||||||
* EXT-X-DISCONTINUITY-SEQUENCE present. */
|
* EXT-X-DISCONTINUITY-SEQUENCE present. */
|
||||||
file =
|
file =
|
||||||
gst_m3u8_media_segment_new (data, title, duration, mediasequence++,
|
gst_m3u8_media_segment_new (data, title, duration, mediasequence++,
|
||||||
|
@ -593,8 +701,12 @@ gst_hls_media_playlist_parse (gchar * data, const gchar * uri,
|
||||||
if (last_init_file)
|
if (last_init_file)
|
||||||
file->init_file = gst_m3u8_init_file_ref (last_init_file);
|
file->init_file = gst_m3u8_init_file_ref (last_init_file);
|
||||||
|
|
||||||
|
file->partial_segments = partial_segments;
|
||||||
|
partial_segments = NULL;
|
||||||
|
|
||||||
date_time = NULL; /* Ownership was passed to the segment */
|
date_time = NULL; /* Ownership was passed to the segment */
|
||||||
duration = 0;
|
duration = 0;
|
||||||
|
partial_duration = 0;
|
||||||
title = NULL; /* Ownership was passed to the segment */
|
title = NULL; /* Ownership was passed to the segment */
|
||||||
discontinuity = FALSE;
|
discontinuity = FALSE;
|
||||||
size = offset = -1;
|
size = offset = -1;
|
||||||
|
@ -763,6 +875,36 @@ gst_hls_media_playlist_parse (gchar * data, const gchar * uri,
|
||||||
}
|
}
|
||||||
} else if (g_str_has_prefix (data_ext_x, "GAP:")) {
|
} else if (g_str_has_prefix (data_ext_x, "GAP:")) {
|
||||||
is_gap = TRUE;
|
is_gap = TRUE;
|
||||||
|
} else if (g_str_has_prefix (data_ext_x, "PART:")) {
|
||||||
|
GstM3U8PartialSegment *part = NULL;
|
||||||
|
|
||||||
|
part =
|
||||||
|
gst_m3u8_parse_partial_segment (data + strlen ("#EXT-X-PART:"),
|
||||||
|
self->base_uri ? self->base_uri : self->uri);
|
||||||
|
if (part == NULL)
|
||||||
|
goto next_line;
|
||||||
|
|
||||||
|
if (partial_segments == NULL) {
|
||||||
|
partial_segments = g_ptr_array_new_full (2,
|
||||||
|
(GDestroyNotify) gst_m3u8_partial_segment_unref);
|
||||||
|
}
|
||||||
|
g_ptr_array_add (partial_segments, part);
|
||||||
|
partial_duration += part->duration;
|
||||||
|
|
||||||
|
} else if (g_str_has_prefix (data_ext_x, "PART-INF:")) {
|
||||||
|
gchar *v, *a;
|
||||||
|
|
||||||
|
data += strlen ("#EXT-X-PART-INF:");
|
||||||
|
|
||||||
|
while (data != NULL && parse_attributes (&data, &a, &v)) {
|
||||||
|
if (strcmp (a, "PART-TARGET") == 0) {
|
||||||
|
if (!time_from_double_in_string (v, NULL,
|
||||||
|
&self->partial_targetduration)) {
|
||||||
|
GST_WARNING ("Invalid PART-TARGET");
|
||||||
|
goto next_line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
GST_LOG ("Ignored line: %s", data);
|
GST_LOG ("Ignored line: %s", data);
|
||||||
}
|
}
|
||||||
|
@ -777,6 +919,59 @@ gst_hls_media_playlist_parse (gchar * data, const gchar * uri,
|
||||||
data = g_utf8_next_char (end); /* skip \n */
|
data = g_utf8_next_char (end); /* skip \n */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If there are trailing partial segments at the end,
|
||||||
|
* create a dummy segment to hold them */
|
||||||
|
if (partial_segments != NULL) {
|
||||||
|
GstM3U8MediaSegment *file;
|
||||||
|
GST_DEBUG ("Creating dummy segment for trailing partial segments");
|
||||||
|
|
||||||
|
/* The discontinuity sequence number is only stored if the header has
|
||||||
|
* EXT-X-DISCONTINUITY-SEQUENCE present. */
|
||||||
|
file =
|
||||||
|
gst_m3u8_media_segment_new (NULL, title, partial_duration,
|
||||||
|
mediasequence++, dsn, size, offset);
|
||||||
|
|
||||||
|
file->partial_only = TRUE;
|
||||||
|
|
||||||
|
self->duration += partial_duration;
|
||||||
|
|
||||||
|
file->is_gap = is_gap;
|
||||||
|
|
||||||
|
/* set encryption params */
|
||||||
|
if (current_key != NULL) {
|
||||||
|
file->key = g_strdup (current_key);
|
||||||
|
if (have_iv) {
|
||||||
|
memcpy (file->iv, iv, sizeof (iv));
|
||||||
|
} else {
|
||||||
|
/* An EXT-X-KEY tag with a KEYFORMAT of "identity" that does
|
||||||
|
* not have an IV attribute indicates that the Media Sequence
|
||||||
|
* Number is to be used as the IV when decrypting a Media
|
||||||
|
* Segment, by putting its big-endian binary representation
|
||||||
|
* into a 16-octet (128-bit) buffer and padding (on the left)
|
||||||
|
* with zeros. */
|
||||||
|
guint8 *iv = file->iv + 12;
|
||||||
|
GST_WRITE_UINT32_BE (iv, file->sequence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file->datetime = date_time;
|
||||||
|
file->discont = discontinuity;
|
||||||
|
if (last_init_file)
|
||||||
|
file->init_file = gst_m3u8_init_file_ref (last_init_file);
|
||||||
|
|
||||||
|
file->partial_segments = partial_segments;
|
||||||
|
partial_segments = NULL;
|
||||||
|
|
||||||
|
date_time = NULL; /* Ownership was passed to the partial segment */
|
||||||
|
duration = 0;
|
||||||
|
partial_duration = 0;
|
||||||
|
title = NULL; /* Ownership was passed to the partial segment */
|
||||||
|
discontinuity = FALSE;
|
||||||
|
size = offset = -1;
|
||||||
|
g_ptr_array_add (self->segments, file);
|
||||||
|
previous = file;
|
||||||
|
}
|
||||||
|
|
||||||
/* Clean up date that wasn't freed / handed to a segment */
|
/* Clean up date that wasn't freed / handed to a segment */
|
||||||
g_free (current_key);
|
g_free (current_key);
|
||||||
current_key = NULL;
|
current_key = NULL;
|
||||||
|
@ -1445,7 +1640,7 @@ gst_hls_media_playlist_is_live (GstHLSMediaPlaylist * m3u8)
|
||||||
return is_live;
|
return is_live;
|
||||||
}
|
}
|
||||||
|
|
||||||
gchar *
|
static gchar *
|
||||||
uri_join (const gchar * uri1, const gchar * uri2)
|
uri_join (const gchar * uri1, const gchar * uri2)
|
||||||
{
|
{
|
||||||
gchar *uri_copy, *tmp, *ret = NULL;
|
gchar *uri_copy, *tmp, *ret = NULL;
|
||||||
|
@ -1617,7 +1812,7 @@ gst_hls_rendition_stream_type_get_name (GstHLSRenditionStreamType mtype)
|
||||||
return nicks[mtype];
|
return nicks[mtype];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns unquoted copy of string */
|
/* returns copy of string with surrounding quotation marks removed */
|
||||||
static gchar *
|
static gchar *
|
||||||
gst_m3u8_unquote (const gchar * str)
|
gst_m3u8_unquote (const gchar * str)
|
||||||
{
|
{
|
||||||
|
|
|
@ -35,6 +35,7 @@ G_BEGIN_DECLS
|
||||||
typedef struct _GstHLSMediaPlaylist GstHLSMediaPlaylist;
|
typedef struct _GstHLSMediaPlaylist GstHLSMediaPlaylist;
|
||||||
typedef struct _GstHLSTimeMap GstHLSTimeMap;
|
typedef struct _GstHLSTimeMap GstHLSTimeMap;
|
||||||
typedef struct _GstM3U8MediaSegment GstM3U8MediaSegment;
|
typedef struct _GstM3U8MediaSegment GstM3U8MediaSegment;
|
||||||
|
typedef struct _GstM3U8PartialSegment GstM3U8PartialSegment;
|
||||||
typedef struct _GstM3U8InitFile GstM3U8InitFile;
|
typedef struct _GstM3U8InitFile GstM3U8InitFile;
|
||||||
typedef struct _GstHLSRenditionStream GstHLSRenditionStream;
|
typedef struct _GstHLSRenditionStream GstHLSRenditionStream;
|
||||||
typedef struct _GstM3U8Client GstM3U8Client;
|
typedef struct _GstM3U8Client GstM3U8Client;
|
||||||
|
@ -43,6 +44,7 @@ typedef struct _GstHLSMasterPlaylist GstHLSMasterPlaylist;
|
||||||
|
|
||||||
#define GST_HLS_MEDIA_PLAYLIST(m) ((GstHLSMediaPlaylist*)m)
|
#define GST_HLS_MEDIA_PLAYLIST(m) ((GstHLSMediaPlaylist*)m)
|
||||||
#define GST_M3U8_MEDIA_SEGMENT(f) ((GstM3U8MediaSegment*)f)
|
#define GST_M3U8_MEDIA_SEGMENT(f) ((GstM3U8MediaSegment*)f)
|
||||||
|
#define GST_M3U8_PARTIAL_SEGMENT(p) ((GstM3U8PartialSegment*)p)
|
||||||
|
|
||||||
#define GST_HLS_MEDIA_PLAYLIST_LOCK(m) g_mutex_lock (&m->lock);
|
#define GST_HLS_MEDIA_PLAYLIST_LOCK(m) g_mutex_lock (&m->lock);
|
||||||
#define GST_HLS_MEDIA_PLAYLIST_UNLOCK(m) g_mutex_unlock (&m->lock);
|
#define GST_HLS_MEDIA_PLAYLIST_UNLOCK(m) g_mutex_unlock (&m->lock);
|
||||||
|
@ -82,6 +84,8 @@ struct _GstHLSMediaPlaylist
|
||||||
|
|
||||||
/* Media Playlist Tags */
|
/* Media Playlist Tags */
|
||||||
GstClockTime targetduration; /* EXT-X-TARGETDURATION, default GST_CLOCK_TIME_NONE */
|
GstClockTime targetduration; /* EXT-X-TARGETDURATION, default GST_CLOCK_TIME_NONE */
|
||||||
|
GstClockTime partial_targetduration; /* EXT-X-PART-INF, default GST_CLOCK_TIME_NONE */
|
||||||
|
|
||||||
gint64 media_sequence; /* EXT-X-MEDIA-SEQUENCE, MSN of the first Media
|
gint64 media_sequence; /* EXT-X-MEDIA-SEQUENCE, MSN of the first Media
|
||||||
Segment in the playlist. */
|
Segment in the playlist. */
|
||||||
gint64 discont_sequence; /* EXT-X-DISCONTINUITY-SEQUENCE. Default : 0 */
|
gint64 discont_sequence; /* EXT-X-DISCONTINUITY-SEQUENCE. Default : 0 */
|
||||||
|
@ -127,6 +131,31 @@ GstHLSMediaPlaylist * gst_hls_media_playlist_ref (GstHLSMediaPlaylist * m3u8);
|
||||||
|
|
||||||
void gst_hls_media_playlist_unref (GstHLSMediaPlaylist * m3u8);
|
void gst_hls_media_playlist_unref (GstHLSMediaPlaylist * m3u8);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstM3U8PartialSegment:
|
||||||
|
*
|
||||||
|
* Official term in RFC : "Partial Segment"
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct _GstM3U8PartialSegment
|
||||||
|
{
|
||||||
|
gboolean is_gap; /* TRUE if this part is a gap */
|
||||||
|
gboolean independent; /* TRUE if there is an I-frame in the partial segment */
|
||||||
|
gchar *uri;
|
||||||
|
gint64 offset, size;
|
||||||
|
|
||||||
|
GstClockTimeDiff stream_time; /* Computed stream time */
|
||||||
|
GstClockTime duration;
|
||||||
|
|
||||||
|
gint ref_count; /* ATOMIC */
|
||||||
|
};
|
||||||
|
|
||||||
|
GstM3U8PartialSegment *
|
||||||
|
gst_m3u8_partial_segment_ref (GstM3U8PartialSegment *part);
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_m3u8_partial_segment_unref (GstM3U8PartialSegment *part);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GstM3U8MediaSegment:
|
* GstM3U8MediaSegment:
|
||||||
*
|
*
|
||||||
|
@ -137,6 +166,7 @@ void gst_hls_media_playlist_unref (GstHLSMediaPlaylist * m3u8);
|
||||||
struct _GstM3U8MediaSegment
|
struct _GstM3U8MediaSegment
|
||||||
{
|
{
|
||||||
gboolean is_gap; /* TRUE if EXT-X-GAP was present for this segment */
|
gboolean is_gap; /* TRUE if EXT-X-GAP was present for this segment */
|
||||||
|
gboolean partial_only; /* TRUE if this is the last segment in a playlist consisting of only EXT-X-PART and no full URL */
|
||||||
|
|
||||||
gchar *title;
|
gchar *title;
|
||||||
GstClockTimeDiff stream_time; /* Computed stream time */
|
GstClockTimeDiff stream_time; /* Computed stream time */
|
||||||
|
@ -148,9 +178,12 @@ struct _GstM3U8MediaSegment
|
||||||
gchar *key;
|
gchar *key;
|
||||||
guint8 iv[16];
|
guint8 iv[16];
|
||||||
gint64 offset, size;
|
gint64 offset, size;
|
||||||
gint ref_count; /* ATOMIC */
|
|
||||||
GstM3U8InitFile *init_file; /* Media Initialization (hold ref) */
|
GstM3U8InitFile *init_file; /* Media Initialization (hold ref) */
|
||||||
GDateTime *datetime; /* EXT-X-PROGRAM-DATE-TIME */
|
GDateTime *datetime; /* EXT-X-PROGRAM-DATE-TIME */
|
||||||
|
|
||||||
|
GPtrArray *partial_segments; /* If there are Partial Segments for this Media Segment */
|
||||||
|
|
||||||
|
gint ref_count; /* ATOMIC */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstM3U8InitFile
|
struct _GstM3U8InitFile
|
||||||
|
@ -170,7 +203,6 @@ gst_m3u8_media_segment_ref (GstM3U8MediaSegment * mfile);
|
||||||
void
|
void
|
||||||
gst_m3u8_media_segment_unref (GstM3U8MediaSegment * mfile);
|
gst_m3u8_media_segment_unref (GstM3U8MediaSegment * mfile);
|
||||||
|
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gst_hls_media_playlist_has_same_data (GstHLSMediaPlaylist * m3u8,
|
gst_hls_media_playlist_has_same_data (GstHLSMediaPlaylist * m3u8,
|
||||||
gchar * playlist_data);
|
gchar * playlist_data);
|
||||||
|
|
Loading…
Reference in a new issue