Background
You might notice your Stream plays on 80% of devices but fails on 20% of them. i.e typical 80-20 rule. Particularly on Live Streams.
In Bitmovin we’ve seen older devices making the bulk of this 20% devices.
Fixing the Stream
After investigating, if the issue’s with the in-stream mp4 boxes you’re likely to update your encoder/packager. This is COSTLY as regression testing is needed and RISKS breaking a device in your 80%.
At Bitmovin, you’ve ANOTHER alternative. CLIENT-SIDE FIXING of the mp4 box in the client!
A Real-Life Usecase
Problem
- Customer’s stream does not have PSSH boxes due to legacy reason
- Tizen 2016 Tv MUST have PSSH box in init segment for DRM decoding
Solution
Bitmovin + codem-isoboxer in THREE steps
- Include the
codem-isoboxer
js script in your HTML file.
<script type="text/javascript"
src="https://cdn.jsdelivr.net/npm/codem-isoboxer@0.3.7/dist/iso_boxer.min.js"></script>
- Update Bitmovin Player network configuration to preprocess media segments before passing it to decoder.
var conf = {
key: 'YOUR-PLAYER-KEY',
playback: {
muted: true,
autoplay: true,
},
.....
.....
.....
network: {
preprocessHttpResponse: function (type, response) {
if (type.includes('media')) {
response.body = prepareSegment(response.body);
}
return Promise.resolve(response);
},
}
};
- Code to modify MP4 box in the segment. In this case add the
PSSH
box in the init segment
function prepareSegment(segmentData) {
var isoFile = ISOBoxer.parseBuffer(segmentData);
/****** An init segment MUST contain `ftyp` and `moov` box *****/
var ftyp = isoFile.fetch('ftyp');
if (!ftyp) {
return segmentData;
}
var moov = isoFile.fetch('moov');
if(!moov) {
return segmentData;
}
/************************************************************/
appendPsshBox(moov);
console.log('---------edited moov box---------');
console.log(moov);
return isoFile.write();
}
function appendPsshBox(parent) {
var psshWidevine = "--YOUR--BASE64--WIDEVINE--PSSH--VALUE--FROM--MANIFEST--";
var psshPlayready = "--YOUR--BASE64--PLAYREADY--PSSH--VALUE--FROM--MANIFEST--"
/******************* Widevine ***************************/
let wvPsshBox = ISOBoxer.createFullBox('pssh');
// Widevine PSSH
wvPsshBox['SystemID'] = [0xed, 0xef, 0x8b, 0xa9, 0x79, 0xd6, 0x4a, 0xce, 0xa3, 0xc8, 0x27, 0xdc, 0xd5, 0x1d, 0x21, 0xed];
// PSSH in binary form
wvPsshBox['Data'] = new Uint8Array(atob(psshWidevine).split("").map(function (c) {
return c.charCodeAt(0);
}));
wvPsshBox['DataSize'] = wvPsshBox['Data'].length;
ISOBoxer.Utils.appendBox(parent, wvPsshBox, 0);
/******************* Playready ***************************/
let prPsshBox = ISOBoxer.createFullBox('pssh');
// Widevine PSSH
prPsshBox['SystemID'] = [0x9a, 0x04, 0xf0, 0x79, 0x98, 0x40, 0x42, 0x86, 0xab, 0x92, 0xe6, 0x5b, 0xe0, 0x88, 0x5f, 0x95];
// PSSH in binary form
prPsshBox['Data'] = new Uint8Array(atob(psshPlayready).split("").map(function (c) {
return c.charCodeAt(0);
}));
prPsshBox['DataSize'] = prPsshBox['Data'].length;
ISOBoxer.Utils.appendBox(parent, prPsshBox, 0);
}