mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 08:46:40 +00:00
hlsdemux2: Add preloader helper.
Add a helper that submits and handles blocking preload requests for future PART/MAP data from live playlists. Add handling in the hlsdemux stream to submit preload requests when hitting the end of the available segments in a live playlist. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3883>
This commit is contained in:
parent
5ca336226e
commit
cb27c05ca7
5 changed files with 347 additions and 0 deletions
|
@ -0,0 +1,228 @@
|
||||||
|
/* GStreamer
|
||||||
|
Copyright (C) 2022 Jan Schmidt <jan@centricular.com>
|
||||||
|
*
|
||||||
|
* gsthlsdemux-preloader.c:
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "gsthlsdemux-preloader.h"
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_EXTERN (gst_hls_demux2_debug);
|
||||||
|
#define GST_CAT_DEFAULT gst_hls_demux2_debug
|
||||||
|
|
||||||
|
typedef struct _GstHLSDemuxPreloadRequest GstHLSDemuxPreloadRequest;
|
||||||
|
struct _GstHLSDemuxPreloadRequest
|
||||||
|
{
|
||||||
|
GstHLSDemuxPreloader *preloader; /* Parent preloader */
|
||||||
|
GstM3U8PreloadHint *hint;
|
||||||
|
DownloadRequest *download_request;
|
||||||
|
};
|
||||||
|
|
||||||
|
static GstHLSDemuxPreloadRequest *
|
||||||
|
gst_hls_demux_preload_request_new (GstHLSDemuxPreloader * preloader,
|
||||||
|
GstM3U8PreloadHint * hint)
|
||||||
|
{
|
||||||
|
GstHLSDemuxPreloadRequest *req = g_new0 (GstHLSDemuxPreloadRequest, 1);
|
||||||
|
req->preloader = preloader;
|
||||||
|
req->hint = gst_m3u8_preload_hint_ref (hint);
|
||||||
|
|
||||||
|
return req;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_hls_demux_preload_request_free (GstHLSDemuxPreloadRequest * req)
|
||||||
|
{
|
||||||
|
gst_m3u8_preload_hint_unref (req->hint);
|
||||||
|
|
||||||
|
/* The download request must have been cancelled and removed by the preload helper */
|
||||||
|
g_assert (req->download_request == NULL);
|
||||||
|
g_free (req);
|
||||||
|
};
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_hls_demux_preloader_submit (GstHLSDemuxPreloader * preloader,
|
||||||
|
GstHLSDemuxPreloadRequest * preload_req, const gchar * referrer_uri);
|
||||||
|
static void gst_hls_demux_preloader_cancel_request (GstHLSDemuxPreloader *
|
||||||
|
preloader, GstHLSDemuxPreloadRequest * req);
|
||||||
|
|
||||||
|
GstHLSDemuxPreloader *
|
||||||
|
gst_hls_demux_preloader_new (DownloadHelper * download_helper)
|
||||||
|
{
|
||||||
|
GstHLSDemuxPreloader *preloader = g_new0 (GstHLSDemuxPreloader, 1);
|
||||||
|
|
||||||
|
preloader->download_helper = download_helper;
|
||||||
|
preloader->active_preloads = g_ptr_array_new ();
|
||||||
|
|
||||||
|
return preloader;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_hls_demux_preloader_free (GstHLSDemuxPreloader * preloader)
|
||||||
|
{
|
||||||
|
gst_hls_demux_preloader_cancel (preloader, M3U8_PRELOAD_HINT_ALL);
|
||||||
|
g_ptr_array_free (preloader->active_preloads, TRUE);
|
||||||
|
g_free (preloader);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_hls_demux_preloader_load (GstHLSDemuxPreloader * preloader,
|
||||||
|
GstM3U8PreloadHint * hint, const gchar * referrer_uri)
|
||||||
|
{
|
||||||
|
/* Check if we have an active preload already for this hint */
|
||||||
|
guint idx;
|
||||||
|
for (idx = 0; idx < preloader->active_preloads->len; idx++) {
|
||||||
|
GstHLSDemuxPreloadRequest *req =
|
||||||
|
g_ptr_array_index (preloader->active_preloads, idx);
|
||||||
|
if (hint->hint_type == req->hint->hint_type) {
|
||||||
|
/* We already have an active hint of this type. If this new one is different, cancel
|
||||||
|
* the active preload before starting this one */
|
||||||
|
if (gst_m3u8_preload_hint_equal (hint, req->hint)) {
|
||||||
|
GST_LOG ("Ignoring pre-existing preload of type %d uri: %s, range:%"
|
||||||
|
G_GINT64_FORMAT " size %" G_GINT64_FORMAT, hint->hint_type,
|
||||||
|
hint->uri, hint->offset, hint->size);
|
||||||
|
return; /* Nothing to do */
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_hls_demux_preloader_cancel_request (preloader, req);
|
||||||
|
g_ptr_array_remove_index_fast (preloader->active_preloads, idx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we get here, then there's no preload of this type. Create one */
|
||||||
|
GstHLSDemuxPreloadRequest *req =
|
||||||
|
gst_hls_demux_preload_request_new (preloader, hint);
|
||||||
|
/* Submit the request */
|
||||||
|
|
||||||
|
if (gst_hls_demux_preloader_submit (preloader, req, referrer_uri)) {
|
||||||
|
g_ptr_array_add (preloader->active_preloads, req);
|
||||||
|
} else {
|
||||||
|
/* Discard failed request */
|
||||||
|
gst_hls_demux_preloader_cancel_request (preloader, req);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_hls_demux_preloader_cancel (GstHLSDemuxPreloader * preloader,
|
||||||
|
GstM3U8PreloadHintType hint_types)
|
||||||
|
{
|
||||||
|
/* Go through the active downloads and remove/cancel any with the matching type */
|
||||||
|
guint idx;
|
||||||
|
for (idx = 0; idx < preloader->active_preloads->len;) {
|
||||||
|
GstHLSDemuxPreloadRequest *req =
|
||||||
|
g_ptr_array_index (preloader->active_preloads, idx);
|
||||||
|
if (hint_types & req->hint->hint_type) {
|
||||||
|
gst_hls_demux_preloader_cancel_request (preloader, req);
|
||||||
|
g_ptr_array_remove_index_fast (preloader->active_preloads, idx);
|
||||||
|
continue; /* Don't increment idx++, as we just removed an item */
|
||||||
|
}
|
||||||
|
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_download_cancellation (DownloadRequest * request, DownloadRequestState state,
|
||||||
|
GstHLSDemuxPreloadRequest * preload_req)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_download_error (DownloadRequest * request, DownloadRequestState state,
|
||||||
|
GstHLSDemuxPreloadRequest * preload_req)
|
||||||
|
{
|
||||||
|
GstM3U8PreloadHint *hint = preload_req->hint;
|
||||||
|
GST_DEBUG ("preload type %d uri: %s download error", hint->hint_type,
|
||||||
|
hint->uri);
|
||||||
|
GST_FIXME ("How to handle failed preload request?");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_download_progress (DownloadRequest * request, DownloadRequestState state,
|
||||||
|
GstHLSDemuxPreloadRequest * preload_req)
|
||||||
|
{
|
||||||
|
GstM3U8PreloadHint *hint = preload_req->hint;
|
||||||
|
GST_DEBUG ("preload type %d uri: %s download progress", hint->hint_type,
|
||||||
|
hint->uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_download_complete (DownloadRequest * request, DownloadRequestState state,
|
||||||
|
GstHLSDemuxPreloadRequest * preload_req)
|
||||||
|
{
|
||||||
|
GstM3U8PreloadHint *hint = preload_req->hint;
|
||||||
|
GST_DEBUG ("preload type %d uri: %s download complete", hint->hint_type,
|
||||||
|
hint->uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_hls_demux_preloader_submit (GstHLSDemuxPreloader * preloader,
|
||||||
|
GstHLSDemuxPreloadRequest * preload_req, const gchar * referrer_uri)
|
||||||
|
{
|
||||||
|
g_assert (preload_req->download_request == NULL);
|
||||||
|
|
||||||
|
DownloadRequest *download_req = download_request_new ();
|
||||||
|
GstM3U8PreloadHint *hint = preload_req->hint;
|
||||||
|
|
||||||
|
/* Configure our download request */
|
||||||
|
gint64 end = RFC8673_LAST_BYTE_POS;
|
||||||
|
if (hint->size > 0) {
|
||||||
|
end = hint->offset + hint->size - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
download_request_set_uri (download_req, hint->uri, hint->offset, end);
|
||||||
|
download_request_set_callbacks (download_req,
|
||||||
|
(DownloadRequestEventCallback) on_download_complete,
|
||||||
|
(DownloadRequestEventCallback) on_download_error,
|
||||||
|
(DownloadRequestEventCallback) on_download_cancellation,
|
||||||
|
(DownloadRequestEventCallback) on_download_progress, preload_req);
|
||||||
|
|
||||||
|
GST_DEBUG ("Submitting preload type %d uri: %s, range:%" G_GINT64_FORMAT
|
||||||
|
" - %" G_GINT64_FORMAT, hint->hint_type, hint->uri, hint->offset, end);
|
||||||
|
|
||||||
|
if (!downloadhelper_submit_request (preloader->download_helper,
|
||||||
|
referrer_uri, DOWNLOAD_FLAG_NONE, download_req, NULL)) {
|
||||||
|
/* Abandon the request */
|
||||||
|
download_request_unref (download_req);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
preload_req->download_request = download_req;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_hls_demux_preloader_cancel_request (GstHLSDemuxPreloader * preloader,
|
||||||
|
GstHLSDemuxPreloadRequest * preload_req)
|
||||||
|
{
|
||||||
|
if (preload_req->download_request) {
|
||||||
|
GstM3U8PreloadHint *hint = preload_req->hint;
|
||||||
|
GST_DEBUG ("Cancelling preload type %d uri: %s, range start:%"
|
||||||
|
G_GINT64_FORMAT " size %" G_GINT64_FORMAT, hint->hint_type, hint->uri,
|
||||||
|
hint->offset, hint->size);
|
||||||
|
|
||||||
|
downloadhelper_cancel_request (preloader->download_helper,
|
||||||
|
preload_req->download_request);
|
||||||
|
download_request_unref (preload_req->download_request);
|
||||||
|
preload_req->download_request = NULL;
|
||||||
|
}
|
||||||
|
gst_hls_demux_preload_request_free (preload_req);
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
/* GStreamer
|
||||||
|
Copyright (C) 2022 Jan Schmidt <jan@centricular.com>
|
||||||
|
*
|
||||||
|
* gsthlsdemux-preloader.h:
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifndef __GST_HLS_DEMUX_PRELOADER_H__
|
||||||
|
#define __GST_HLS_DEMUX_PRELOADER_H__
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "m3u8.h"
|
||||||
|
|
||||||
|
#include "downloadrequest.h"
|
||||||
|
#include "downloadhelper.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
typedef struct _GstHLSDemuxPreloader GstHLSDemuxPreloader;
|
||||||
|
|
||||||
|
struct _GstHLSDemuxPreloader {
|
||||||
|
DownloadHelper *download_helper; /* Owned by the demuxer */
|
||||||
|
GPtrArray *active_preloads;
|
||||||
|
};
|
||||||
|
|
||||||
|
GstHLSDemuxPreloader *gst_hls_demux_preloader_new (DownloadHelper *download_helper);
|
||||||
|
void gst_hls_demux_preloader_free (GstHLSDemuxPreloader *preloader);
|
||||||
|
void gst_hls_demux_preloader_load (GstHLSDemuxPreloader *preloader, GstM3U8PreloadHint *hint, const gchar *referrer_uri);
|
||||||
|
void gst_hls_demux_preloader_cancel (GstHLSDemuxPreloader *preloader, GstM3U8PreloadHintType hint_types);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
#endif /* __GST_HLS_DEMUX_PRELOADER_H__ */
|
|
@ -1844,6 +1844,11 @@ gst_hls_demux_stream_finalize (GObject * object)
|
||||||
gst_buffer_replace (&hls_stream->pending_typefind_buffer, NULL);
|
gst_buffer_replace (&hls_stream->pending_typefind_buffer, NULL);
|
||||||
gst_buffer_replace (&hls_stream->pending_segment_data, NULL);
|
gst_buffer_replace (&hls_stream->pending_segment_data, NULL);
|
||||||
|
|
||||||
|
if (hls_stream->preloader) {
|
||||||
|
gst_hls_demux_preloader_free (hls_stream->preloader);
|
||||||
|
hls_stream->preloader = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (hls_stream->moov)
|
if (hls_stream->moov)
|
||||||
gst_isoff_moov_box_free (hls_stream->moov);
|
gst_isoff_moov_box_free (hls_stream->moov);
|
||||||
|
|
||||||
|
@ -2298,6 +2303,61 @@ gst_hls_demux_reset_for_lost_sync (GstHLSDemux * hlsdemux)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_hls_demux_stream_update_preloads (GstHLSDemuxStream * hlsdemux_stream)
|
||||||
|
{
|
||||||
|
GstHLSMediaPlaylist *playlist = hlsdemux_stream->playlist;
|
||||||
|
GstAdaptiveDemux *demux =
|
||||||
|
GST_ADAPTIVE_DEMUX2_STREAM_CAST (hlsdemux_stream)->demux;
|
||||||
|
GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
|
||||||
|
|
||||||
|
gboolean preloads_allowed = hlsdemux->llhls_enabled
|
||||||
|
&& GST_HLS_MEDIA_PLAYLIST_IS_LIVE (playlist);
|
||||||
|
|
||||||
|
if (playlist->preload_hints == NULL || !preloads_allowed) {
|
||||||
|
if (hlsdemux_stream->preloader != NULL) {
|
||||||
|
/* Cancel any preloads, the new playlist doesn't have them */
|
||||||
|
gst_hls_demux_preloader_cancel (hlsdemux_stream->preloader,
|
||||||
|
M3U8_PRELOAD_HINT_ALL);
|
||||||
|
}
|
||||||
|
/* Nothing to preload */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hlsdemux_stream->preloader == NULL) {
|
||||||
|
GstAdaptiveDemux *demux =
|
||||||
|
GST_ADAPTIVE_DEMUX2_STREAM (hlsdemux_stream)->demux;
|
||||||
|
hlsdemux_stream->preloader =
|
||||||
|
gst_hls_demux_preloader_new (demux->download_helper);
|
||||||
|
if (hlsdemux_stream->preloader == NULL) {
|
||||||
|
GST_WARNING_OBJECT (hlsdemux_stream, "Failed to create preload handler");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The HLS spec says any extra preload hint of each type should be ignored */
|
||||||
|
GstM3U8PreloadHintType seen_types = 0;
|
||||||
|
guint idx;
|
||||||
|
for (idx = 0; idx < playlist->preload_hints->len; idx++) {
|
||||||
|
GstM3U8PreloadHint *hint = g_ptr_array_index (playlist->preload_hints, idx);
|
||||||
|
switch (hint->hint_type) {
|
||||||
|
case M3U8_PRELOAD_HINT_MAP:
|
||||||
|
case M3U8_PRELOAD_HINT_PART:
|
||||||
|
if (seen_types & hint->hint_type) {
|
||||||
|
continue; /* Ignore preload hint type we've already seen */
|
||||||
|
}
|
||||||
|
seen_types |= hint->hint_type;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GST_FIXME_OBJECT (hlsdemux_stream, "Ignoring unknown preload type %d",
|
||||||
|
hint->hint_type);
|
||||||
|
continue; /* Unknown hint type, ignore it */
|
||||||
|
}
|
||||||
|
gst_hls_demux_preloader_load (hlsdemux_stream->preloader, hint,
|
||||||
|
playlist->uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_hls_demux_stream_update_media_playlist (GstHLSDemux * demux,
|
gst_hls_demux_stream_update_media_playlist (GstHLSDemux * demux,
|
||||||
GstHLSDemuxStream * stream, gchar ** uri, GError ** err)
|
GstHLSDemuxStream * stream, gchar ** uri, GError ** err)
|
||||||
|
@ -2429,6 +2489,11 @@ gst_hls_demux_stream_update_media_playlist (GstHLSDemux * demux,
|
||||||
stream->playlist = new_playlist;
|
stream->playlist = new_playlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!GST_HLS_MEDIA_PLAYLIST_IS_LIVE (stream->playlist)) {
|
||||||
|
/* Make sure to cancel any preloads if a playlist isn't live after reload */
|
||||||
|
gst_hls_demux_stream_update_preloads (stream);
|
||||||
|
}
|
||||||
|
|
||||||
if (stream->is_variant) {
|
if (stream->is_variant) {
|
||||||
/* Update time mappings. We only use the variant stream for collecting
|
/* Update time mappings. We only use the variant stream for collecting
|
||||||
* mappings since it is the reference on which rendition stream timing will
|
* mappings since it is the reference on which rendition stream timing will
|
||||||
|
@ -2581,6 +2646,7 @@ gst_hls_demux_stream_update_fragment_info (GstAdaptiveDemux2Stream * stream)
|
||||||
stream->current_position, hlsdemux_stream->in_partial_segments,
|
stream->current_position, hlsdemux_stream->in_partial_segments,
|
||||||
&seek_result)) {
|
&seek_result)) {
|
||||||
GST_INFO_OBJECT (stream, "At the end of the current media playlist");
|
GST_INFO_OBJECT (stream, "At the end of the current media playlist");
|
||||||
|
gst_hls_demux_stream_update_preloads (hlsdemux_stream);
|
||||||
return GST_FLOW_EOS;
|
return GST_FLOW_EOS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2620,6 +2686,7 @@ gst_hls_demux_stream_update_fragment_info (GstAdaptiveDemux2Stream * stream)
|
||||||
* hit the live edge and need to wait for a playlist update */
|
* hit the live edge and need to wait for a playlist update */
|
||||||
if (file->partial_only) {
|
if (file->partial_only) {
|
||||||
GST_INFO_OBJECT (stream, "At the end of the current media playlist");
|
GST_INFO_OBJECT (stream, "At the end of the current media playlist");
|
||||||
|
gst_hls_demux_stream_update_preloads (hlsdemux_stream);
|
||||||
return GST_FLOW_EOS;
|
return GST_FLOW_EOS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
#include "m3u8.h"
|
#include "m3u8.h"
|
||||||
#include "gstisoff.h"
|
#include "gstisoff.h"
|
||||||
#include "gstadaptivedemux.h"
|
#include "gstadaptivedemux.h"
|
||||||
|
#include "gsthlsdemux-preloader.h"
|
||||||
|
|
||||||
#if defined(HAVE_OPENSSL)
|
#if defined(HAVE_OPENSSL)
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#elif defined(HAVE_NETTLE)
|
#elif defined(HAVE_NETTLE)
|
||||||
|
@ -126,6 +128,9 @@ struct _GstHLSDemuxStream
|
||||||
gboolean in_partial_segments;
|
gboolean in_partial_segments;
|
||||||
guint part_idx;
|
guint part_idx;
|
||||||
|
|
||||||
|
/* Preload helper, that manages blocking preload downloads */
|
||||||
|
GstHLSDemuxPreloader *preloader;
|
||||||
|
|
||||||
/* Whether we need to typefind the next buffer */
|
/* Whether we need to typefind the next buffer */
|
||||||
gboolean do_typefind;
|
gboolean do_typefind;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
hls_sources = [
|
hls_sources = [
|
||||||
'hls/gsthlsdemux.c',
|
'hls/gsthlsdemux.c',
|
||||||
|
'hls/gsthlsdemux-preloader.c',
|
||||||
'hls/gsthlsdemux-util.c',
|
'hls/gsthlsdemux-util.c',
|
||||||
'hls/gsthlselement.c',
|
'hls/gsthlselement.c',
|
||||||
'hls/m3u8.c',
|
'hls/m3u8.c',
|
||||||
|
|
Loading…
Reference in a new issue