3 # playready_experiment.py - Example of SmoothStreaming PlayReady authentication
5 # Copyright (C) 2016 Antonio Ospite <ao2@ao2.it>
7 # This program is free software: you can redistribute it and/or modify it under
8 # the terms of the GNU General Public License as published by the Free Software
9 # Foundation, either version 3 of the License, or (at your option) any later
12 # This program is distributed in the hope that it will be useful, but WITHOUT
13 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 # You should have received a copy of the GNU General Public License along with
18 # this program. If not, see <http://www.gnu.org/licenses/>.
21 # Experiment on how to use the ProtectionHeader element in SmoothSTreaming
24 # The code is just a demonstration of how to decode the ProtectionHeader element
25 # content, it is not supposed to do nothing actually useful.
27 # Based on the PlayReady Header Object specification:
28 # http://download.microsoft.com/download/1/4/7/1475C862-6B67-44B2-AF31-ABC83EA68292/PlayReady%20Header%20Object%20(7-2-2012).docx
33 import xml.etree.ElementTree as etree
35 from pysimplesoap.client import SoapClient
36 from pysimplesoap.simplexml import SimpleXMLElement
39 def get_right_management_header(protection_header_text):
40 play_ready_header_objects = base64.b64decode(protection_header_text)
45 total_size = struct.unpack("<L", play_ready_header_objects[offset:offset + field_size])[0]
48 if total_size != len(play_ready_header_objects):
49 sys.stderr.write("Error, unexpected size.\n")
53 count = struct.unpack("<H", play_ready_header_objects[offset:offset + field_size])[0]
56 for i in range(count):
58 record_type = struct.unpack("<H", play_ready_header_objects[offset:offset + field_size])[0]
62 record_length = struct.unpack("<H", play_ready_header_objects[offset:offset + field_size])[0]
66 right_management_header = play_ready_header_objects[offset:offset + record_length].decode("UTF-16")
67 return right_management_header
69 sys.stderr.write("Error, unsupported record type. Skipping.\n")
70 offset += record_length
74 if len(sys.argv) != 2:
75 sys.stderr.write("usage: %s <manifest>\n" % sys.argv[0])
78 manifest_filename = sys.argv[1]
80 manifest = etree.parse(manifest_filename)
81 protection_header = manifest.find(".//Protection/ProtectionHeader")
83 challenge = get_right_management_header(protection_header.text)
85 challenge_xml = etree.fromstring(challenge)
86 la_url = challenge_xml.find(".//{http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader}LA_URL").text
90 action='http://schemas.microsoft.com/DRM/2007/03/protocols/',
91 soap_ns='soap', trace=True, ns=False)
93 params = SimpleXMLElement("""<AcquireLicense xmlns="http://schemas.microsoft.com/DRM/2007/03/protocols"><challenge>""" +
95 """</challenge></AcquireLicense>""")
97 response = client.call('AcquireLicense', params)
100 if __name__ == "__main__":