dash: split mpdparser, mpdclient and xmlhelper

provide a separate namespace for mpd helper
for xml parsing and the real mpd parsing.
This commit is contained in:
Stéphane Cerveau 2019-05-20 18:48:23 +02:00
parent 4eac9d0ae6
commit 86b251b7d1
12 changed files with 5127 additions and 4920 deletions

View file

@ -520,7 +520,7 @@ gst_dash_demux_get_presentation_offset (GstAdaptiveDemux * demux,
GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream; GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (demux); GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (demux);
return gst_mpd_parser_get_stream_presentation_offset (dashdemux->client, return gst_mpd_client_get_stream_presentation_offset (dashdemux->client,
dashstream->index); dashstream->index);
} }
@ -529,7 +529,7 @@ gst_dash_demux_get_period_start_time (GstAdaptiveDemux * demux)
{ {
GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (demux); GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (demux);
return gst_mpd_parser_get_period_start_time (dashdemux->client); return gst_mpd_client_get_period_start_time (dashdemux->client);
} }
static void static void
@ -778,14 +778,14 @@ gst_dash_demux_setup_all_streams (GstDashDemux * demux)
gst_mpd_client_get_period_index (demux->client)); gst_mpd_client_get_period_index (demux->client));
/* clean old active stream list, if any */ /* clean old active stream list, if any */
gst_active_streams_free (demux->client); gst_mpd_client_active_streams_free (demux->client);
if (!gst_dash_demux_setup_mpdparser_streams (demux, demux->client)) { if (!gst_dash_demux_setup_mpdparser_streams (demux, demux->client)) {
return FALSE; return FALSE;
} }
GST_DEBUG_OBJECT (demux, "Creating stream objects"); GST_DEBUG_OBJECT (demux, "Creating stream objects");
for (i = 0; i < gst_mpdparser_get_nb_active_stream (demux->client); i++) { for (i = 0; i < gst_mpd_client_get_nb_active_stream (demux->client); i++) {
GstDashDemuxStream *stream; GstDashDemuxStream *stream;
GstActiveStream *active_stream; GstActiveStream *active_stream;
GstCaps *caps; GstCaps *caps;
@ -794,7 +794,8 @@ gst_dash_demux_setup_all_streams (GstDashDemux * demux)
gchar *lang = NULL; gchar *lang = NULL;
GstTagList *tags = NULL; GstTagList *tags = NULL;
active_stream = gst_mpdparser_get_active_stream_by_index (demux->client, i); active_stream =
gst_mpd_client_get_active_stream_by_index (demux->client, i);
if (active_stream == NULL) if (active_stream == NULL)
continue; continue;
@ -1036,7 +1037,7 @@ gst_dash_demux_process_manifest (GstAdaptiveDemux * demux, GstBuffer * buf)
if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) { if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
manifest = (gchar *) mapinfo.data; manifest = (gchar *) mapinfo.data;
if (gst_mpd_parse (dashdemux->client, manifest, mapinfo.size)) { if (gst_mpd_client_parse (dashdemux->client, manifest, mapinfo.size)) {
if (gst_mpd_client_setup_media_presentation (dashdemux->client, 0, 0, if (gst_mpd_client_setup_media_presentation (dashdemux->client, 0, 0,
NULL)) { NULL)) {
ret = TRUE; ret = TRUE;
@ -1232,7 +1233,7 @@ gst_dash_demux_stream_update_headers_info (GstAdaptiveDemuxStream * stream)
if (path != NULL) { if (path != NULL) {
stream->fragment.header_uri = stream->fragment.header_uri =
gst_uri_join_strings (gst_mpdparser_get_baseURL (dashdemux->client, gst_uri_join_strings (gst_mpd_client_get_baseURL (dashdemux->client,
dashstream->index), path); dashstream->index), path);
g_free (path); g_free (path);
path = NULL; path = NULL;
@ -1244,7 +1245,7 @@ gst_dash_demux_stream_update_headers_info (GstAdaptiveDemuxStream * stream)
if (path != NULL) { if (path != NULL) {
stream->fragment.index_uri = stream->fragment.index_uri =
gst_uri_join_strings (gst_mpdparser_get_baseURL (dashdemux->client, gst_uri_join_strings (gst_mpd_client_get_baseURL (dashdemux->client,
dashstream->index), path); dashstream->index), path);
g_free (path); g_free (path);
} }
@ -1501,9 +1502,9 @@ gst_dash_demux_stream_seek (GstAdaptiveDemuxStream * stream, gboolean forward,
if (is_isobmff) { if (is_isobmff) {
GstClockTime period_start, offset; GstClockTime period_start, offset;
period_start = gst_mpd_parser_get_period_start_time (dashdemux->client); period_start = gst_mpd_client_get_period_start_time (dashdemux->client);
offset = offset =
gst_mpd_parser_get_stream_presentation_offset (dashdemux->client, gst_mpd_client_get_stream_presentation_offset (dashdemux->client,
dashstream->index); dashstream->index);
if (G_UNLIKELY (ts < period_start)) if (G_UNLIKELY (ts < period_start))
@ -2198,12 +2199,12 @@ gst_dash_demux_stream_select_bitrate (GstAdaptiveDemuxStream * stream,
if (GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (base_demux) || if (GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (base_demux) ||
ABS (base_demux->segment.rate) <= 1.0) { ABS (base_demux->segment.rate) <= 1.0) {
new_index = new_index =
gst_mpdparser_get_rep_idx_with_max_bandwidth (rep_list, bitrate, gst_mpd_client_get_rep_idx_with_max_bandwidth (rep_list, bitrate,
demux->max_video_width, demux->max_video_height, demux->max_video_width, demux->max_video_height,
demux->max_video_framerate_n, demux->max_video_framerate_d); demux->max_video_framerate_n, demux->max_video_framerate_d);
} else { } else {
new_index = new_index =
gst_mpdparser_get_rep_idx_with_max_bandwidth (rep_list, gst_mpd_client_get_rep_idx_with_max_bandwidth (rep_list,
bitrate / ABS (base_demux->segment.rate), demux->max_video_width, bitrate / ABS (base_demux->segment.rate), demux->max_video_width,
demux->max_video_height, demux->max_video_framerate_n, demux->max_video_height, demux->max_video_framerate_n,
demux->max_video_framerate_d); demux->max_video_framerate_d);
@ -2211,7 +2212,7 @@ gst_dash_demux_stream_select_bitrate (GstAdaptiveDemuxStream * stream,
/* if no representation has the required bandwidth, take the lowest one */ /* if no representation has the required bandwidth, take the lowest one */
if (new_index == -1) if (new_index == -1)
new_index = gst_mpdparser_get_rep_idx_with_min_bandwidth (rep_list); new_index = gst_mpd_client_get_rep_idx_with_min_bandwidth (rep_list);
if (new_index != active_stream->representation_idx) { if (new_index != active_stream->representation_idx) {
GstRepresentationNode *rep = g_list_nth_data (rep_list, new_index); GstRepresentationNode *rep = g_list_nth_data (rep_list, new_index);
@ -2346,7 +2347,7 @@ gst_dash_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek)
GST_DEBUG_OBJECT (demux, "Seeking to Period %d", current_period); GST_DEBUG_OBJECT (demux, "Seeking to Period %d", current_period);
/* clean old active stream list, if any */ /* clean old active stream list, if any */
gst_active_streams_free (dashdemux->client); gst_mpd_client_active_streams_free (dashdemux->client);
dashdemux->trickmode_no_audio = trickmode_no_audio; dashdemux->trickmode_no_audio = trickmode_no_audio;
/* setup video, audio and subtitle streams, starting from the new Period */ /* setup video, audio and subtitle streams, starting from the new Period */
@ -2356,7 +2357,7 @@ gst_dash_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek)
streams = demux->next_streams; streams = demux->next_streams;
} else if (dashdemux->trickmode_no_audio != trickmode_no_audio) { } else if (dashdemux->trickmode_no_audio != trickmode_no_audio) {
/* clean old active stream list, if any */ /* clean old active stream list, if any */
gst_active_streams_free (dashdemux->client); gst_mpd_client_active_streams_free (dashdemux->client);
dashdemux->trickmode_no_audio = trickmode_no_audio; dashdemux->trickmode_no_audio = trickmode_no_audio;
/* setup video, audio and subtitle streams, starting from the new Period */ /* setup video, audio and subtitle streams, starting from the new Period */
@ -2404,7 +2405,7 @@ gst_dash_demux_update_manifest_data (GstAdaptiveDemux * demux,
new_client->mpd_base_uri = g_strdup (demux->manifest_base_uri); new_client->mpd_base_uri = g_strdup (demux->manifest_base_uri);
gst_buffer_map (buffer, &mapinfo, GST_MAP_READ); gst_buffer_map (buffer, &mapinfo, GST_MAP_READ);
if (gst_mpd_parse (new_client, (gchar *) mapinfo.data, mapinfo.size)) { if (gst_mpd_client_parse (new_client, (gchar *) mapinfo.data, mapinfo.size)) {
const gchar *period_id; const gchar *period_id;
guint period_idx; guint period_idx;
GList *iter; GList *iter;
@ -2490,7 +2491,7 @@ gst_dash_demux_update_manifest_data (GstAdaptiveDemux * demux,
/* _get_next_fragment_timestamp() returned relative timestamp to /* _get_next_fragment_timestamp() returned relative timestamp to
* corresponding period start, but _client_stream_seek expects absolute * corresponding period start, but _client_stream_seek expects absolute
* MPD time. */ * MPD time. */
ts += gst_mpd_parser_get_period_start_time (dashdemux->client); ts += gst_mpd_client_get_period_start_time (dashdemux->client);
GST_DEBUG_OBJECT (GST_ADAPTIVE_DEMUX_STREAM_PAD (demux_stream), GST_DEBUG_OBJECT (GST_ADAPTIVE_DEMUX_STREAM_PAD (demux_stream),
"Current position: %" GST_TIME_FORMAT ", updating to %" "Current position: %" GST_TIME_FORMAT ", updating to %"

View file

@ -34,7 +34,7 @@
#include <gst/adaptivedemux/gstadaptivedemux.h> #include <gst/adaptivedemux/gstadaptivedemux.h>
#include <gst/base/gstadapter.h> #include <gst/base/gstadapter.h>
#include <gst/base/gstdataqueue.h> #include <gst/base/gstdataqueue.h>
#include "gstmpdparser.h" #include "gstmpdclient.h"
#include <gst/isoff/gstisoff.h> #include <gst/isoff/gstisoff.h>
#include <gst/uridownloader/gsturidownloader.h> #include <gst/uridownloader/gsturidownloader.h>

2915
ext/dash/gstmpdclient.c Normal file

File diff suppressed because it is too large Load diff

142
ext/dash/gstmpdclient.h Normal file
View file

@ -0,0 +1,142 @@
/* GStreamer
*
* Copyright (C) 2019 Collabora Ltd.
* Author: Stéphane Cerveau <scerveau@collabora.com>
*
* 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.1 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 (COPYING); if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_MPDCLIENT_H__
#define __GST_MPDCLIENT_H__
#include "gstmpdparser.h"
G_BEGIN_DECLS
#define GST_MPD_CLIENT_LOCK(c) g_mutex_lock (&c->lock);
#define GST_MPD_CLIENT_UNLOCK(c) g_mutex_unlock (&c->lock);
typedef struct _GstMpdClient GstMpdClient;
struct _GstMpdClient
{
GstMPDNode *mpd_node; /* active MPD manifest file */
GList *periods; /* list of GstStreamPeriod */
guint period_idx; /* index of current Period */
GList *active_streams; /* list of GstActiveStream */
guint update_failed_count;
gchar *mpd_uri; /* manifest file URI */
gchar *mpd_base_uri; /* base URI for resolving relative URIs.
* this will be different for redirects */
/* profiles */
gboolean profile_isoff_ondemand;
GstUriDownloader * downloader;
};
/* Basic initialization/deinitialization functions */
GstMpdClient *gst_mpd_client_new (void);
void gst_mpd_client_active_streams_free (GstMpdClient * client);
void gst_mpd_client_free (GstMpdClient * client);
/* main mpd parsing methods from xml data */
gboolean gst_mpd_client_parse (GstMpdClient * client, const gchar * data, gint size);
void gst_mpd_client_set_uri_downloader (GstMpdClient * client, GstUriDownloader * download);
void gst_mpd_client_check_profiles (GstMpdClient * client);
void gst_mpd_client_fetch_on_load_external_resources (GstMpdClient * client);
/* Streaming management */
gboolean gst_mpd_client_setup_media_presentation (GstMpdClient *client, GstClockTime time, gint period_index, const gchar *period_id);
gboolean gst_mpd_client_setup_streaming (GstMpdClient * client, GstAdaptationSetNode * adapt_set);
gboolean gst_mpd_client_setup_representation (GstMpdClient *client, GstActiveStream *stream, GstRepresentationNode *representation);
GstClockTime gst_mpd_client_get_next_fragment_duration (GstMpdClient * client, GstActiveStream * stream);
GstClockTime gst_mpd_client_get_media_presentation_duration (GstMpdClient *client);
GstClockTime gst_mpd_client_get_maximum_segment_duration (GstMpdClient * client);
gboolean gst_mpd_client_get_last_fragment_timestamp_end (GstMpdClient * client, guint stream_idx, GstClockTime * ts);
gboolean gst_mpd_client_get_next_fragment_timestamp (GstMpdClient * client, guint stream_idx, GstClockTime * ts);
gboolean gst_mpd_client_get_next_fragment (GstMpdClient *client, guint indexStream, GstMediaFragmentInfo * fragment);
gboolean gst_mpd_client_get_next_header (GstMpdClient *client, gchar **uri, guint stream_idx, gint64 * range_start, gint64 * range_end);
gboolean gst_mpd_client_get_next_header_index (GstMpdClient *client, gchar **uri, guint stream_idx, gint64 * range_start, gint64 * range_end);
gboolean gst_mpd_client_is_live (GstMpdClient * client);
gboolean gst_mpd_client_stream_seek (GstMpdClient * client, GstActiveStream * stream, gboolean forward, GstSeekFlags flags, GstClockTime ts, GstClockTime * final_ts);
gboolean gst_mpd_client_seek_to_time (GstMpdClient * client, GDateTime * time);
GstClockTime gst_mpd_client_get_stream_presentation_offset (GstMpdClient *client, guint stream_idx);
gchar** gst_mpd_client_get_utc_timing_sources (GstMpdClient *client, guint methods, GstMPDUTCTimingType *selected_method);
GstClockTime gst_mpd_client_get_period_start_time (GstMpdClient *client);
/* Period selection */
guint gst_mpd_client_get_period_index_at_time (GstMpdClient * client, GstDateTime * time);
gboolean gst_mpd_client_set_period_index (GstMpdClient *client, guint period_idx);
gboolean gst_mpd_client_set_period_id (GstMpdClient *client, const gchar * period_id);
guint gst_mpd_client_get_period_index (GstMpdClient *client);
const gchar *gst_mpd_client_get_period_id (GstMpdClient *client);
gboolean gst_mpd_client_has_next_period (GstMpdClient *client);
gboolean gst_mpd_client_has_previous_period (GstMpdClient * client);
/* Representation selection */
gint gst_mpd_client_get_rep_idx_with_max_bandwidth (GList *Representations, gint64 max_bandwidth, gint max_video_width, gint max_video_height, gint max_video_framerate_n, gint max_video_framerate_d);
gint gst_mpd_client_get_rep_idx_with_min_bandwidth (GList * Representations);
GstDateTime *
gst_mpd_client_get_availability_start_time (GstMpdClient * client);
/* URL management */
const gchar *gst_mpd_client_get_baseURL (GstMpdClient *client, guint indexStream);
gchar *gst_mpd_client_parse_baseURL (GstMpdClient * client, GstActiveStream * stream, gchar ** query);
/* Active stream */
guint gst_mpd_client_get_nb_active_stream (GstMpdClient *client);
GstActiveStream *gst_mpd_client_get_active_stream_by_index (GstMpdClient *client, guint stream_idx);
gboolean gst_mpd_client_active_stream_contains_subtitles (GstActiveStream * stream);
/* AdaptationSet */
guint gst_mpd_client_get_nb_adaptationSet (GstMpdClient *client);
GList * gst_mpd_client_get_adaptation_sets (GstMpdClient * client);
/* Segment */
gboolean gst_mpd_client_has_next_segment (GstMpdClient * client, GstActiveStream * stream, gboolean forward);
GstFlowReturn gst_mpd_client_advance_segment (GstMpdClient * client, GstActiveStream * stream, gboolean forward);
void gst_mpd_client_seek_to_first_segment (GstMpdClient * client);
GstDateTime *gst_mpd_client_get_next_segment_availability_start_time (GstMpdClient * client, GstActiveStream * stream);
/* Get audio/video stream parameters (caps, width, height, rate, number of channels) */
GstCaps * gst_mpd_client_get_stream_caps (GstActiveStream * stream);
gboolean gst_mpd_client_get_bitstream_switching_flag (GstActiveStream * stream);
guint gst_mpd_client_get_video_stream_width (GstActiveStream * stream);
guint gst_mpd_client_get_video_stream_height (GstActiveStream * stream);
gboolean gst_mpd_client_get_video_stream_framerate (GstActiveStream * stream, gint * fps_num, gint * fps_den);
guint gst_mpd_client_get_audio_stream_rate (GstActiveStream * stream);
guint gst_mpd_client_get_audio_stream_num_channels (GstActiveStream * stream);
/* Support multi language */
guint gst_mpd_client_get_list_and_nb_of_audio_language (GstMpdClient *client, GList **lang);
gint64 gst_mpd_client_calculate_time_difference (const GstDateTime * t1, const GstDateTime * t2);
GstDateTime *gst_mpd_client_add_time_difference (GstDateTime * t1, gint64 usecs);
gint64 gst_mpd_client_parse_default_presentation_delay(GstMpdClient * client, const gchar * default_presentation_delay);
/* profiles */
gboolean gst_mpd_client_has_isoff_ondemand_profile (GstMpdClient *client);
G_END_DECLS
#endif /* __GST_MPDCLIENT_H__ */

78
ext/dash/gstmpdhelper.c Normal file
View file

@ -0,0 +1,78 @@
/* GStreamer
*
* Copyright (C) 2019 Collabora Ltd.
* Author: Stéphane Cerveau <scerveau@collabora.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "gstmpdhelper.h"
gboolean
gst_mpd_helper_get_mpd_type (xmlNode * a_node,
const gchar * property_name, GstMPDFileType * property_value)
{
xmlChar *prop_string;
gboolean exists = FALSE;
*property_value = GST_MPD_FILE_TYPE_STATIC; /* default */
prop_string = xmlGetProp (a_node, (const xmlChar *) property_name);
if (prop_string) {
if (xmlStrcmp (prop_string, (xmlChar *) "OnDemand") == 0
|| xmlStrcmp (prop_string, (xmlChar *) "static") == 0) {
exists = TRUE;
*property_value = GST_MPD_FILE_TYPE_STATIC;
GST_LOG (" - %s: static", property_name);
} else if (xmlStrcmp (prop_string, (xmlChar *) "Live") == 0
|| xmlStrcmp (prop_string, (xmlChar *) "dynamic") == 0) {
exists = TRUE;
*property_value = GST_MPD_FILE_TYPE_DYNAMIC;
GST_LOG (" - %s: dynamic", property_name);
} else {
GST_WARNING ("failed to parse MPD type property %s from xml string %s",
property_name, prop_string);
}
xmlFree (prop_string);
}
return exists;
}
gboolean
gst_mpd_helper_get_SAP_type (xmlNode * a_node,
const gchar * property_name, GstMPDSAPType * property_value)
{
xmlChar *prop_string;
guint prop_SAP_type = 0;
gboolean exists = FALSE;
prop_string = xmlGetProp (a_node, (const xmlChar *) property_name);
if (prop_string) {
if (sscanf ((gchar *) prop_string, "%u", &prop_SAP_type) == 1
&& prop_SAP_type <= 6) {
exists = TRUE;
*property_value = (GstMPDSAPType) prop_SAP_type;
GST_LOG (" - %s: %u", property_name, prop_SAP_type);
} else {
GST_WARNING
("failed to parse unsigned integer property %s from xml string %s",
property_name, prop_string);
}
xmlFree (prop_string);
}
return exists;
}

49
ext/dash/gstmpdhelper.h Normal file
View file

@ -0,0 +1,49 @@
/* GStreamer
*
* Copyright (C) 2019 Collabora Ltd.
* Author: Stéphane Cerveau <scerveau@collabora.com>
*
* 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.1 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 (COPYING); if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_MPDHELPER_H__
#define __GST_MPDHELPER_H__
#include "gstxmlhelper.h"
G_BEGIN_DECLS
typedef enum
{
GST_MPD_FILE_TYPE_STATIC,
GST_MPD_FILE_TYPE_DYNAMIC
} GstMPDFileType;
typedef enum
{
GST_SAP_TYPE_0 = 0,
GST_SAP_TYPE_1,
GST_SAP_TYPE_2,
GST_SAP_TYPE_3,
GST_SAP_TYPE_4,
GST_SAP_TYPE_5,
GST_SAP_TYPE_6
} GstMPDSAPType;
gboolean gst_mpd_helper_get_mpd_type (xmlNode * a_node, const gchar * property_name, GstMPDFileType * property_value);
gboolean gst_mpd_helper_get_SAP_type (xmlNode * a_node, const gchar * property_name, GstMPDSAPType * property_value);
G_END_DECLS
#endif /* __GST_MPDHELPER_H__ */

File diff suppressed because it is too large Load diff

View file

@ -30,10 +30,10 @@
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/uridownloader/gsturidownloader.h> #include <gst/uridownloader/gsturidownloader.h>
#include <gst/base/gstadapter.h> #include <gst/base/gstadapter.h>
#include "gstmpdhelper.h"
G_BEGIN_DECLS G_BEGIN_DECLS
typedef struct _GstMpdClient GstMpdClient;
typedef struct _GstActiveStream GstActiveStream; typedef struct _GstActiveStream GstActiveStream;
typedef struct _GstStreamPeriod GstStreamPeriod; typedef struct _GstStreamPeriod GstStreamPeriod;
typedef struct _GstMediaFragmentInfo GstMediaFragmentInfo; typedef struct _GstMediaFragmentInfo GstMediaFragmentInfo;
@ -50,10 +50,7 @@ typedef struct _GstSegmentListNode GstSegmentListNode;
typedef struct _GstSegmentTemplateNode GstSegmentTemplateNode; typedef struct _GstSegmentTemplateNode GstSegmentTemplateNode;
typedef struct _GstSegmentURLNode GstSegmentURLNode; typedef struct _GstSegmentURLNode GstSegmentURLNode;
typedef struct _GstBaseURL GstBaseURL; typedef struct _GstBaseURL GstBaseURL;
typedef struct _GstRange GstRange;
typedef struct _GstRatio GstRatio;
typedef struct _GstFrameRate GstFrameRate;
typedef struct _GstConditionalUintType GstConditionalUintType;
typedef struct _GstSubsetNode GstSubsetNode; typedef struct _GstSubsetNode GstSubsetNode;
typedef struct _GstProgramInformationNode GstProgramInformationNode; typedef struct _GstProgramInformationNode GstProgramInformationNode;
typedef struct _GstMetricsRangeNode GstMetricsRangeNode; typedef struct _GstMetricsRangeNode GstMetricsRangeNode;
@ -65,8 +62,6 @@ typedef struct _GstSegmentBaseType GstSegmentBaseType;
typedef struct _GstURLType GstURLType; typedef struct _GstURLType GstURLType;
typedef struct _GstMultSegmentBaseType GstMultSegmentBaseType; typedef struct _GstMultSegmentBaseType GstMultSegmentBaseType;
#define GST_MPD_CLIENT_LOCK(c) g_mutex_lock (&c->lock);
#define GST_MPD_CLIENT_UNLOCK(c) g_mutex_unlock (&c->lock);
#define GST_MPD_DURATION_NONE ((guint64)-1) #define GST_MPD_DURATION_NONE ((guint64)-1)
@ -78,22 +73,6 @@ typedef enum
GST_STREAM_APPLICATION /* application stream (optional): for timed text/subtitles */ GST_STREAM_APPLICATION /* application stream (optional): for timed text/subtitles */
} GstStreamMimeType; } GstStreamMimeType;
typedef enum
{
GST_MPD_FILE_TYPE_STATIC,
GST_MPD_FILE_TYPE_DYNAMIC
} GstMPDFileType;
typedef enum
{
GST_SAP_TYPE_0 = 0,
GST_SAP_TYPE_1,
GST_SAP_TYPE_2,
GST_SAP_TYPE_3,
GST_SAP_TYPE_4,
GST_SAP_TYPE_5,
GST_SAP_TYPE_6
} GstSAPType;
typedef enum typedef enum
{ {
@ -120,30 +99,6 @@ struct _GstBaseURL
gchar *byteRange; gchar *byteRange;
}; };
struct _GstRange
{
guint64 first_byte_pos;
guint64 last_byte_pos;
};
struct _GstRatio
{
guint num;
guint den;
};
struct _GstFrameRate
{
guint num;
guint den;
};
struct _GstConditionalUintType
{
gboolean flag;
guint value;
};
struct _GstSNode struct _GstSNode
{ {
guint64 t; guint64 t;
@ -160,14 +115,14 @@ struct _GstSegmentTimelineNode
struct _GstURLType struct _GstURLType
{ {
gchar *sourceURL; gchar *sourceURL;
GstRange *range; GstXMLRange *range;
}; };
struct _GstSegmentBaseType struct _GstSegmentBaseType
{ {
guint timescale; guint timescale;
guint64 presentationTimeOffset; guint64 presentationTimeOffset;
GstRange *indexRange; GstXMLRange *indexRange;
gboolean indexRangeExact; gboolean indexRangeExact;
/* Initialization node */ /* Initialization node */
GstURLType *Initialization; GstURLType *Initialization;
@ -211,9 +166,9 @@ struct _GstSegmentTemplateNode
struct _GstSegmentURLNode struct _GstSegmentURLNode
{ {
gchar *media; gchar *media;
GstRange *mediaRange; GstXMLRange *mediaRange;
gchar *index; gchar *index;
GstRange *indexRange; GstXMLRange *indexRange;
}; };
struct _GstRepresentationBaseType struct _GstRepresentationBaseType
@ -221,16 +176,16 @@ struct _GstRepresentationBaseType
gchar *profiles; gchar *profiles;
guint width; guint width;
guint height; guint height;
GstRatio *sar; GstXMLRatio *sar;
GstFrameRate *minFrameRate; GstXMLFrameRate *minFrameRate;
GstFrameRate *maxFrameRate; GstXMLFrameRate *maxFrameRate;
GstFrameRate *frameRate; GstXMLFrameRate *frameRate;
gchar *audioSamplingRate; gchar *audioSamplingRate;
gchar *mimeType; gchar *mimeType;
gchar *segmentProfiles; gchar *segmentProfiles;
gchar *codecs; gchar *codecs;
gdouble maximumSAPPeriod; gdouble maximumSAPPeriod;
GstSAPType startWithSAP; GstMPDSAPType startWithSAP;
gdouble maxPlayoutRate; gdouble maxPlayoutRate;
gboolean codingDependency; gboolean codingDependency;
gchar *scanType; gchar *scanType;
@ -285,7 +240,7 @@ struct _GstContentComponentNode
guint id; guint id;
gchar *lang; /* LangVectorType RFC 5646 */ gchar *lang; /* LangVectorType RFC 5646 */
gchar *contentType; gchar *contentType;
GstRatio *par; GstXMLRatio *par;
/* list of Accessibility DescriptorType nodes */ /* list of Accessibility DescriptorType nodes */
GList *Accessibility; GList *Accessibility;
/* list of Role DescriptorType nodes */ /* list of Role DescriptorType nodes */
@ -302,16 +257,16 @@ struct _GstAdaptationSetNode
guint group; guint group;
gchar *lang; /* LangVectorType RFC 5646 */ gchar *lang; /* LangVectorType RFC 5646 */
gchar *contentType; gchar *contentType;
GstRatio *par; GstXMLRatio *par;
guint minBandwidth; guint minBandwidth;
guint maxBandwidth; guint maxBandwidth;
guint minWidth; guint minWidth;
guint maxWidth; guint maxWidth;
guint minHeight; guint minHeight;
guint maxHeight; guint maxHeight;
GstConditionalUintType *segmentAlignment; GstXMLConditionalUintType *segmentAlignment;
GstConditionalUintType *subsegmentAlignment; GstXMLConditionalUintType *subsegmentAlignment;
GstSAPType subsegmentStartsWithSAP; GstMPDSAPType subsegmentStartsWithSAP;
gboolean bitstreamSwitching; gboolean bitstreamSwitching;
/* list of Accessibility DescriptorType nodes */ /* list of Accessibility DescriptorType nodes */
GList *Accessibility; GList *Accessibility;
@ -502,106 +457,35 @@ struct _GstActiveStream
GstClockTime presentationTimeOffset; /* presentation time offset of the current segment */ GstClockTime presentationTimeOffset; /* presentation time offset of the current segment */
}; };
struct _GstMpdClient
{
GstMPDNode *mpd_node; /* active MPD manifest file */
GList *periods; /* list of GstStreamPeriod */
guint period_idx; /* index of current Period */
GList *active_streams; /* list of GstActiveStream */
guint update_failed_count;
gchar *mpd_uri; /* manifest file URI */
gchar *mpd_base_uri; /* base URI for resolving relative URIs.
* this will be different for redirects */
/* profiles */
gboolean profile_isoff_ondemand;
GstUriDownloader * downloader;
};
/* Basic initialization/deinitialization functions */
GstMpdClient *gst_mpd_client_new (void);
void gst_active_streams_free (GstMpdClient * client);
void gst_mpd_client_free (GstMpdClient * client);
void gst_media_fragment_info_clear (GstMediaFragmentInfo * fragment);
void gst_mpd_client_set_uri_downloader (GstMpdClient * client, GstUriDownloader * download);
/* MPD file parsing */ /* MPD file parsing */
gboolean gst_mpd_parse (GstMpdClient *client, const gchar *data, gint size); gboolean gst_mpdparser_get_mpd_node (GstMPDNode ** mpd_node, const gchar * data, gint size);
GstSegmentListNode * gst_mpdparser_get_external_segment_list (const gchar * data, gint size, GstSegmentListNode * parent);
GList * gst_mpdparser_get_external_periods (const gchar * data, gint size);
GList * gst_mpdparser_get_external_adaptation_sets (const gchar * data, gint size, GstPeriodNode* period);
/* Streaming management */ /* navigation functions */
gboolean gst_mpd_client_setup_media_presentation (GstMpdClient *client, GstClockTime time, gint period_index, const gchar *period_id); GstStreamMimeType gst_mpdparser_representation_get_mimetype (GstAdaptationSetNode * adapt_set, GstRepresentationNode * rep);
gboolean gst_mpd_client_setup_streaming (GstMpdClient * client, GstAdaptationSetNode * adapt_set);
gboolean gst_mpd_client_setup_representation (GstMpdClient *client, GstActiveStream *stream, GstRepresentationNode *representation);
GstClockTime gst_mpd_client_get_next_fragment_duration (GstMpdClient * client, GstActiveStream * stream);
GstClockTime gst_mpd_client_get_media_presentation_duration (GstMpdClient *client);
GstClockTime gst_mpd_client_get_maximum_segment_duration (GstMpdClient * client);
gboolean gst_mpd_client_get_last_fragment_timestamp_end (GstMpdClient * client, guint stream_idx, GstClockTime * ts);
gboolean gst_mpd_client_get_next_fragment_timestamp (GstMpdClient * client, guint stream_idx, GstClockTime * ts);
gboolean gst_mpd_client_get_next_fragment (GstMpdClient *client, guint indexStream, GstMediaFragmentInfo * fragment);
gboolean gst_mpd_client_get_next_header (GstMpdClient *client, gchar **uri, guint stream_idx, gint64 * range_start, gint64 * range_end);
gboolean gst_mpd_client_get_next_header_index (GstMpdClient *client, gchar **uri, guint stream_idx, gint64 * range_start, gint64 * range_end);
gboolean gst_mpd_client_is_live (GstMpdClient * client);
gboolean gst_mpd_client_stream_seek (GstMpdClient * client, GstActiveStream * stream, gboolean forward, GstSeekFlags flags, GstClockTime ts, GstClockTime * final_ts);
gboolean gst_mpd_client_seek_to_time (GstMpdClient * client, GDateTime * time);
GstClockTime gst_mpd_parser_get_stream_presentation_offset (GstMpdClient *client, guint stream_idx);
gchar** gst_mpd_client_get_utc_timing_sources (GstMpdClient *client, guint methods, GstMPDUTCTimingType *selected_method);
GstClockTime gst_mpd_parser_get_period_start_time (GstMpdClient *client);
/* Period selection */ /* Memory management */
guint gst_mpd_client_get_period_index_at_time (GstMpdClient * client, GstDateTime * time); void gst_mpdparser_free_mpd_node (GstMPDNode * mpd_node);
gboolean gst_mpd_client_set_period_index (GstMpdClient *client, guint period_idx); void gst_mpdparser_free_period_node (GstPeriodNode * period_node);
gboolean gst_mpd_client_set_period_id (GstMpdClient *client, const gchar * period_id); void gst_mpdparser_free_adaptation_set_node (GstAdaptationSetNode * adaptation_set_node);
guint gst_mpd_client_get_period_index (GstMpdClient *client); void gst_mpdparser_free_segment_list_node (GstSegmentListNode * segment_list_node);
const gchar *gst_mpd_client_get_period_id (GstMpdClient *client); void gst_mpdparser_free_stream_period (GstStreamPeriod * stream_period);
gboolean gst_mpd_client_has_next_period (GstMpdClient *client); void gst_mpdparser_free_media_segment (GstMediaSegment * media_segment);
gboolean gst_mpd_client_has_previous_period (GstMpdClient * client); void gst_mpdparser_free_active_stream (GstActiveStream * active_stream);
void gst_mpdparser_free_base_url_node (GstBaseURL * base_url_node);
/* Representation selection */ /* Active stream methods*/
gint gst_mpdparser_get_rep_idx_with_max_bandwidth (GList *Representations, gint64 max_bandwidth, gint max_video_width, gint max_video_height, gint max_video_framerate_n, gint max_video_framerate_d); void gst_mpdparser_init_active_stream_segments (GstActiveStream * stream);
gint gst_mpdparser_get_rep_idx_with_min_bandwidth (GList * Representations); gchar *gst_mpdparser_get_mediaURL (GstActiveStream * stream, GstSegmentURLNode * segmentURL);
const gchar *gst_mpdparser_get_initializationURL (GstActiveStream * stream, GstURLType * InitializationURL);
/* URL management */
const gchar *gst_mpdparser_get_baseURL (GstMpdClient *client, guint indexStream);
/* Active stream */
guint gst_mpdparser_get_nb_active_stream (GstMpdClient *client);
GstActiveStream *gst_mpdparser_get_active_stream_by_index (GstMpdClient *client, guint stream_idx);
gboolean gst_mpd_client_active_stream_contains_subtitles (GstActiveStream * stream);
/* AdaptationSet */
guint gst_mpdparser_get_nb_adaptationSet (GstMpdClient *client);
GList * gst_mpd_client_get_adaptation_sets (GstMpdClient * client);
/* Segment */
gboolean gst_mpd_client_has_next_segment (GstMpdClient * client, GstActiveStream * stream, gboolean forward);
GstFlowReturn gst_mpd_client_advance_segment (GstMpdClient * client, GstActiveStream * stream, gboolean forward);
void gst_mpd_client_seek_to_first_segment (GstMpdClient * client);
GstDateTime *gst_mpd_client_get_next_segment_availability_start_time (GstMpdClient * client, GstActiveStream * stream);
/* Get audio/video stream parameters (caps, width, height, rate, number of channels) */
GstCaps * gst_mpd_client_get_stream_caps (GstActiveStream * stream);
gboolean gst_mpd_client_get_bitstream_switching_flag (GstActiveStream * stream);
guint gst_mpd_client_get_video_stream_width (GstActiveStream * stream);
guint gst_mpd_client_get_video_stream_height (GstActiveStream * stream);
gboolean gst_mpd_client_get_video_stream_framerate (GstActiveStream * stream, gint * fps_num, gint * fps_den);
guint gst_mpd_client_get_audio_stream_rate (GstActiveStream * stream);
guint gst_mpd_client_get_audio_stream_num_channels (GstActiveStream * stream);
/* Support multi language */
guint gst_mpdparser_get_list_and_nb_of_audio_language (GstMpdClient *client, GList **lang);
gint64 gst_mpd_client_calculate_time_difference (const GstDateTime * t1, const GstDateTime * t2);
GstDateTime *gst_mpd_client_add_time_difference (GstDateTime * t1, gint64 usecs);
gint64 gst_mpd_client_parse_default_presentation_delay(GstMpdClient * client, const gchar * default_presentation_delay);
/* profiles */
gboolean gst_mpd_client_has_isoff_ondemand_profile (GstMpdClient *client);
/*Helper methods */
gchar *gst_mpdparser_build_URL_from_template (const gchar * url_template, const gchar * id, guint number, guint bandwidth, guint64 time);
const gchar *gst_mpdparser_mimetype_to_caps (const gchar * mimeType);
GstUri *combine_urls (GstUri * base, GList * list, gchar ** query, guint idx);
int strncmp_ext (const char *s1, const char *s2);
G_END_DECLS G_END_DECLS
#endif /* __GST_MPDPARSER_H__ */ #endif /* __GST_MPDPARSER_H__ */

1024
ext/dash/gstxmlhelper.c Normal file

File diff suppressed because it is too large Load diff

113
ext/dash/gstxmlhelper.h Normal file
View file

@ -0,0 +1,113 @@
/* GStreamer
*
* Copyright (C) 2019 Collabora Ltd.
* Author: Stéphane Cerveau <scerveau@collabora.com>
*
* 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.1 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 (COPYING); if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_XMLHELPER_H__
#define __GST_XMLHELPER_H__
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <gst/gst.h>
G_BEGIN_DECLS
typedef struct _GstXMLRange GstXMLRange;
typedef struct _GstXMLRatio GstXMLRatio;
typedef struct _GstXMLFrameRate GstXMLFrameRate;
typedef struct _GstXMLConditionalUintType GstXMLConditionalUintType;
struct _GstXMLRange
{
guint64 first_byte_pos;
guint64 last_byte_pos;
};
struct _GstXMLRatio
{
guint num;
guint den;
};
struct _GstXMLFrameRate
{
guint num;
guint den;
};
struct _GstXMLConditionalUintType
{
gboolean flag;
guint value;
};
GstXMLRange *gst_xml_helper_clone_range (GstXMLRange * range);
/* XML property get method */
gboolean gst_xml_helper_get_prop_validated_string (xmlNode * a_node,
const gchar * property_name, gchar ** property_value,
gboolean (*validator) (const char *));
gboolean gst_xml_helper_get_prop_string (xmlNode * a_node,
const gchar * property_name, gchar ** property_value);
gboolean gst_xml_helper_get_prop_string_stripped (xmlNode * a_node,
const gchar * property_name, gchar ** property_value);
gboolean gst_xml_helper_get_ns_prop_string (xmlNode * a_node,
const gchar * ns_name, const gchar * property_name,
gchar ** property_value);
gboolean gst_xml_helper_get_prop_string_vector_type (xmlNode * a_node,
const gchar * property_name, gchar *** property_value);
gboolean gst_xml_helper_get_prop_signed_integer (xmlNode * a_node,
const gchar * property_name, gint default_val, gint * property_value);
gboolean gst_xml_helper_get_prop_unsigned_integer (xmlNode * a_node,
const gchar * property_name, guint default_val, guint * property_value);
gboolean gst_xml_helper_get_prop_unsigned_integer_64 (xmlNode *
a_node, const gchar * property_name, guint64 default_val,
guint64 * property_value);
gboolean gst_xml_helper_get_prop_uint_vector_type (xmlNode * a_node,
const gchar * property_name, guint ** property_value, guint * value_size);
gboolean gst_xml_helper_get_prop_double (xmlNode * a_node,
const gchar * property_name, gdouble * property_value);
gboolean gst_xml_helper_get_prop_boolean (xmlNode * a_node,
const gchar * property_name, gboolean default_val,
gboolean * property_value);
gboolean gst_xml_helper_get_prop_range (xmlNode * a_node,
const gchar * property_name, GstXMLRange ** property_value);
gboolean gst_xml_helper_get_prop_ratio (xmlNode * a_node,
const gchar * property_name, GstXMLRatio ** property_value);
gboolean gst_xml_helper_get_prop_framerate (xmlNode * a_node,
const gchar * property_name, GstXMLFrameRate ** property_value);
gboolean gst_xml_helper_get_prop_cond_uint (xmlNode * a_node,
const gchar * property_name, GstXMLConditionalUintType ** property_value);
gboolean gst_xml_helper_get_prop_dateTime (xmlNode * a_node,
const gchar * property_name, GstDateTime ** property_value);
gboolean gst_xml_helper_get_prop_duration (xmlNode * a_node,
const gchar * property_name, guint64 default_value,
guint64 * property_value);
gboolean gst_xml_helper_get_prop_string_no_whitespace (xmlNode * a_node,
const gchar * property_name, gchar ** property_value);
/* XML node get method */
gboolean gst_xml_helper_get_node_content (xmlNode * a_node,
gchar ** content);
gchar *gst_xml_helper_get_node_namespace (xmlNode * a_node,
const gchar * prefix);
gboolean gst_xml_helper_get_node_as_string (xmlNode * a_node,
gchar ** content);
G_END_DECLS
#endif /* __GST_XMLHELPER_H__ */

View file

@ -1,6 +1,9 @@
dash_sources = [ dash_sources = [
'gstdashdemux.c', 'gstdashdemux.c',
'gstxmlhelper.c',
'gstmpdhelper.c',
'gstmpdparser.c', 'gstmpdparser.c',
'gstmpdclient.c',
'gstplugin.c', 'gstplugin.c',
] ]

File diff suppressed because it is too large Load diff