mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 09:55:36 +00:00
mssdemux: PlayReady WRM parsing support
If the manifest has a ProtectionHeader node then parse it and emit protection events according to the specified protection SystemID. https://bugzilla.gnome.org/show_bug.cgi?id=753613
This commit is contained in:
parent
5d4388bf9e
commit
ae7d938842
4 changed files with 140 additions and 0 deletions
|
@ -367,12 +367,34 @@ _create_pad (GstMssDemux * mssdemux, GstMssStream * manifeststream)
|
|||
return srcpad;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mss_demux_apply_protection_system (GstCaps * caps,
|
||||
const gchar * selected_system)
|
||||
{
|
||||
GstStructure *s;
|
||||
|
||||
g_return_if_fail (selected_system);
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
gst_structure_set (s,
|
||||
"original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
|
||||
GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
|
||||
NULL);
|
||||
gst_structure_set_name (s, "application/x-cenc");
|
||||
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_mss_demux_setup_streams (GstAdaptiveDemux * demux)
|
||||
{
|
||||
GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (demux);
|
||||
GSList *streams = gst_mss_manifest_get_streams (mssdemux->manifest);
|
||||
GSList *iter;
|
||||
const gchar *protection_system_id =
|
||||
gst_mss_manifest_get_protection_system_id (mssdemux->manifest);
|
||||
const gchar *protection_data =
|
||||
gst_mss_manifest_get_protection_data (mssdemux->manifest);
|
||||
gboolean protected = protection_system_id && protection_data;
|
||||
const gchar *selected_system = NULL;
|
||||
|
||||
if (streams == NULL) {
|
||||
GST_INFO_OBJECT (mssdemux, "No streams found in the manifest");
|
||||
|
@ -382,6 +404,17 @@ gst_mss_demux_setup_streams (GstAdaptiveDemux * demux)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if (protected) {
|
||||
const gchar *sys_ids[2] = { protection_system_id, NULL };
|
||||
|
||||
selected_system = gst_protection_select_system (sys_ids);
|
||||
if (!selected_system) {
|
||||
GST_ERROR_OBJECT (mssdemux, "stream is protected, but no "
|
||||
"suitable decryptor element has been found");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
GST_INFO_OBJECT (mssdemux, "Changing max bitrate to %u",
|
||||
demux->connection_speed);
|
||||
gst_mss_manifest_change_bitrate (mssdemux->manifest, demux->connection_speed);
|
||||
|
@ -404,7 +437,13 @@ gst_mss_demux_setup_streams (GstAdaptiveDemux * demux)
|
|||
srcpad);
|
||||
stream->manifest_stream = manifeststream;
|
||||
gst_mss_stream_set_active (manifeststream, TRUE);
|
||||
|
||||
caps = gst_mss_stream_get_caps (stream->manifest_stream);
|
||||
|
||||
if (protected) {
|
||||
gst_mss_demux_apply_protection_system (caps, selected_system);
|
||||
}
|
||||
|
||||
gst_adaptive_demux_stream_set_caps (GST_ADAPTIVE_DEMUX_STREAM_CAST (stream),
|
||||
create_mss_caps (stream, caps));
|
||||
gst_caps_unref (caps);
|
||||
|
@ -417,6 +456,22 @@ gst_mss_demux_setup_streams (GstAdaptiveDemux * demux)
|
|||
gst_adaptive_demux_stream_set_tags (GST_ADAPTIVE_DEMUX_STREAM_CAST
|
||||
(stream), tags);
|
||||
}
|
||||
|
||||
if (protected) {
|
||||
gsize protection_data_len;
|
||||
guchar *decoded_data =
|
||||
g_base64_decode (protection_data, &protection_data_len);
|
||||
GstBuffer *protection_buffer =
|
||||
gst_buffer_new_wrapped (decoded_data, protection_data_len);
|
||||
GstEvent *event =
|
||||
gst_event_new_protection (protection_system_id, protection_buffer,
|
||||
"smooth-streaming");
|
||||
|
||||
GST_LOG_OBJECT (stream, "Queuing Protection event on source pad");
|
||||
gst_adaptive_demux_stream_queue_event ((GstAdaptiveDemuxStream *) stream,
|
||||
event);
|
||||
gst_buffer_unref (protection_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
@ -476,10 +531,31 @@ gst_mss_demux_stream_select_bitrate (GstAdaptiveDemuxStream * stream,
|
|||
if (gst_mss_stream_select_bitrate (mssstream->manifest_stream, bitrate)) {
|
||||
GstCaps *caps;
|
||||
GstCaps *msscaps;
|
||||
GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (stream->demux);
|
||||
const gchar *protection_system_id =
|
||||
gst_mss_manifest_get_protection_system_id (mssdemux->manifest);
|
||||
const gchar *protection_data =
|
||||
gst_mss_manifest_get_protection_data (mssdemux->manifest);
|
||||
gboolean protected = protection_system_id && protection_data;
|
||||
|
||||
caps = gst_mss_stream_get_caps (mssstream->manifest_stream);
|
||||
|
||||
GST_DEBUG_OBJECT (stream->pad,
|
||||
"Starting streams reconfiguration due to bitrate changes");
|
||||
|
||||
if (protected) {
|
||||
const gchar *sys_ids[2] = { protection_system_id, NULL };
|
||||
const gchar *selected_system = gst_protection_select_system (sys_ids);
|
||||
|
||||
if (!selected_system) {
|
||||
GST_ERROR_OBJECT (mssdemux, "stream is protected, but no "
|
||||
"suitable decryptor element has been found");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gst_mss_demux_apply_protection_system (caps, selected_system);
|
||||
}
|
||||
|
||||
msscaps = create_mss_caps (mssstream, caps);
|
||||
|
||||
GST_DEBUG_OBJECT (stream->pad,
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <gst/adaptivedemux/gstadaptivedemux.h>
|
||||
#include <gst/base/gstadapter.h>
|
||||
#include <gst/base/gstdataqueue.h>
|
||||
#include <gst/gstprotection.h>
|
||||
#include "gstmssmanifest.h"
|
||||
#include <gst/uridownloader/gsturidownloader.h>
|
||||
|
||||
|
|
|
@ -95,6 +95,9 @@ struct _GstMssManifest
|
|||
|
||||
gboolean is_live;
|
||||
|
||||
GString *protection_system_id;
|
||||
gchar *protection_data;
|
||||
|
||||
GSList *streams;
|
||||
};
|
||||
|
||||
|
@ -267,6 +270,41 @@ _gst_mss_stream_init (GstMssStream * stream, xmlNodePtr node)
|
|||
stream->regex_position = g_regex_new ("\\{start[ _]time\\}", 0, 0, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_gst_mss_parse_protection (GstMssManifest * manifest,
|
||||
xmlNodePtr protection_node)
|
||||
{
|
||||
xmlNodePtr nodeiter;
|
||||
|
||||
for (nodeiter = protection_node->children; nodeiter;
|
||||
nodeiter = nodeiter->next) {
|
||||
if (nodeiter->type == XML_ELEMENT_NODE
|
||||
&& (strcmp ((const char *) nodeiter->name, "ProtectionHeader") == 0)) {
|
||||
xmlChar *system_id_attribute =
|
||||
xmlGetProp (nodeiter, (xmlChar *) "SystemID");
|
||||
gchar *value = (gchar *) system_id_attribute;
|
||||
int id_len = strlen (value);
|
||||
GString *system_id;
|
||||
|
||||
if (value[0] == '{') {
|
||||
value++;
|
||||
id_len--;
|
||||
}
|
||||
|
||||
system_id = g_string_new (value);
|
||||
system_id = g_string_ascii_down (system_id);
|
||||
if (value[id_len - 1] == '}')
|
||||
system_id = g_string_truncate (system_id, id_len - 1);
|
||||
|
||||
manifest->protection_system_id = system_id;
|
||||
manifest->protection_data = (gchar *) xmlNodeGetContent (nodeiter);
|
||||
xmlFree (system_id_attribute);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GstMssManifest *
|
||||
gst_mss_manifest_new (GstBuffer * data)
|
||||
{
|
||||
|
@ -300,6 +338,11 @@ gst_mss_manifest_new (GstBuffer * data)
|
|||
manifest->streams = g_slist_append (manifest->streams, stream);
|
||||
_gst_mss_stream_init (stream, nodeiter);
|
||||
}
|
||||
|
||||
if (nodeiter->type == XML_ELEMENT_NODE
|
||||
&& (strcmp ((const char *) nodeiter->name, "Protection") == 0)) {
|
||||
_gst_mss_parse_protection (manifest, nodeiter);
|
||||
}
|
||||
}
|
||||
|
||||
gst_buffer_unmap (data, &mapinfo);
|
||||
|
@ -327,10 +370,28 @@ gst_mss_manifest_free (GstMssManifest * manifest)
|
|||
|
||||
g_slist_free_full (manifest->streams, (GDestroyNotify) gst_mss_stream_free);
|
||||
|
||||
if (manifest->protection_system_id != NULL)
|
||||
g_string_free (manifest->protection_system_id, TRUE);
|
||||
xmlFree (manifest->protection_data);
|
||||
|
||||
xmlFreeDoc (manifest->xml);
|
||||
g_free (manifest);
|
||||
}
|
||||
|
||||
const gchar *
|
||||
gst_mss_manifest_get_protection_system_id (GstMssManifest * manifest)
|
||||
{
|
||||
if (manifest->protection_system_id != NULL)
|
||||
return manifest->protection_system_id->str;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
gst_mss_manifest_get_protection_data (GstMssManifest * manifest)
|
||||
{
|
||||
return manifest->protection_data;
|
||||
}
|
||||
|
||||
GSList *
|
||||
gst_mss_manifest_get_streams (GstMssManifest * manifest)
|
||||
{
|
||||
|
|
|
@ -52,6 +52,8 @@ gint64 gst_mss_manifest_get_dvr_window_length (GstMssManifest * manifest);
|
|||
gint gst_mss_manifest_get_look_ahead_fragments_count (GstMssManifest * manifest);
|
||||
void gst_mss_manifest_reload_fragments (GstMssManifest * manifest, GstBuffer * data);
|
||||
GstClockTime gst_mss_manifest_get_min_fragment_duration (GstMssManifest * manifest);
|
||||
const gchar * gst_mss_manifest_get_protection_system_id (GstMssManifest * manifest);
|
||||
const gchar * gst_mss_manifest_get_protection_data (GstMssManifest * manifest);
|
||||
|
||||
GstMssStreamType gst_mss_stream_get_type (GstMssStream *stream);
|
||||
GstCaps * gst_mss_stream_get_caps (GstMssStream * stream);
|
||||
|
|
Loading…
Reference in a new issue