Python & XML Quick Reference
Reading XML license requests, Python idioms used in labs.
Why Python and XML
CWIP labs use Python scripts to drive the SDK and parse / generate XML (DASH manifests, configuration files). You don't need to be a Python expert; you need to read it confidently and tweak it without surprises.
Reading a DASH MPD
import xml.etree.ElementTree as ET
tree = ET.parse("manifest.mpd")
root = tree.getroot()
# Namespaces in DASH are declared at the top of the document.
NS = {
"mpd": "urn:mpeg:dash:schema:mpd:2011",
"cenc": "urn:mpeg:cenc:2013",
}
for adapt in root.iter(f"{{{NS['mpd']}}}AdaptationSet"):
mime = adapt.attrib.get("mimeType")
print("AdaptationSet:", mime)
for prot in adapt.findall(f"{{{NS['mpd']}}}ContentProtection"):
scheme = prot.attrib.get("schemeIdUri")
print(" ContentProtection:", scheme)
ElementTree uses Clark notation {namespace}localname for namespaced elements. Don't strip the namespace — be explicit and your scripts won't break when the next manifest uses a slightly different prefix.
Writing XML config
For lab configuration files:
import xml.etree.ElementTree as ET
config = ET.Element("Config")
ET.SubElement(config, "LicenseUrl").text = "https://license.example.com/widevine"
ET.SubElement(config, "ContentKey", {"kid": "abc123"}).text = "deadbeef..."
tree = ET.ElementTree(config)
ET.indent(tree, space=" ")
tree.write("config.xml", encoding="utf-8", xml_declaration=True)
HTTP from Python
The standard library is enough for lab work:
import urllib.request, ssl
req = urllib.request.Request(
"https://license.example.com/widevine",
data=licence_request_bytes,
headers={"Authorization": f"Bearer {app_token}",
"Content-Type": "application/octet-stream"},
method="POST",
)
with urllib.request.urlopen(req) as resp:
licence_response = resp.read()
Or, if requests is installed:
import requests
r = requests.post(
"https://license.example.com/widevine",
data=licence_request_bytes,
headers={"Authorization": f"Bearer {app_token}"},
)
r.raise_for_status()
licence_response = r.content
Base64 + hex
You'll meet PSSH boxes encoded as base64 and KIDs as hex:
import base64, binascii
pssh_b64 = "AAAAQ3Bzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAACMI..."
pssh = base64.b64decode(pssh_b64)
print(binascii.hexlify(pssh[:16]).decode()) # first 16 bytes as hex
What CWIPs read most often
A typical Day 2 task is "given this MPD, show me the KIDs and the Widevine PSSH." A 10-line Python script with ElementTree handles it. Practice that one pattern and most of the lab work falls out.