From 65127784256622633575bf2fe9c7f13306126e0b Mon Sep 17 00:00:00 2001 From: Karthik raja Date: Tue, 7 Dec 2021 17:29:02 +0530 Subject: [PATCH] Add support to parse cenc tags (#54) * Add support to parse cenc tags * Remove whitespace * Add support to parse other key id's also * Add initialization * Add test case and refactor code * Move test case to xmltompd * Add whitespace * Fix typo * Fix formatting --- mpegdash/nodes.py | 49 +++++++++++++++++-- mpegdash/utils.py | 2 +- tests/mpd-samples/with_content_protection.mpd | 19 +++++++ tests/test_xmltompd.py | 6 +++ 4 files changed, 70 insertions(+), 6 deletions(-) create mode 100644 tests/mpd-samples/with_content_protection.mpd diff --git a/mpegdash/nodes.py b/mpegdash/nodes.py index 3345b76..b402bb4 100644 --- a/mpegdash/nodes.py +++ b/mpegdash/nodes.py @@ -320,21 +320,57 @@ def __init__(self): self.scheme_id_uri = '' # xs:anyURI (required) self.value = None # xs:string self.id = None # xs:string - self.key_id = None # xs:string def parse(self, xmlnode): self.scheme_id_uri = parse_attr_value(xmlnode, 'schemeIdUri', str) self.value = parse_attr_value(xmlnode, 'value', str) self.id = parse_attr_value(xmlnode, 'id', str) - self.key_id = parse_attr_value(xmlnode, 'ns2:default_KID', str) def write(self, xmlnode): write_attr_value(xmlnode, 'schemeIdUri', self.scheme_id_uri) write_attr_value(xmlnode, 'value', self.value) write_attr_value(xmlnode, 'id', self.id) - write_attr_value(xmlnode, 'ns2:default_KID', self.key_id) +class PSSH(XMLNode): + def __init__(self): + self.pssh = None + + def parse(self, xmlnode): + self.pssh = parse_node_value(xmlnode, str) + + def write(self, xmlnode): + write_node_value(xmlnode, self.pssh) + + +class ContentProtection(XMLNode): + def __init__(self): + self.scheme_id_uri = "" # xs:anyURI (required) + self.value = None # xs:string + self.id = None # xs:string + self.pssh = None # PSSH + self.default_key_id = None # xs:string + self.ns2_key_id = None # xs:string + self.cenc_default_kid = None # xs:string + + def parse(self, xmlnode): + self.scheme_id_uri = parse_attr_value(xmlnode, "schemeIdUri", str) + self.value = parse_attr_value(xmlnode, "value", str) + self.id = parse_attr_value(xmlnode, "id", str) + self.default_key_id = parse_attr_value(xmlnode, "default_KID", str) + self.ns2_key_id = parse_attr_value(xmlnode, "ns2:default_KID", str) + self.cenc_default_kid = parse_attr_value(xmlnode, "cenc:default_KID", str) + self.pssh = parse_child_nodes(xmlnode, "cenc:pssh", PSSH) + + def write(self, xmlnode): + write_attr_value(xmlnode, "schemeIdUri", self.scheme_id_uri) + write_attr_value(xmlnode, "value", self.value) + write_attr_value(xmlnode, "id", self.id) + write_attr_value(xmlnode, "default_KID", self.default_key_id) + write_attr_value(xmlnode, "ns2:default_KID", self.ns2_key_id) + write_attr_value(xmlnode, "cenc:default_KID", self.cenc_default_kid) + write_child_node(xmlnode, "cenc:pssh", self.pssh) + class ContentComponent(XMLNode): def __init__(self): self.id = None # xs:unsigendInt @@ -390,7 +426,7 @@ def __init__(self): self.frame_packings = None # DescriptorType* self.audio_channel_configurations = None # DescriptorType* - self.content_protections = None # DescriptorType* + self.content_protections = None # ContentProtection* self.essential_properties = None # DescriptorType* self.supplemental_properties = None # DescriptorType* self.inband_event_streams = None # DescriptorType* @@ -414,7 +450,7 @@ def parse(self, xmlnode): self.frame_packings = parse_child_nodes(xmlnode, 'FramePacking', Descriptor) self.audio_channel_configurations = parse_child_nodes(xmlnode, 'AudioChannelConfiguration', Descriptor) - self.content_protections = parse_child_nodes(xmlnode, 'ContentProtection', Descriptor) + self.content_protections = parse_child_nodes(xmlnode, 'ContentProtection', ContentProtection) self.essential_properties = parse_child_nodes(xmlnode, 'EssentialProperty', Descriptor) self.supplemental_properties = parse_child_nodes(xmlnode, 'SupplementalProperty', Descriptor) self.inband_event_streams = parse_child_nodes(xmlnode, 'InbandEventStream', Descriptor) @@ -700,6 +736,7 @@ def __init__(self): self.id = None # xs:string self.type = None # PresentationType self.profiles = '' # xs:string (required) + self.cenc = None # xs:string self.availability_start_time = None # xs:dateTime self.availability_end_time = None # xs:dateTime self.publish_time = None # xs:dateTime @@ -723,6 +760,7 @@ def parse(self, xmlnode): self.id = parse_attr_value(xmlnode, 'id', str) self.type = parse_attr_value(xmlnode, 'type', str) self.profiles = parse_attr_value(xmlnode, 'profiles', str) + self.cenc = parse_attr_value(xmlnode, "xmlns:cenc", str) self.availability_start_time = parse_attr_value(xmlnode, 'availabilityStartTime', str) self.availability_end_time = parse_attr_value(xmlnode, 'availabilityEndTime', str) self.publish_time = parse_attr_value(xmlnode, 'publishTime', str) @@ -746,6 +784,7 @@ def write(self, xmlnode): write_attr_value(xmlnode, 'id', self.id) write_attr_value(xmlnode, 'type', self.type) write_attr_value(xmlnode, 'profiles', self.profiles) + write_attr_value(xmlnode, "xmlns:cenc", self.cenc) write_attr_value(xmlnode, 'availabilityStartTime', self.availability_start_time) write_attr_value(xmlnode, 'availabilityEndTime', self.availability_end_time) write_attr_value(xmlnode, 'publishTime', self.publish_time) diff --git a/mpegdash/utils.py b/mpegdash/utils.py index 36e8887..4d7b828 100644 --- a/mpegdash/utils.py +++ b/mpegdash/utils.py @@ -7,7 +7,7 @@ def _find_child_nodes_by_name(parent, name): nodes = [] for node in parent.childNodes: - if node.nodeType == node.ELEMENT_NODE and node.localName == name: + if node.nodeType == node.ELEMENT_NODE and (node.localName == name or node.nodeName == name): nodes.append(node) return nodes diff --git a/tests/mpd-samples/with_content_protection.mpd b/tests/mpd-samples/with_content_protection.mpd new file mode 100644 index 0000000..c486431 --- /dev/null +++ b/tests/mpd-samples/with_content_protection.mpd @@ -0,0 +1,19 @@ + + + + + + + + AAAAWnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAADoiMjc2NjQ2ZjYzNjk3MDY4NjU3MjBlNWZhZjdmODhiOTQ1ZWJhYmYzOWM2MTc4ZmFkNTc2SOPclZsG + + + + + + + + + + + diff --git a/tests/test_xmltompd.py b/tests/test_xmltompd.py index 4359aaf..aed66ee 100644 --- a/tests/test_xmltompd.py +++ b/tests/test_xmltompd.py @@ -74,6 +74,12 @@ def test_xml2mpd_parse_vector_type_attributes(self): self.assertEqual(sub_rep.content_component[0], '102') self.assertEqual(sub_rep.content_component[1], '104') + def test_xml2mpd_from_file_with_content_protection(self): + mpd = MPEGDASHParser.parse('./tests/mpd-samples/with_content_protection.mpd') + self.assertEqual("6c28b624-5854-5b8c-8033-9d61ac0c039c", mpd.periods[0].adaptation_sets[0].content_protections[0].cenc_default_kid) + self.assertEqual("urn:mpeg:dash:mp4protection:2011", mpd.periods[0].adaptation_sets[0].content_protections[0].scheme_id_uri) + self.assertTrue(mpd.periods[0].adaptation_sets[0].content_protections[1].pssh[0].pssh is not None) + def assert_mpd(self, mpd): self.assertTrue(mpd is not None) self.assertTrue(len(mpd.periods) > 0)