Skip to content

Instantly share code, notes, and snippets.

@ToreJuloe
Last active April 11, 2017 09:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ToreJuloe/a5bff9905e63dadd050849e1601ab9b9 to your computer and use it in GitHub Desktop.
Save ToreJuloe/a5bff9905e63dadd050849e1601ab9b9 to your computer and use it in GitHub Desktop.
Extract a key ID from a Smooth Streaming asset
// Adapted nippet from here: https://rosettacode.org/wiki/Strip_control_codes_and_extended_characters_from_a_string#JavaScript
// Also remove non "<" chars in the beginning of the XML.
function stripGarbage (string) {
return string.split('').filter(function (character) {
const number = character.charCodeAt(0)
return 31 < number && 127 > number
}).join('').replace(/^[^<]*/, '')
}
// Snippet from here: http://stackoverflow.com/a/13240395/511923
function toHex (d) {
return ("0" + (Number(d).toString(16))).slice(-2).toUpperCase()
}
// Code adapted from C# example here: https://www.computerworld.dk/eksperten/spm/1003445?k=8181491
function getKID (txt) {
const domparser = new DOMParser()
// Strip garbage and parse the text as XML
const xmlData = domparser.parseFromString(stripGarbage(txt), "text/xml", 0)
// Decode Base64 and get innerHTML of the ProtectionHeader
const innerProtectionHeader = atob(xmlData.getElementsByTagName('ProtectionHeader')[0].innerHTML)
// Strip garbage and parse again ...
const protectionHeaderXML = domparser.parseFromString(stripGarbage(innerProtectionHeader), "text/xml", 0)
// return the innerHTML of the KeyID (KID)
return protectionHeaderXML.getElementsByTagName('KID')[0].innerHTML
}
function arrayToGuid (arr) {
// Why reverse? Something about little and big endian.
return arr.slice(0, 4).reverse().join('').toLowerCase()
+ '-' + arr.slice(4, 6).reverse().join('').toLowerCase()
+ '-' + arr.slice(6, 8).reverse().join('').toLowerCase()
+ '-' + arr.slice(8, 10).join('').toLowerCase()
+ '-' + arr.slice(10, 16).join('').toLowerCase()
}
function base64StringToGuid (base64string) {
const charArray = atob(base64string)
.split('')
.map(el => el.charCodeAt(0))
.map(el => toHex(el))
return arrayToGuid(charArray)
}
function fetchFromSmoothStreamingManifest (manifesturl, expectedString) {
return fetch(manifesturl)
.then(resp => resp.text())
.then(txt => getKID(txt))
.then(kid => console.log(`Key ID match? ${ base64StringToGuid(kid) } === ${ expectedString } :`, (base64StringToGuid(kid)) === expectedString))
}
// Try it on a test Smooth Streaming asset from: http://playready.azurewebsites.net/Home/AdaptiveTests
// Should yield 6f651ae1-dbe4-4434-bcb4-690d1564c41c
fetchFromSmoothStreamingManifest('http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/manifest', '6f651ae1-dbe4-4434-bcb4-690d1564c41c')
// Should yield 09E36702-8F33-436C-A5DD-60FFE6671E70
fetchFromSmoothStreamingManifest('http://playready.eastus2.cloudapp.azure.com/smoothstreaming/SSWSS720H264PR/SuperSpeedway_720.ism/Manifest', '09e36702-8f33-436c-a5dd-60ffe6671e70')
@ToreJuloe
Copy link
Author

Only after having written this, did I discover that dash.js now also has a SmoothStreaming parser with a bit that does the same thing: https://github.com/Dash-Industry-Forum/dash.js/blob/development/src/mss/parser/MssParser.js#L346-L375

😞

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment