diff --git a/ext/dash/gstdashdemux.c b/ext/dash/gstdashdemux.c index 9b91e06e22..17df50fedb 100644 --- a/ext/dash/gstdashdemux.c +++ b/ext/dash/gstdashdemux.c @@ -241,6 +241,9 @@ static GstPad *gst_dash_demux_create_pad (GstDashDemux * demux, #define SIDX_ENTRY(s,i) (&(SIDX(s)->entries[(i)])) #define SIDX_CURRENT_ENTRY(s) SIDX_ENTRY(s, SIDX(s)->entry_index) +static void gst_dash_demux_send_content_protection_event (gpointer cp_data, + gpointer stream); + #define gst_dash_demux_parent_class parent_class G_DEFINE_TYPE_WITH_CODE (GstDashDemux, gst_dash_demux, GST_TYPE_ADAPTIVE_DEMUX, GST_DEBUG_CATEGORY_INIT (gst_dash_demux_debug, "dashdemux", 0, @@ -525,12 +528,52 @@ gst_dash_demux_setup_all_streams (GstDashDemux * demux) (stream), tags); stream->index = i; stream->pending_seek_ts = GST_CLOCK_TIME_NONE; + if (active_stream->cur_adapt_set && + active_stream->cur_adapt_set->RepresentationBase && + active_stream->cur_adapt_set->RepresentationBase->ContentProtection) { + GST_DEBUG_OBJECT (demux, "Adding ContentProtection events to source pad"); + g_list_foreach (active_stream->cur_adapt_set-> + RepresentationBase->ContentProtection, + gst_dash_demux_send_content_protection_event, stream); + } + gst_isoff_sidx_parser_init (&stream->sidx_parser); } return TRUE; } +static void +gst_dash_demux_send_content_protection_event (gpointer data, gpointer userdata) +{ + GstDescriptorType *cp = (GstDescriptorType *) data; + GstDashDemuxStream *stream = (GstDashDemuxStream *) userdata; + GstEvent *event; + GstBuffer *pssi; + glong pssi_len; + gchar *schemeIdUri; + + if (cp->schemeIdUri == NULL) + return; + + GST_TRACE_OBJECT (stream, "check schemeIdUri %s", cp->schemeIdUri); + /* RFC 2141 states: The leading "urn:" sequence is case-insensitive */ + schemeIdUri = g_ascii_strdown (cp->schemeIdUri, -1); + if (g_str_has_prefix (schemeIdUri, "urn:uuid:")) { + pssi_len = strlen (cp->value); + pssi = gst_buffer_new_wrapped (g_memdup (cp->value, pssi_len), pssi_len); + GST_LOG_OBJECT (stream, "Queuing Protection event on source pad"); + /* RFC 4122 states that the hex part of a UUID is in lower case, + * but some streams seem to ignore this and use upper case for the + * protection system ID */ + event = gst_event_new_protection (cp->schemeIdUri + 9, pssi, "dash/mpd"); + gst_adaptive_demux_stream_queue_event ((GstAdaptiveDemuxStream *) stream, + event); + gst_buffer_unref (pssi); + } + g_free (schemeIdUri); +} + static GstClockTime gst_dash_demux_get_duration (GstAdaptiveDemux * ademux) { diff --git a/ext/dash/gstmpdparser.c b/ext/dash/gstmpdparser.c index b809c36830..b967ca87bd 100644 --- a/ext/dash/gstmpdparser.c +++ b/ext/dash/gstmpdparser.c @@ -69,6 +69,8 @@ static gboolean gst_mpdparser_get_xml_node_content (xmlNode * a_node, gchar ** content); static gchar *gst_mpdparser_get_xml_node_namespace (xmlNode * a_node, const gchar * prefix); +static gboolean gst_mpdparser_get_xml_node_as_string (xmlNode * a_node, + gchar ** content); /* XML node parsing */ static void gst_mpdparser_parse_baseURL_node (GList ** list, xmlNode * a_node); @@ -934,6 +936,24 @@ gst_mpdparser_get_xml_node_content (xmlNode * a_node, gchar ** content) return exists; } +static gboolean +gst_mpdparser_get_xml_node_as_string (xmlNode * a_node, gchar ** content) +{ + gboolean exists = FALSE; + xmlBufferPtr buffer = xmlBufferCreate (); + int size; + + size = xmlNodeDump (buffer, a_node->doc, a_node, 0, /* indent */ + 0 /* format */ ); + if (size > 0) { + *content = (gchar *) xmlBufferDetach (buffer); + exists = TRUE; + GST_LOG (" - %s: %s", a_node->name, *content); + } + xmlBufferFree (buffer); + return exists; +} + static gchar * gst_mpdparser_get_xml_node_namespace (xmlNode * a_node, const gchar * prefix) { @@ -992,7 +1012,11 @@ gst_mpdparser_parse_descriptor_type_node (GList ** list, xmlNode * a_node) GST_LOG ("attributes of %s node:", a_node->name); gst_mpdparser_get_xml_prop_string (a_node, "schemeIdUri", &new_descriptor->schemeIdUri); - gst_mpdparser_get_xml_prop_string (a_node, "value", &new_descriptor->value); + if (!gst_mpdparser_get_xml_prop_string (a_node, "value", + &new_descriptor->value)) { + /* if no value attribute, use XML string representation of the node */ + gst_mpdparser_get_xml_node_as_string (a_node, &new_descriptor->value); + } } static void diff --git a/gst-libs/gst/adaptivedemux/gstadaptivedemux.c b/gst-libs/gst/adaptivedemux/gstadaptivedemux.c index 7df1c63596..483d232067 100644 --- a/gst-libs/gst/adaptivedemux/gstadaptivedemux.c +++ b/gst-libs/gst/adaptivedemux/gstadaptivedemux.c @@ -657,6 +657,17 @@ gst_adaptive_demux_set_stream_struct_size (GstAdaptiveDemux * demux, demux->stream_struct_size = struct_size; } +static void +gst_adaptive_demux_send_event (gpointer data, gpointer userdata) +{ + GstEvent *event = (GstEvent *) data; + GstPad *pad = (GstPad *) userdata; + + if (!gst_pad_push_event (pad, event)) { + GST_ERROR_OBJECT (pad, "Failed to send pending event"); + } +} + static gboolean gst_adaptive_demux_expose_stream (GstAdaptiveDemux * demux, GstAdaptiveDemuxStream * stream) @@ -877,6 +888,11 @@ gst_adaptive_demux_stream_free (GstAdaptiveDemuxStream * stream) stream->pending_segment = NULL; } + if (stream->pending_events) { + g_list_free_full (stream->pending_events, (GDestroyNotify) gst_event_unref); + stream->pending_events = NULL; + } + if (stream->src_srcpad) { gst_object_unref (stream->src_srcpad); stream->src_srcpad = NULL; @@ -1296,6 +1312,13 @@ gst_adaptive_demux_stream_set_tags (GstAdaptiveDemuxStream * stream, stream->pending_tags = tags; } +void +gst_adaptive_demux_stream_queue_event (GstAdaptiveDemuxStream * stream, + GstEvent * event) +{ + stream->pending_events = g_list_append (stream->pending_events, event); +} + static guint64 _update_average_bitrate (GstAdaptiveDemux * demux, GstAdaptiveDemuxStream * stream, guint64 new_bitrate) @@ -1447,6 +1470,13 @@ gst_adaptive_demux_stream_push_buffer (GstAdaptiveDemuxStream * stream, gst_pad_push_event (stream->pad, gst_event_new_tag (stream->pending_tags)); stream->pending_tags = NULL; } + if (G_UNLIKELY (stream->pending_events)) { + g_list_foreach (stream->pending_events, gst_adaptive_demux_send_event, + stream->pad); + g_list_free (stream->pending_events); + stream->pending_events = NULL; + } + ret = gst_pad_push (stream->pad, buffer); GST_LOG_OBJECT (stream->pad, "Push result: %d %s", ret, diff --git a/gst-libs/gst/adaptivedemux/gstadaptivedemux.h b/gst-libs/gst/adaptivedemux/gstadaptivedemux.h index 9303a84348..dc8fabe588 100644 --- a/gst-libs/gst/adaptivedemux/gstadaptivedemux.h +++ b/gst-libs/gst/adaptivedemux/gstadaptivedemux.h @@ -118,6 +118,7 @@ struct _GstAdaptiveDemuxStream GstEvent *pending_segment; GstTagList *pending_tags; gboolean need_header; + GList *pending_events; GstFlowReturn last_ret; GError *last_error; @@ -427,6 +428,9 @@ GstFlowReturn gst_adaptive_demux_stream_push_buffer (GstAdaptiveDemuxStream * st GstFlowReturn gst_adaptive_demux_stream_advance_fragment (GstAdaptiveDemux * demux, GstAdaptiveDemuxStream * stream, GstClockTime duration); +void gst_adaptive_demux_stream_queue_event (GstAdaptiveDemuxStream * stream, + GstEvent * event); + GstFlowReturn gst_adaptive_demux_stream_advance_fragment_unlocked (GstAdaptiveDemux * demux, GstAdaptiveDemuxStream * stream, GstClockTime duration);