mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-19 14:56:36 +00:00
mssdemux: more manifest parsing and helper functions
Now the mss manifest is able to generate the files urls
This commit is contained in:
parent
5291985efe
commit
6b63a7dc81
2 changed files with 170 additions and 8 deletions
|
@ -27,11 +27,41 @@
|
|||
|
||||
#include "gstmssmanifest.h"
|
||||
|
||||
#define MSS_NODE_STREAM_FRAGMENT "c"
|
||||
#define MSS_NODE_STREAM_QUALITY "QualityLevel"
|
||||
|
||||
#define MSS_PROP_BITRATE "Bitrate"
|
||||
#define MSS_PROP_DURATION "d"
|
||||
#define MSS_PROP_NUMBER "n"
|
||||
#define MSS_PROP_TIME "t"
|
||||
#define MSS_PROP_URL "Url"
|
||||
|
||||
/* TODO check if atoi is successful? */
|
||||
|
||||
typedef struct _GstMssManifestStreamFragment
|
||||
{
|
||||
guint number;
|
||||
guint64 time;
|
||||
guint64 duration;
|
||||
} GstMssManifestStreamFragment;
|
||||
|
||||
struct _GstMssManifestStream
|
||||
{
|
||||
xmlNodePtr xmlnode;
|
||||
|
||||
gint selectedQualityIndex;
|
||||
|
||||
GList *fragments;
|
||||
GList *qualities;
|
||||
|
||||
gchar *url;
|
||||
|
||||
GList *current_fragment;
|
||||
GList *current_quality;
|
||||
|
||||
/* TODO move this to somewhere static */
|
||||
GRegex *regex_bitrate;
|
||||
GRegex *regex_position;
|
||||
};
|
||||
|
||||
struct _GstMssManifest
|
||||
|
@ -42,6 +72,89 @@ struct _GstMssManifest
|
|||
GSList *streams;
|
||||
};
|
||||
|
||||
static gboolean
|
||||
node_has_type (xmlNodePtr node, const gchar * name)
|
||||
{
|
||||
return strcmp ((gchar *) node->name, name) == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_gst_mss_manifest_stream_init (GstMssManifestStream * stream, xmlNodePtr node)
|
||||
{
|
||||
xmlNodePtr iter;
|
||||
GstMssManifestStreamFragment *previous_fragment = NULL;
|
||||
guint fragment_number = 0;
|
||||
guint fragment_time_accum = 0;
|
||||
GError *gerror = NULL;
|
||||
|
||||
stream->xmlnode = node;
|
||||
|
||||
/* get the base url path generator */
|
||||
stream->url = (gchar *) xmlGetProp (node, (xmlChar *) MSS_PROP_URL);
|
||||
|
||||
for (iter = node->children; iter; iter = iter->next) {
|
||||
if (node_has_type (iter, MSS_NODE_STREAM_FRAGMENT)) {
|
||||
gchar *duration_str;
|
||||
gchar *time_str;
|
||||
gchar *seqnum_str;
|
||||
GstMssManifestStreamFragment *fragment =
|
||||
g_new (GstMssManifestStreamFragment, 1);
|
||||
|
||||
duration_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_DURATION);
|
||||
time_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_TIME);
|
||||
seqnum_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_NUMBER);
|
||||
|
||||
/* use the node's seq number or use the previous + 1 */
|
||||
if (seqnum_str) {
|
||||
fragment->number = atoi (seqnum_str);
|
||||
g_free (seqnum_str);
|
||||
} else {
|
||||
fragment->number = fragment_number;
|
||||
}
|
||||
fragment_number = fragment->number + 1;
|
||||
|
||||
if (time_str) {
|
||||
fragment->time = atoi (time_str);
|
||||
g_free (time_str);
|
||||
} else {
|
||||
fragment->time = fragment_time_accum;
|
||||
}
|
||||
|
||||
/* if we have a previous fragment, means we need to set its duration */
|
||||
if (previous_fragment)
|
||||
previous_fragment->duration = fragment->time - previous_fragment->time;
|
||||
|
||||
if (duration_str) {
|
||||
fragment->duration = atoi (duration_str);
|
||||
|
||||
previous_fragment = NULL;
|
||||
fragment_time_accum += fragment->duration;
|
||||
g_free (duration_str);
|
||||
} else {
|
||||
/* store to set the duration at the next iteration */
|
||||
previous_fragment = fragment;
|
||||
}
|
||||
|
||||
/* we reverse it later */
|
||||
stream->fragments = g_list_prepend (stream->fragments, fragment);
|
||||
|
||||
} else if (node_has_type (iter, MSS_NODE_STREAM_QUALITY)) {
|
||||
stream->qualities = g_list_prepend (stream->qualities, iter);
|
||||
} else {
|
||||
/* TODO gst log this */
|
||||
}
|
||||
}
|
||||
|
||||
stream->fragments = g_list_reverse (stream->fragments);
|
||||
stream->qualities = g_list_reverse (stream->qualities);
|
||||
|
||||
stream->current_fragment = stream->fragments;
|
||||
stream->current_quality = stream->qualities;
|
||||
|
||||
stream->regex_bitrate = g_regex_new ("\\{[Bb]itrate\\}", 0, 0, &gerror);
|
||||
stream->regex_position = g_regex_new ("\\{start[ _]time\\}", 0, 0, &gerror);
|
||||
}
|
||||
|
||||
GstMssManifest *
|
||||
gst_mss_manifest_new (const GstBuffer * data)
|
||||
{
|
||||
|
@ -61,19 +174,31 @@ gst_mss_manifest_new (const GstBuffer * data)
|
|||
GstMssManifestStream *stream = g_new0 (GstMssManifestStream, 1);
|
||||
|
||||
manifest->streams = g_slist_append (manifest->streams, stream);
|
||||
stream->xmlnode = nodeiter;
|
||||
_gst_mss_manifest_stream_init (stream, nodeiter);
|
||||
}
|
||||
}
|
||||
|
||||
return manifest;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mss_manifest_stream_free (GstMssManifestStream * stream)
|
||||
{
|
||||
g_list_free_full (stream->fragments, g_free);
|
||||
g_list_free (stream->qualities);
|
||||
g_free (stream->url);
|
||||
g_regex_unref (stream->regex_position);
|
||||
g_regex_unref (stream->regex_bitrate);
|
||||
g_free (stream);
|
||||
}
|
||||
|
||||
void
|
||||
gst_mss_manifest_free (GstMssManifest * manifest)
|
||||
{
|
||||
g_return_if_fail (manifest != NULL);
|
||||
|
||||
g_slist_free_full (manifest->streams, g_free);
|
||||
g_slist_free_full (manifest->streams,
|
||||
(GDestroyNotify) gst_mss_manifest_stream_free);
|
||||
|
||||
xmlFreeDoc (manifest->xml);
|
||||
g_free (manifest);
|
||||
|
@ -208,12 +333,7 @@ gst_mss_manifest_stream_get_caps (GstMssManifestStream * stream)
|
|||
{
|
||||
GstMssManifestStreamType streamtype =
|
||||
gst_mss_manifest_stream_get_type (stream);
|
||||
|
||||
/* TODO properly get the stream */
|
||||
xmlNodePtr qualitylevel = stream->xmlnode->children;
|
||||
while (strcmp ((gchar *) qualitylevel->name, "QualityLevel")) {
|
||||
qualitylevel = qualitylevel->next;
|
||||
}
|
||||
xmlNodePtr qualitylevel = stream->current_quality->data;
|
||||
|
||||
if (streamtype == MSS_STREAM_TYPE_VIDEO)
|
||||
return
|
||||
|
@ -227,6 +347,46 @@ gst_mss_manifest_stream_get_caps (GstMssManifestStream * stream)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
GstFlowReturn
|
||||
gst_mss_manifest_stream_get_fragment_url (GstMssManifestStream * stream,
|
||||
gchar ** url)
|
||||
{
|
||||
gchar *tmp;
|
||||
gchar *bitrate_str;
|
||||
gchar *start_time_str;
|
||||
GstMssManifestStreamFragment *fragment = stream->current_fragment->data;
|
||||
|
||||
if (stream->current_fragment == NULL) /* stream is over */
|
||||
return GST_FLOW_UNEXPECTED;
|
||||
|
||||
bitrate_str =
|
||||
(gchar *) xmlGetProp (stream->current_quality->data,
|
||||
(xmlChar *) MSS_PROP_BITRATE);
|
||||
start_time_str = g_strdup_printf ("%" G_GUINT64_FORMAT, fragment->time);
|
||||
|
||||
tmp = g_regex_replace_literal (stream->regex_bitrate, stream->url,
|
||||
strlen (stream->url), 0, bitrate_str, 0, NULL);
|
||||
*url = g_regex_replace_literal (stream->regex_position, tmp,
|
||||
strlen (tmp), 0, start_time_str, 0, NULL);
|
||||
|
||||
g_free (tmp);
|
||||
g_free (start_time_str);
|
||||
g_free (bitrate_str);
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
GstFlowReturn
|
||||
gst_mss_manifest_stream_advance_fragment (GstMssManifestStream * stream)
|
||||
{
|
||||
if (stream->current_fragment == NULL)
|
||||
return GST_FLOW_UNEXPECTED;
|
||||
|
||||
stream->current_fragment = g_list_next (stream->current_fragment);
|
||||
if (stream->current_fragment == NULL);
|
||||
return GST_FLOW_UNEXPECTED;
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
gst_mss_manifest_stream_type_name (GstMssManifestStreamType streamtype)
|
||||
{
|
||||
|
|
|
@ -44,6 +44,8 @@ GSList * gst_mss_manifest_get_streams (GstMssManifest * manifest);
|
|||
|
||||
GstMssManifestStreamType gst_mss_manifest_stream_get_type (GstMssManifestStream *stream);
|
||||
GstCaps * gst_mss_manifest_stream_get_caps (GstMssManifestStream * stream);
|
||||
GstFlowReturn gst_mss_manifest_stream_get_fragment_url (GstMssManifestStream * stream, gchar ** url);
|
||||
GstFlowReturn gst_mss_manifest_stream_advance_fragment (GstMssManifestStream * stream);
|
||||
|
||||
const gchar * gst_mss_manifest_stream_type_name (GstMssManifestStreamType streamtype);
|
||||
|
||||
|
|
Loading…
Reference in a new issue