mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
hlsdemux: Fix accessing invalidated memory
In gst_hls_demux_get_next_fragment() the next fragment URI gets stored in next_fragment_uri, but the gst_hls_demux_updates_loop() can at any time update the playlist, rendering this string invalid. Therefore, any data (like key, iv, URIs) that is taken from a GstM3U8Client needs to be copied. In addition, accessing the internals of a GstM3U8Client requires locking. https://bugzilla.gnome.org/show_bug.cgi?id=737793
This commit is contained in:
parent
a2b82ba541
commit
c87835a79f
4 changed files with 113 additions and 56 deletions
107
ext/hls/gsthlsdemux.c
Normal file → Executable file
107
ext/hls/gsthlsdemux.c
Normal file → Executable file
|
@ -588,7 +588,7 @@ gst_hls_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||||
|
|
||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
case GST_EVENT_EOS:{
|
case GST_EVENT_EOS:{
|
||||||
gchar *playlist = NULL;
|
gchar *uri, *playlist = NULL;
|
||||||
|
|
||||||
if (demux->playlist == NULL) {
|
if (demux->playlist == NULL) {
|
||||||
GST_WARNING_OBJECT (demux, "Received EOS without a playlist.");
|
GST_WARNING_OBJECT (demux, "Received EOS without a playlist.");
|
||||||
|
@ -602,7 +602,7 @@ gst_hls_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||||
ret = gst_pad_peer_query (demux->sinkpad, query);
|
ret = gst_pad_peer_query (demux->sinkpad, query);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
gboolean permanent;
|
gboolean permanent;
|
||||||
gchar *uri, *redirect_uri;
|
gchar *redirect_uri;
|
||||||
|
|
||||||
gst_query_parse_uri (query, &uri);
|
gst_query_parse_uri (query, &uri);
|
||||||
gst_query_parse_uri_redirection (query, &redirect_uri);
|
gst_query_parse_uri_redirection (query, &redirect_uri);
|
||||||
|
@ -618,16 +618,17 @@ gst_hls_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||||
}
|
}
|
||||||
gst_query_unref (query);
|
gst_query_unref (query);
|
||||||
|
|
||||||
|
uri = gst_m3u8_client_get_uri (demux->client);
|
||||||
gst_element_post_message (GST_ELEMENT_CAST (demux),
|
gst_element_post_message (GST_ELEMENT_CAST (demux),
|
||||||
gst_message_new_element (GST_OBJECT_CAST (demux),
|
gst_message_new_element (GST_OBJECT_CAST (demux),
|
||||||
gst_structure_new (STATISTICS_MESSAGE_NAME,
|
gst_structure_new (STATISTICS_MESSAGE_NAME,
|
||||||
"manifest-uri", G_TYPE_STRING,
|
"manifest-uri", G_TYPE_STRING, uri,
|
||||||
gst_m3u8_client_get_uri (demux->client), "uri", G_TYPE_STRING,
|
"uri", G_TYPE_STRING, uri,
|
||||||
gst_m3u8_client_get_uri (demux->client),
|
|
||||||
"manifest-download-start", GST_TYPE_CLOCK_TIME,
|
"manifest-download-start", GST_TYPE_CLOCK_TIME,
|
||||||
GST_CLOCK_TIME_NONE,
|
GST_CLOCK_TIME_NONE,
|
||||||
"manifest-download-stop", GST_TYPE_CLOCK_TIME,
|
"manifest-download-stop", GST_TYPE_CLOCK_TIME,
|
||||||
gst_util_get_timestamp (), NULL)));
|
gst_util_get_timestamp (), NULL)));
|
||||||
|
g_free (uri);
|
||||||
|
|
||||||
playlist = gst_hls_src_buf_to_utf8_playlist (demux->playlist);
|
playlist = gst_hls_src_buf_to_utf8_playlist (demux->playlist);
|
||||||
demux->playlist = NULL;
|
demux->playlist = NULL;
|
||||||
|
@ -694,9 +695,14 @@ gst_hls_demux_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
|
||||||
}
|
}
|
||||||
case GST_QUERY_URI:
|
case GST_QUERY_URI:
|
||||||
if (hlsdemux->client) {
|
if (hlsdemux->client) {
|
||||||
|
gchar *uri;
|
||||||
|
|
||||||
/* FIXME: Do we answer with the variant playlist, with the current
|
/* FIXME: Do we answer with the variant playlist, with the current
|
||||||
* playlist or the the uri of the least downlowaded fragment? */
|
* playlist or the the uri of the least downlowaded fragment? */
|
||||||
gst_query_set_uri (query, gst_m3u8_client_get_uri (hlsdemux->client));
|
uri = gst_m3u8_client_get_uri (hlsdemux->client);
|
||||||
|
gst_query_set_uri (query, uri);
|
||||||
|
g_free (uri);
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1405,8 +1411,14 @@ gst_hls_demux_reset (GstHLSDemux * demux, gboolean dispose)
|
||||||
if (demux->pending_buffer)
|
if (demux->pending_buffer)
|
||||||
gst_buffer_unref (demux->pending_buffer);
|
gst_buffer_unref (demux->pending_buffer);
|
||||||
demux->pending_buffer = NULL;
|
demux->pending_buffer = NULL;
|
||||||
demux->current_key = NULL;
|
if (demux->current_key) {
|
||||||
demux->current_iv = NULL;
|
g_free (demux->current_key);
|
||||||
|
demux->current_key = NULL;
|
||||||
|
}
|
||||||
|
if (demux->current_iv) {
|
||||||
|
g_free (demux->current_iv);
|
||||||
|
demux->current_iv = NULL;
|
||||||
|
}
|
||||||
gst_hls_demux_decrypt_end (demux);
|
gst_hls_demux_decrypt_end (demux);
|
||||||
|
|
||||||
demux->current_download_rate = -1;
|
demux->current_download_rate = -1;
|
||||||
|
@ -1575,25 +1587,28 @@ gst_hls_demux_update_playlist (GstHLSDemux * demux, gboolean update,
|
||||||
GstBuffer *buf;
|
GstBuffer *buf;
|
||||||
gchar *playlist;
|
gchar *playlist;
|
||||||
gboolean main_checked = FALSE, updated = FALSE;
|
gboolean main_checked = FALSE, updated = FALSE;
|
||||||
const gchar *uri;
|
gchar *uri, *main_uri;
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
uri = gst_m3u8_client_get_current_uri (demux->client);
|
uri = gst_m3u8_client_get_current_uri (demux->client);
|
||||||
|
main_uri = gst_m3u8_client_get_uri (demux->client);
|
||||||
download =
|
download =
|
||||||
gst_uri_downloader_fetch_uri (demux->downloader, uri,
|
gst_uri_downloader_fetch_uri (demux->downloader, uri,
|
||||||
demux->client->main ? demux->client->main->uri : NULL, TRUE, TRUE, TRUE,
|
main_uri, TRUE, TRUE, TRUE, err);
|
||||||
err);
|
g_free (main_uri);
|
||||||
if (download == NULL) {
|
if (download == NULL) {
|
||||||
if (update && !main_checked
|
if (update && !main_checked
|
||||||
&& gst_m3u8_client_has_variant_playlist (demux->client)
|
&& gst_m3u8_client_has_variant_playlist (demux->client)
|
||||||
&& demux->client->main) {
|
&& gst_m3u8_client_has_main (demux->client)) {
|
||||||
GError *err2 = NULL;
|
GError *err2 = NULL;
|
||||||
|
main_uri = gst_m3u8_client_get_uri (demux->client);
|
||||||
GST_INFO_OBJECT (demux,
|
GST_INFO_OBJECT (demux,
|
||||||
"Updating playlist %s failed, attempt to refresh variant playlist %s",
|
"Updating playlist %s failed, attempt to refresh variant playlist %s",
|
||||||
uri, demux->client->main->uri);
|
uri, main_uri);
|
||||||
download =
|
download =
|
||||||
gst_uri_downloader_fetch_uri (demux->downloader,
|
gst_uri_downloader_fetch_uri (demux->downloader,
|
||||||
demux->client->main->uri, NULL, TRUE, TRUE, TRUE, &err2);
|
main_uri, NULL, TRUE, TRUE, TRUE, &err2);
|
||||||
|
g_free (main_uri);
|
||||||
g_clear_error (&err2);
|
g_clear_error (&err2);
|
||||||
if (download != NULL) {
|
if (download != NULL) {
|
||||||
gchar *base_uri;
|
gchar *base_uri;
|
||||||
|
@ -1607,6 +1622,7 @@ retry:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_free (uri);
|
||||||
if (download->redirect_permanent && download->redirect_uri) {
|
if (download->redirect_permanent && download->redirect_uri) {
|
||||||
uri = download->redirect_uri;
|
uri = download->redirect_uri;
|
||||||
base_uri = NULL;
|
base_uri = NULL;
|
||||||
|
@ -1627,13 +1643,17 @@ retry:
|
||||||
main_checked = TRUE;
|
main_checked = TRUE;
|
||||||
goto retry;
|
goto retry;
|
||||||
} else {
|
} else {
|
||||||
|
g_free (uri);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
g_free (uri);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_free (uri);
|
||||||
|
|
||||||
/* Set the base URI of the playlist to the redirect target if any */
|
/* Set the base URI of the playlist to the redirect target if any */
|
||||||
GST_M3U8_CLIENT_LOCK (demux->client);
|
GST_M3U8_CLIENT_LOCK (demux->client);
|
||||||
g_free (demux->client->current->uri);
|
g_free (demux->client->current->uri);
|
||||||
|
@ -1667,26 +1687,30 @@ retry:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uri = gst_m3u8_client_get_current_uri(demux->client);
|
||||||
|
main_uri = gst_m3u8_client_get_uri (demux->client);
|
||||||
gst_element_post_message (GST_ELEMENT_CAST (demux),
|
gst_element_post_message (GST_ELEMENT_CAST (demux),
|
||||||
gst_message_new_element (GST_OBJECT_CAST (demux),
|
gst_message_new_element (GST_OBJECT_CAST (demux),
|
||||||
gst_structure_new (STATISTICS_MESSAGE_NAME,
|
gst_structure_new (STATISTICS_MESSAGE_NAME,
|
||||||
"manifest-uri", G_TYPE_STRING,
|
"manifest-uri", G_TYPE_STRING, main_uri,
|
||||||
gst_m3u8_client_get_uri (demux->client), "uri", G_TYPE_STRING,
|
"uri", G_TYPE_STRING, uri,
|
||||||
gst_m3u8_client_get_current_uri (demux->client),
|
|
||||||
"manifest-download-start", GST_TYPE_CLOCK_TIME,
|
"manifest-download-start", GST_TYPE_CLOCK_TIME,
|
||||||
download->download_start_time,
|
download->download_start_time,
|
||||||
"manifest-download-stop", GST_TYPE_CLOCK_TIME,
|
"manifest-download-stop", GST_TYPE_CLOCK_TIME,
|
||||||
download->download_stop_time, NULL)));
|
download->download_stop_time, NULL)));
|
||||||
|
g_free (main_uri);
|
||||||
|
g_free (uri);
|
||||||
|
|
||||||
g_object_unref (download);
|
g_object_unref (download);
|
||||||
|
|
||||||
|
GST_M3U8_CLIENT_LOCK (demux->client);
|
||||||
|
|
||||||
/* If it's a live source, do not let the sequence number go beyond
|
/* If it's a live source, do not let the sequence number go beyond
|
||||||
* three fragments before the end of the list */
|
* three fragments before the end of the list */
|
||||||
if (update == FALSE && demux->client->current &&
|
if (update == FALSE && demux->client->current &&
|
||||||
gst_m3u8_client_is_live (demux->client)) {
|
GST_M3U8_CLIENT_IS_LIVE (demux->client)) {
|
||||||
gint64 last_sequence;
|
gint64 last_sequence;
|
||||||
|
|
||||||
GST_M3U8_CLIENT_LOCK (demux->client);
|
|
||||||
last_sequence =
|
last_sequence =
|
||||||
GST_M3U8_MEDIA_FILE (g_list_last (demux->client->current->
|
GST_M3U8_MEDIA_FILE (g_list_last (demux->client->current->
|
||||||
files)->data)->sequence;
|
files)->data)->sequence;
|
||||||
|
@ -1697,8 +1721,7 @@ retry:
|
||||||
demux->need_segment = TRUE;
|
demux->need_segment = TRUE;
|
||||||
demux->client->sequence = last_sequence - 3;
|
demux->client->sequence = last_sequence - 3;
|
||||||
}
|
}
|
||||||
GST_M3U8_CLIENT_UNLOCK (demux->client);
|
} else if (demux->client->current && !GST_M3U8_CLIENT_IS_LIVE (demux->client)) {
|
||||||
} else if (demux->client->current && !gst_m3u8_client_is_live (demux->client)) {
|
|
||||||
GstClockTime current_pos, target_pos;
|
GstClockTime current_pos, target_pos;
|
||||||
guint sequence = 0;
|
guint sequence = 0;
|
||||||
GList *walk;
|
GList *walk;
|
||||||
|
@ -1707,7 +1730,6 @@ retry:
|
||||||
* playlists, so get the correct fragment here based on the current
|
* playlists, so get the correct fragment here based on the current
|
||||||
* position
|
* position
|
||||||
*/
|
*/
|
||||||
GST_M3U8_CLIENT_LOCK (demux->client);
|
|
||||||
current_pos = 0;
|
current_pos = 0;
|
||||||
target_pos = demux->segment.position;
|
target_pos = demux->segment.position;
|
||||||
for (walk = demux->client->current->files; walk; walk = walk->next) {
|
for (walk = demux->client->current->files; walk; walk = walk->next) {
|
||||||
|
@ -1725,9 +1747,10 @@ retry:
|
||||||
sequence++;
|
sequence++;
|
||||||
demux->client->sequence = sequence;
|
demux->client->sequence = sequence;
|
||||||
demux->client->sequence_position = current_pos;
|
demux->client->sequence_position = current_pos;
|
||||||
GST_M3U8_CLIENT_UNLOCK (demux->client);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GST_M3U8_CLIENT_UNLOCK (demux->client);
|
||||||
|
|
||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1769,13 +1792,17 @@ retry_failover_protection:
|
||||||
demux->new_playlist = TRUE;
|
demux->new_playlist = TRUE;
|
||||||
|
|
||||||
if (gst_hls_demux_update_playlist (demux, FALSE, NULL)) {
|
if (gst_hls_demux_update_playlist (demux, FALSE, NULL)) {
|
||||||
|
gchar *uri, *main_uri;
|
||||||
|
uri = gst_m3u8_client_get_current_uri (demux->client);
|
||||||
|
main_uri = gst_m3u8_client_get_uri (demux->client);
|
||||||
gst_element_post_message (GST_ELEMENT_CAST (demux),
|
gst_element_post_message (GST_ELEMENT_CAST (demux),
|
||||||
gst_message_new_element (GST_OBJECT_CAST (demux),
|
gst_message_new_element (GST_OBJECT_CAST (demux),
|
||||||
gst_structure_new (STATISTICS_MESSAGE_NAME,
|
gst_structure_new (STATISTICS_MESSAGE_NAME,
|
||||||
"manifest-uri", G_TYPE_STRING,
|
"manifest-uri", G_TYPE_STRING, main_uri,
|
||||||
gst_m3u8_client_get_uri (demux->client), "uri", G_TYPE_STRING,
|
"uri", G_TYPE_STRING, uri,
|
||||||
gst_m3u8_client_get_current_uri (demux->client), "bitrate",
|
"bitrate", G_TYPE_INT, new_bandwidth, NULL)));
|
||||||
G_TYPE_INT, new_bandwidth, NULL)));
|
g_free (uri);
|
||||||
|
g_free (main_uri);
|
||||||
} else {
|
} else {
|
||||||
GList *failover = NULL;
|
GList *failover = NULL;
|
||||||
|
|
||||||
|
@ -2090,13 +2117,13 @@ static gboolean
|
||||||
gst_hls_demux_get_next_fragment (GstHLSDemux * demux,
|
gst_hls_demux_get_next_fragment (GstHLSDemux * demux,
|
||||||
gboolean * end_of_playlist, GError ** err)
|
gboolean * end_of_playlist, GError ** err)
|
||||||
{
|
{
|
||||||
const gchar *next_fragment_uri;
|
gchar *uri, *next_fragment_uri;
|
||||||
GstClockTime duration;
|
GstClockTime duration;
|
||||||
GstClockTime timestamp;
|
GstClockTime timestamp;
|
||||||
gboolean discont;
|
gboolean discont;
|
||||||
gint64 range_start, range_end;
|
gint64 range_start, range_end;
|
||||||
const gchar *key = NULL;
|
gchar *key = NULL;
|
||||||
const guint8 *iv = NULL;
|
guint8 *iv = NULL;
|
||||||
GstClockTime download_start_time = 0;
|
GstClockTime download_start_time = 0;
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
|
|
||||||
|
@ -2120,7 +2147,11 @@ gst_hls_demux_get_next_fragment (GstHLSDemux * demux,
|
||||||
demux->current_duration = duration;
|
demux->current_duration = duration;
|
||||||
demux->starting_fragment = TRUE;
|
demux->starting_fragment = TRUE;
|
||||||
demux->reset_crypto = TRUE;
|
demux->reset_crypto = TRUE;
|
||||||
|
if (demux->current_key)
|
||||||
|
g_free (demux->current_key);
|
||||||
demux->current_key = key;
|
demux->current_key = key;
|
||||||
|
if (demux->current_iv)
|
||||||
|
g_free (demux->current_iv);
|
||||||
demux->current_iv = iv;
|
demux->current_iv = iv;
|
||||||
|
|
||||||
/* Reset last flow return */
|
/* Reset last flow return */
|
||||||
|
@ -2129,15 +2160,19 @@ gst_hls_demux_get_next_fragment (GstHLSDemux * demux,
|
||||||
g_clear_error (&demux->last_error);
|
g_clear_error (&demux->last_error);
|
||||||
g_mutex_unlock (&demux->fragment_download_lock);
|
g_mutex_unlock (&demux->fragment_download_lock);
|
||||||
|
|
||||||
|
GST_M3U8_CLIENT_LOCK (demux->client);
|
||||||
if (!gst_hls_demux_update_source (demux, next_fragment_uri,
|
if (!gst_hls_demux_update_source (demux, next_fragment_uri,
|
||||||
demux->client->main ? demux->client->main->uri : NULL,
|
demux->client->main ? demux->client->main->uri : NULL,
|
||||||
FALSE,
|
FALSE,
|
||||||
demux->client->current ? demux->client->current->allowcache : TRUE)) {
|
demux->client->current ? demux->client->current->allowcache : TRUE)) {
|
||||||
|
GST_M3U8_CLIENT_UNLOCK (demux->client);
|
||||||
*err =
|
*err =
|
||||||
g_error_new (GST_CORE_ERROR, GST_CORE_ERROR_MISSING_PLUGIN,
|
g_error_new (GST_CORE_ERROR, GST_CORE_ERROR_MISSING_PLUGIN,
|
||||||
"Missing plugin to handle URI: '%s'", next_fragment_uri);
|
"Missing plugin to handle URI: '%s'", next_fragment_uri);
|
||||||
|
g_free (next_fragment_uri);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
GST_M3U8_CLIENT_UNLOCK (demux->client);
|
||||||
|
|
||||||
gst_hls_demux_configure_src_pad (demux);
|
gst_hls_demux_configure_src_pad (demux);
|
||||||
|
|
||||||
|
@ -2155,6 +2190,7 @@ gst_hls_demux_get_next_fragment (GstHLSDemux * demux,
|
||||||
"Source element can't handle range requests");
|
"Source element can't handle range requests");
|
||||||
demux->last_ret = GST_FLOW_ERROR;
|
demux->last_ret = GST_FLOW_ERROR;
|
||||||
g_mutex_unlock (&demux->fragment_download_lock);
|
g_mutex_unlock (&demux->fragment_download_lock);
|
||||||
|
g_free (next_fragment_uri);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2207,23 +2243,26 @@ gst_hls_demux_get_next_fragment (GstHLSDemux * demux,
|
||||||
if (demux->segment.rate > 0)
|
if (demux->segment.rate > 0)
|
||||||
demux->segment.position += demux->current_duration;
|
demux->segment.position += demux->current_duration;
|
||||||
|
|
||||||
|
uri = gst_m3u8_client_get_uri (demux->client);
|
||||||
gst_element_post_message (GST_ELEMENT_CAST (demux),
|
gst_element_post_message (GST_ELEMENT_CAST (demux),
|
||||||
gst_message_new_element (GST_OBJECT_CAST (demux),
|
gst_message_new_element (GST_OBJECT_CAST (demux),
|
||||||
gst_structure_new (STATISTICS_MESSAGE_NAME,
|
gst_structure_new (STATISTICS_MESSAGE_NAME,
|
||||||
"manifest-uri", G_TYPE_STRING,
|
"manifest-uri", G_TYPE_STRING, uri,
|
||||||
gst_m3u8_client_get_uri (demux->client), "uri", G_TYPE_STRING,
|
"uri", G_TYPE_STRING, next_fragment_uri,
|
||||||
next_fragment_uri, "fragment-start-time",
|
"fragment-start-time", GST_TYPE_CLOCK_TIME, download_start_time,
|
||||||
GST_TYPE_CLOCK_TIME, download_start_time,
|
|
||||||
"fragment-stop-time", GST_TYPE_CLOCK_TIME,
|
"fragment-stop-time", GST_TYPE_CLOCK_TIME,
|
||||||
gst_util_get_timestamp (), "fragment-size", G_TYPE_UINT64,
|
gst_util_get_timestamp (), "fragment-size", G_TYPE_UINT64,
|
||||||
demux->download_total_bytes, "fragment-download-time",
|
demux->download_total_bytes, "fragment-download-time",
|
||||||
GST_TYPE_CLOCK_TIME, demux->download_total_time * GST_USECOND,
|
GST_TYPE_CLOCK_TIME, demux->download_total_time * GST_USECOND,
|
||||||
NULL)));
|
NULL)));
|
||||||
|
g_free (uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clear the ghostpad eos state */
|
/* clear the ghostpad eos state */
|
||||||
gst_hls_demux_stream_clear_eos_state (demux);
|
gst_hls_demux_stream_clear_eos_state (demux);
|
||||||
|
|
||||||
|
g_free (next_fragment_uri);
|
||||||
|
|
||||||
if (ret != GST_FLOW_OK)
|
if (ret != GST_FLOW_OK)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
|
4
ext/hls/gsthlsdemux.h
Normal file → Executable file
4
ext/hls/gsthlsdemux.h
Normal file → Executable file
|
@ -139,8 +139,8 @@ struct _GstHLSDemux
|
||||||
#else
|
#else
|
||||||
gcry_cipher_hd_t aes_ctx;
|
gcry_cipher_hd_t aes_ctx;
|
||||||
#endif
|
#endif
|
||||||
const gchar *current_key;
|
gchar *current_key;
|
||||||
const guint8 *current_iv;
|
guint8 *current_iv;
|
||||||
GstAdapter *adapter; /* used to accumulate 16 bytes multiple chunks */
|
GstAdapter *adapter; /* used to accumulate 16 bytes multiple chunks */
|
||||||
GstBuffer *pending_buffer; /* decryption scenario:
|
GstBuffer *pending_buffer; /* decryption scenario:
|
||||||
* the last buffer can only be pushed when
|
* the last buffer can only be pushed when
|
||||||
|
|
47
ext/hls/m3u8.c
Normal file → Executable file
47
ext/hls/m3u8.c
Normal file → Executable file
|
@ -932,9 +932,9 @@ find_next_fragment (GstM3U8Client * client, GList * l, gboolean forward)
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gst_m3u8_client_get_next_fragment (GstM3U8Client * client,
|
gst_m3u8_client_get_next_fragment (GstM3U8Client * client,
|
||||||
gboolean * discontinuity, const gchar ** uri, GstClockTime * duration,
|
gboolean * discontinuity, gchar ** uri, GstClockTime * duration,
|
||||||
GstClockTime * timestamp, gint64 * range_start, gint64 * range_end,
|
GstClockTime * timestamp, gint64 * range_start, gint64 * range_end,
|
||||||
const gchar ** key, const guint8 ** iv, gboolean forward)
|
gchar ** key, guint8 ** iv, gboolean forward)
|
||||||
{
|
{
|
||||||
GList *l;
|
GList *l;
|
||||||
GstM3U8MediaFile *file;
|
GstM3U8MediaFile *file;
|
||||||
|
@ -964,7 +964,7 @@ gst_m3u8_client_get_next_fragment (GstM3U8Client * client,
|
||||||
if (discontinuity)
|
if (discontinuity)
|
||||||
*discontinuity = client->sequence != file->sequence || file->discont;
|
*discontinuity = client->sequence != file->sequence || file->discont;
|
||||||
if (uri)
|
if (uri)
|
||||||
*uri = file->uri;
|
*uri = g_strdup (file->uri);
|
||||||
if (duration)
|
if (duration)
|
||||||
*duration = file->duration;
|
*duration = file->duration;
|
||||||
if (range_start)
|
if (range_start)
|
||||||
|
@ -972,9 +972,11 @@ gst_m3u8_client_get_next_fragment (GstM3U8Client * client,
|
||||||
if (range_end)
|
if (range_end)
|
||||||
*range_end = file->size != -1 ? file->offset + file->size - 1 : -1;
|
*range_end = file->size != -1 ? file->offset + file->size - 1 : -1;
|
||||||
if (key)
|
if (key)
|
||||||
*key = file->key;
|
*key = g_strdup (file->key);
|
||||||
if (iv)
|
if (iv) {
|
||||||
*iv = file->iv;
|
*iv = g_new (guint8, sizeof (file->iv));
|
||||||
|
memcpy (*iv, file->iv, sizeof (file->iv));
|
||||||
|
}
|
||||||
|
|
||||||
client->sequence = file->sequence;
|
client->sequence = file->sequence;
|
||||||
|
|
||||||
|
@ -1054,32 +1056,48 @@ gst_m3u8_client_get_target_duration (GstM3U8Client * client)
|
||||||
return duration;
|
return duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
const gchar *
|
gchar *
|
||||||
gst_m3u8_client_get_uri (GstM3U8Client * client)
|
gst_m3u8_client_get_uri (GstM3U8Client * client)
|
||||||
{
|
{
|
||||||
const gchar *uri;
|
gchar *uri;
|
||||||
|
|
||||||
g_return_val_if_fail (client != NULL, NULL);
|
g_return_val_if_fail (client != NULL, NULL);
|
||||||
|
|
||||||
GST_M3U8_CLIENT_LOCK (client);
|
GST_M3U8_CLIENT_LOCK (client);
|
||||||
uri = client->main->uri;
|
uri = client->main ? g_strdup (client->main->uri) : NULL;
|
||||||
GST_M3U8_CLIENT_UNLOCK (client);
|
GST_M3U8_CLIENT_UNLOCK (client);
|
||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
const gchar *
|
gchar *
|
||||||
gst_m3u8_client_get_current_uri (GstM3U8Client * client)
|
gst_m3u8_client_get_current_uri (GstM3U8Client * client)
|
||||||
{
|
{
|
||||||
const gchar *uri;
|
gchar *uri;
|
||||||
|
|
||||||
g_return_val_if_fail (client != NULL, NULL);
|
g_return_val_if_fail (client != NULL, NULL);
|
||||||
|
|
||||||
GST_M3U8_CLIENT_LOCK (client);
|
GST_M3U8_CLIENT_LOCK (client);
|
||||||
uri = client->current->uri;
|
uri = g_strdup (client->current->uri);
|
||||||
GST_M3U8_CLIENT_UNLOCK (client);
|
GST_M3U8_CLIENT_UNLOCK (client);
|
||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gst_m3u8_client_has_main(GstM3U8Client * client)
|
||||||
|
{
|
||||||
|
gboolean ret;
|
||||||
|
|
||||||
|
g_return_val_if_fail (client != NULL, FALSE);
|
||||||
|
|
||||||
|
GST_M3U8_CLIENT_LOCK (client);
|
||||||
|
if (client->main)
|
||||||
|
ret = TRUE;
|
||||||
|
else
|
||||||
|
ret = FALSE;
|
||||||
|
GST_M3U8_CLIENT_UNLOCK (client);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gst_m3u8_client_has_variant_playlist (GstM3U8Client * client)
|
gst_m3u8_client_has_variant_playlist (GstM3U8Client * client)
|
||||||
{
|
{
|
||||||
|
@ -1101,10 +1119,7 @@ gst_m3u8_client_is_live (GstM3U8Client * client)
|
||||||
g_return_val_if_fail (client != NULL, FALSE);
|
g_return_val_if_fail (client != NULL, FALSE);
|
||||||
|
|
||||||
GST_M3U8_CLIENT_LOCK (client);
|
GST_M3U8_CLIENT_LOCK (client);
|
||||||
if (!client->current || client->current->endlist)
|
ret = GST_M3U8_CLIENT_IS_LIVE (client);
|
||||||
ret = FALSE;
|
|
||||||
else
|
|
||||||
ret = TRUE;
|
|
||||||
GST_M3U8_CLIENT_UNLOCK (client);
|
GST_M3U8_CLIENT_UNLOCK (client);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
11
ext/hls/m3u8.h
Normal file → Executable file
11
ext/hls/m3u8.h
Normal file → Executable file
|
@ -35,6 +35,8 @@ typedef struct _GstM3U8Client GstM3U8Client;
|
||||||
#define GST_M3U8_CLIENT_LOCK(c) g_mutex_lock (&c->lock);
|
#define GST_M3U8_CLIENT_LOCK(c) g_mutex_lock (&c->lock);
|
||||||
#define GST_M3U8_CLIENT_UNLOCK(c) g_mutex_unlock (&c->lock);
|
#define GST_M3U8_CLIENT_UNLOCK(c) g_mutex_unlock (&c->lock);
|
||||||
|
|
||||||
|
#define GST_M3U8_CLIENT_IS_LIVE(c) ((!(c)->current || (c)->current->endlist) ? FALSE : TRUE)
|
||||||
|
|
||||||
struct _GstM3U8
|
struct _GstM3U8
|
||||||
{
|
{
|
||||||
gchar *uri; /* actually downloaded URI */
|
gchar *uri; /* actually downloaded URI */
|
||||||
|
@ -94,14 +96,15 @@ gboolean gst_m3u8_client_update (GstM3U8Client * client, gchar * data);
|
||||||
gboolean gst_m3u8_client_update_variant_playlist (GstM3U8Client * client, gchar * data, const gchar * uri, const gchar * base_uri);
|
gboolean gst_m3u8_client_update_variant_playlist (GstM3U8Client * client, gchar * data, const gchar * uri, const gchar * base_uri);
|
||||||
void gst_m3u8_client_set_current (GstM3U8Client * client, GstM3U8 * m3u8);
|
void gst_m3u8_client_set_current (GstM3U8Client * client, GstM3U8 * m3u8);
|
||||||
gboolean gst_m3u8_client_get_next_fragment (GstM3U8Client * client,
|
gboolean gst_m3u8_client_get_next_fragment (GstM3U8Client * client,
|
||||||
gboolean * discontinuity, const gchar ** uri, GstClockTime * duration,
|
gboolean * discontinuity, gchar ** uri, GstClockTime * duration,
|
||||||
GstClockTime * timestamp, gint64 * range_start, gint64 * range_end,
|
GstClockTime * timestamp, gint64 * range_start, gint64 * range_end,
|
||||||
const gchar ** key, const guint8 ** iv, gboolean forward);
|
gchar ** key, guint8 ** iv, gboolean forward);
|
||||||
void gst_m3u8_client_advance_fragment (GstM3U8Client * client, gboolean forward);
|
void gst_m3u8_client_advance_fragment (GstM3U8Client * client, gboolean forward);
|
||||||
GstClockTime gst_m3u8_client_get_duration (GstM3U8Client * client);
|
GstClockTime gst_m3u8_client_get_duration (GstM3U8Client * client);
|
||||||
GstClockTime gst_m3u8_client_get_target_duration (GstM3U8Client * client);
|
GstClockTime gst_m3u8_client_get_target_duration (GstM3U8Client * client);
|
||||||
const gchar *gst_m3u8_client_get_uri(GstM3U8Client * client);
|
gchar *gst_m3u8_client_get_uri(GstM3U8Client * client);
|
||||||
const gchar *gst_m3u8_client_get_current_uri(GstM3U8Client * client);
|
gchar *gst_m3u8_client_get_current_uri(GstM3U8Client * client);
|
||||||
|
gboolean gst_m3u8_client_has_main(GstM3U8Client * client);
|
||||||
gboolean gst_m3u8_client_has_variant_playlist(GstM3U8Client * client);
|
gboolean gst_m3u8_client_has_variant_playlist(GstM3U8Client * client);
|
||||||
gboolean gst_m3u8_client_is_live(GstM3U8Client * client);
|
gboolean gst_m3u8_client_is_live(GstM3U8Client * client);
|
||||||
GList * gst_m3u8_client_get_playlist_for_bitrate (GstM3U8Client * client,
|
GList * gst_m3u8_client_get_playlist_for_bitrate (GstM3U8Client * client,
|
||||||
|
|
Loading…
Reference in a new issue