mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-25 16:48:11 +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;
|
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
|
static gboolean
|
||||||
gst_mss_demux_setup_streams (GstAdaptiveDemux * demux)
|
gst_mss_demux_setup_streams (GstAdaptiveDemux * demux)
|
||||||
{
|
{
|
||||||
GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (demux);
|
GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (demux);
|
||||||
GSList *streams = gst_mss_manifest_get_streams (mssdemux->manifest);
|
GSList *streams = gst_mss_manifest_get_streams (mssdemux->manifest);
|
||||||
GSList *iter;
|
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) {
|
if (streams == NULL) {
|
||||||
GST_INFO_OBJECT (mssdemux, "No streams found in the manifest");
|
GST_INFO_OBJECT (mssdemux, "No streams found in the manifest");
|
||||||
|
@ -382,6 +404,17 @@ gst_mss_demux_setup_streams (GstAdaptiveDemux * demux)
|
||||||
return FALSE;
|
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",
|
GST_INFO_OBJECT (mssdemux, "Changing max bitrate to %u",
|
||||||
demux->connection_speed);
|
demux->connection_speed);
|
||||||
gst_mss_manifest_change_bitrate (mssdemux->manifest, 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);
|
srcpad);
|
||||||
stream->manifest_stream = manifeststream;
|
stream->manifest_stream = manifeststream;
|
||||||
gst_mss_stream_set_active (manifeststream, TRUE);
|
gst_mss_stream_set_active (manifeststream, TRUE);
|
||||||
|
|
||||||
caps = gst_mss_stream_get_caps (stream->manifest_stream);
|
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),
|
gst_adaptive_demux_stream_set_caps (GST_ADAPTIVE_DEMUX_STREAM_CAST (stream),
|
||||||
create_mss_caps (stream, caps));
|
create_mss_caps (stream, caps));
|
||||||
gst_caps_unref (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
|
gst_adaptive_demux_stream_set_tags (GST_ADAPTIVE_DEMUX_STREAM_CAST
|
||||||
(stream), tags);
|
(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;
|
return TRUE;
|
||||||
|
@ -476,10 +531,31 @@ gst_mss_demux_stream_select_bitrate (GstAdaptiveDemuxStream * stream,
|
||||||
if (gst_mss_stream_select_bitrate (mssstream->manifest_stream, bitrate)) {
|
if (gst_mss_stream_select_bitrate (mssstream->manifest_stream, bitrate)) {
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
GstCaps *msscaps;
|
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);
|
caps = gst_mss_stream_get_caps (mssstream->manifest_stream);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (stream->pad,
|
GST_DEBUG_OBJECT (stream->pad,
|
||||||
"Starting streams reconfiguration due to bitrate changes");
|
"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);
|
msscaps = create_mss_caps (mssstream, caps);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (stream->pad,
|
GST_DEBUG_OBJECT (stream->pad,
|
||||||
|
|
|
@ -27,6 +27,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 <gst/gstprotection.h>
|
||||||
#include "gstmssmanifest.h"
|
#include "gstmssmanifest.h"
|
||||||
#include <gst/uridownloader/gsturidownloader.h>
|
#include <gst/uridownloader/gsturidownloader.h>
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,9 @@ struct _GstMssManifest
|
||||||
|
|
||||||
gboolean is_live;
|
gboolean is_live;
|
||||||
|
|
||||||
|
GString *protection_system_id;
|
||||||
|
gchar *protection_data;
|
||||||
|
|
||||||
GSList *streams;
|
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);
|
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 *
|
GstMssManifest *
|
||||||
gst_mss_manifest_new (GstBuffer * data)
|
gst_mss_manifest_new (GstBuffer * data)
|
||||||
{
|
{
|
||||||
|
@ -300,6 +338,11 @@ gst_mss_manifest_new (GstBuffer * data)
|
||||||
manifest->streams = g_slist_append (manifest->streams, stream);
|
manifest->streams = g_slist_append (manifest->streams, stream);
|
||||||
_gst_mss_stream_init (stream, nodeiter);
|
_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);
|
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);
|
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);
|
xmlFreeDoc (manifest->xml);
|
||||||
g_free (manifest);
|
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 *
|
GSList *
|
||||||
gst_mss_manifest_get_streams (GstMssManifest * manifest)
|
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);
|
gint gst_mss_manifest_get_look_ahead_fragments_count (GstMssManifest * manifest);
|
||||||
void gst_mss_manifest_reload_fragments (GstMssManifest * manifest, GstBuffer * data);
|
void gst_mss_manifest_reload_fragments (GstMssManifest * manifest, GstBuffer * data);
|
||||||
GstClockTime gst_mss_manifest_get_min_fragment_duration (GstMssManifest * manifest);
|
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);
|
GstMssStreamType gst_mss_stream_get_type (GstMssStream *stream);
|
||||||
GstCaps * gst_mss_stream_get_caps (GstMssStream * stream);
|
GstCaps * gst_mss_stream_get_caps (GstMssStream * stream);
|
||||||
|
|
Loading…
Reference in a new issue