mssdemux: more manifest parsing and helper functions

Now the mss manifest is able to generate the files urls
This commit is contained in:
Thiago Santos 2012-11-16 17:29:38 -03:00
parent 5291985efe
commit 6b63a7dc81
2 changed files with 170 additions and 8 deletions

View file

@ -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)
{

View file

@ -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);