Prerequisites · 10 min read

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.

No questions yet for python-xml. Add some in content/questions/python-xml.json.