hls.js 1.5.14-0.canary.10555 → 1.5.14-0.canary.10559
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hls-demo.js +3 -2
- package/dist/hls-demo.js.map +1 -1
- package/dist/hls.js +97 -43
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +2 -3
- package/dist/hls.light.js.map +1 -1
- package/dist/hls.light.min.js +1 -1
- package/dist/hls.light.min.js.map +1 -1
- package/dist/hls.light.mjs +2 -3
- package/dist/hls.light.mjs.map +1 -1
- package/dist/hls.min.js +1 -1
- package/dist/hls.min.js.map +1 -1
- package/dist/hls.mjs +91 -43
- package/dist/hls.mjs.map +1 -1
- package/dist/hls.worker.js +1 -1
- package/dist/hls.worker.js.map +1 -1
- package/package.json +2 -2
- package/src/controller/eme-controller.ts +39 -19
- package/src/utils/mediakeys-helper.ts +11 -8
- package/src/utils/mp4-tools.ts +72 -27
package/package.json
CHANGED
@@ -111,7 +111,7 @@
|
|
111
111
|
"karma-rollup-preprocessor": "github:jlmakes/karma-rollup-preprocessor#7a7268d91149307b3cf2888ee4e65ccd079955a3",
|
112
112
|
"karma-sinon-chai": "2.0.2",
|
113
113
|
"karma-sourcemap-loader": "0.4.0",
|
114
|
-
"lint-staged": "15.2.
|
114
|
+
"lint-staged": "15.2.9",
|
115
115
|
"markdown-styles": "3.2.0",
|
116
116
|
"micromatch": "4.0.7",
|
117
117
|
"mocha": "10.7.3",
|
@@ -130,5 +130,5 @@
|
|
130
130
|
"url-toolkit": "2.2.5",
|
131
131
|
"wrangler": "3.72.0"
|
132
132
|
},
|
133
|
-
"version": "1.5.14-0.canary.
|
133
|
+
"version": "1.5.14-0.canary.10559"
|
134
134
|
}
|
@@ -14,8 +14,6 @@ import {
|
|
14
14
|
keySystemFormatToKeySystemDomain,
|
15
15
|
KeySystemIds,
|
16
16
|
keySystemIdToKeySystemDomain,
|
17
|
-
} from '../utils/mediakeys-helper';
|
18
|
-
import {
|
19
17
|
KeySystems,
|
20
18
|
requestMediaKeySystemAccess,
|
21
19
|
} from '../utils/mediakeys-helper';
|
@@ -23,7 +21,13 @@ import { strToUtf8array } from '../utils/utf8-utils';
|
|
23
21
|
import { base64Decode } from '../utils/numeric-encoding-utils';
|
24
22
|
import { DecryptData, LevelKey } from '../loader/level-key';
|
25
23
|
import Hex from '../utils/hex';
|
26
|
-
import {
|
24
|
+
import {
|
25
|
+
bin2str,
|
26
|
+
parseMultiPssh,
|
27
|
+
parseSinf,
|
28
|
+
PsshData,
|
29
|
+
PsshInvalidResult,
|
30
|
+
} from '../utils/mp4-tools';
|
27
31
|
import { EventEmitter } from 'eventemitter3';
|
28
32
|
import type Hls from '../hls';
|
29
33
|
import type { ComponentAPI } from '../types/component-api';
|
@@ -512,7 +516,8 @@ class EMEController extends Logger implements ComponentAPI {
|
|
512
516
|
|
513
517
|
private onMediaEncrypted = (event: MediaEncryptedEvent) => {
|
514
518
|
const { initDataType, initData } = event;
|
515
|
-
|
519
|
+
const logMessage = `"${event.type}" event: init data type: "${initDataType}"`;
|
520
|
+
this.debug(logMessage);
|
516
521
|
|
517
522
|
// Ignore event when initData is null
|
518
523
|
if (initData === null) {
|
@@ -532,30 +537,42 @@ class EMEController extends Logger implements ComponentAPI {
|
|
532
537
|
const sinf = base64Decode(JSON.parse(json).sinf);
|
533
538
|
const tenc = parseSinf(new Uint8Array(sinf));
|
534
539
|
if (!tenc) {
|
535
|
-
|
540
|
+
throw new Error(
|
541
|
+
`'schm' box missing or not cbcs/cenc with schi > tenc`,
|
542
|
+
);
|
536
543
|
}
|
537
544
|
keyId = tenc.subarray(8, 24);
|
538
545
|
keySystemDomain = KeySystems.FAIRPLAY;
|
539
546
|
} catch (error) {
|
540
|
-
this.warn(
|
547
|
+
this.warn(`${logMessage} Failed to parse sinf: ${error}`);
|
541
548
|
return;
|
542
549
|
}
|
543
550
|
} else {
|
544
|
-
// Support clear-lead key-session creation (otherwise depend on playlist keys)
|
545
|
-
const
|
546
|
-
|
551
|
+
// Support Widevine clear-lead key-session creation (otherwise depend on playlist keys)
|
552
|
+
const psshResults = parseMultiPssh(initData);
|
553
|
+
const psshInfo = psshResults.filter(
|
554
|
+
(pssh): pssh is PsshData => pssh.systemId === KeySystemIds.WIDEVINE,
|
555
|
+
)[0];
|
556
|
+
if (!psshInfo) {
|
557
|
+
if (
|
558
|
+
psshResults.length === 0 ||
|
559
|
+
psshResults.some((pssh): pssh is PsshInvalidResult => !pssh.systemId)
|
560
|
+
) {
|
561
|
+
this.warn(`${logMessage} contains incomplete or invalid pssh data`);
|
562
|
+
} else {
|
563
|
+
this.log(
|
564
|
+
`ignoring ${logMessage} for ${(psshResults as PsshData[])
|
565
|
+
.map((pssh) => keySystemIdToKeySystemDomain(pssh.systemId))
|
566
|
+
.join(',')} pssh data in favor of playlist keys`,
|
567
|
+
);
|
568
|
+
}
|
547
569
|
return;
|
548
570
|
}
|
549
|
-
|
550
|
-
|
551
|
-
psshInfo.
|
552
|
-
psshInfo.data
|
553
|
-
) {
|
554
|
-
keyId = psshInfo.data.subarray(8, 24);
|
571
|
+
keySystemDomain = keySystemIdToKeySystemDomain(psshInfo.systemId);
|
572
|
+
if (psshInfo.version === 0 && psshInfo.data) {
|
573
|
+
const offset = psshInfo.data.length - 22;
|
574
|
+
keyId = psshInfo.data.subarray(offset, offset + 16);
|
555
575
|
}
|
556
|
-
keySystemDomain = keySystemIdToKeySystemDomain(
|
557
|
-
psshInfo.systemId as KeySystemIds,
|
558
|
-
);
|
559
576
|
}
|
560
577
|
|
561
578
|
if (!keySystemDomain || !keyId) {
|
@@ -570,7 +587,7 @@ class EMEController extends Logger implements ComponentAPI {
|
|
570
587
|
// Match playlist key
|
571
588
|
const keyContext = mediaKeySessions[i];
|
572
589
|
const decryptdata = keyContext.decryptdata;
|
573
|
-
if (
|
590
|
+
if (!decryptdata.keyId) {
|
574
591
|
continue;
|
575
592
|
}
|
576
593
|
const oldKeyIdHex = Hex.hexDump(decryptdata.keyId);
|
@@ -579,6 +596,9 @@ class EMEController extends Logger implements ComponentAPI {
|
|
579
596
|
decryptdata.uri.replace(/-/g, '').indexOf(keyIdHex) !== -1
|
580
597
|
) {
|
581
598
|
keySessionContextPromise = keyIdToKeySessionPromise[oldKeyIdHex];
|
599
|
+
if (decryptdata.pssh) {
|
600
|
+
break;
|
601
|
+
}
|
582
602
|
delete keyIdToKeySessionPromise[oldKeyIdHex];
|
583
603
|
decryptdata.pssh = new Uint8Array(initData);
|
584
604
|
decryptdata.keyId = keyId;
|
@@ -36,10 +36,10 @@ export function keySystemFormatToKeySystemDomain(
|
|
36
36
|
|
37
37
|
// System IDs for which we can extract a key ID from "encrypted" event PSSH
|
38
38
|
export const enum KeySystemIds {
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
CENC = '1077efecc0b24d02ace33c1e52e2fb4b',
|
40
|
+
CLEARKEY = 'e2719d58a985b3c9781ab030af78d30e',
|
41
|
+
FAIRPLAY = '94ce86fb07ff4f43adb893d2fa968ca2',
|
42
|
+
PLAYREADY = '9a04f07998404286ab92e65be0885f95',
|
43
43
|
WIDEVINE = 'edef8ba979d64acea3c827dcd51d21ed',
|
44
44
|
}
|
45
45
|
|
@@ -48,10 +48,13 @@ export function keySystemIdToKeySystemDomain(
|
|
48
48
|
): KeySystems | undefined {
|
49
49
|
if (systemId === KeySystemIds.WIDEVINE) {
|
50
50
|
return KeySystems.WIDEVINE;
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
51
|
+
} else if (systemId === KeySystemIds.PLAYREADY) {
|
52
|
+
return KeySystems.PLAYREADY;
|
53
|
+
} else if (
|
54
|
+
systemId === KeySystemIds.CENC ||
|
55
|
+
systemId === KeySystemIds.CLEARKEY
|
56
|
+
) {
|
57
|
+
return KeySystems.CLEARKEY;
|
55
58
|
}
|
56
59
|
}
|
57
60
|
|
package/src/utils/mp4-tools.ts
CHANGED
@@ -3,6 +3,7 @@ import { sliceUint8 } from './typed-array';
|
|
3
3
|
import { utf8ArrayToStr } from '@svta/common-media-library/utils/utf8ArrayToStr';
|
4
4
|
import { logger } from '../utils/logger';
|
5
5
|
import Hex from './hex';
|
6
|
+
import type { KeySystemIds } from './mediakeys-helper';
|
6
7
|
import type { PassthroughTrack, UserdataSample } from '../types/demuxer';
|
7
8
|
import type { DecryptData } from '../loader/level-key';
|
8
9
|
|
@@ -547,7 +548,6 @@ export function parseSinf(sinf: Uint8Array): Uint8Array | null {
|
|
547
548
|
return findBox(sinf, ['schi', 'tenc'])[0];
|
548
549
|
}
|
549
550
|
}
|
550
|
-
logger.error(`[eme] missing 'schm' box`);
|
551
551
|
return null;
|
552
552
|
}
|
553
553
|
|
@@ -1351,41 +1351,86 @@ export function mp4pssh(
|
|
1351
1351
|
);
|
1352
1352
|
}
|
1353
1353
|
|
1354
|
-
export
|
1355
|
-
|
1356
|
-
|
1354
|
+
export type PsshData = {
|
1355
|
+
version: 0 | 1;
|
1356
|
+
systemId: KeySystemIds;
|
1357
|
+
kids: null | Uint8Array[];
|
1358
|
+
data: null | Uint8Array;
|
1359
|
+
offset: number;
|
1360
|
+
size: number;
|
1361
|
+
};
|
1362
|
+
|
1363
|
+
export type PsshInvalidResult = {
|
1364
|
+
systemId?: undefined;
|
1365
|
+
offset: number;
|
1366
|
+
size: number;
|
1367
|
+
};
|
1368
|
+
|
1369
|
+
export function parseMultiPssh(
|
1370
|
+
initData: ArrayBuffer,
|
1371
|
+
): (PsshData | PsshInvalidResult)[] {
|
1372
|
+
const results: (PsshData | PsshInvalidResult)[] = [];
|
1373
|
+
if (initData instanceof ArrayBuffer) {
|
1374
|
+
const length = initData.byteLength;
|
1375
|
+
let offset = 0;
|
1376
|
+
while (offset + 32 < length) {
|
1377
|
+
const view = new DataView(initData, offset);
|
1378
|
+
const pssh = parsePssh(view);
|
1379
|
+
results.push(pssh);
|
1380
|
+
offset += pssh.size;
|
1381
|
+
}
|
1357
1382
|
}
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1361
|
-
|
1362
|
-
|
1363
|
-
|
1364
|
-
const
|
1365
|
-
|
1366
|
-
|
1367
|
-
|
1383
|
+
return results;
|
1384
|
+
}
|
1385
|
+
|
1386
|
+
function parsePssh(view: DataView): PsshData | PsshInvalidResult {
|
1387
|
+
const size = view.getUint32(0);
|
1388
|
+
const offset = view.byteOffset;
|
1389
|
+
const length = view.byteLength;
|
1390
|
+
if (length < size) {
|
1391
|
+
return {
|
1392
|
+
offset,
|
1393
|
+
size: length,
|
1394
|
+
};
|
1368
1395
|
}
|
1369
1396
|
const type = view.getUint32(4);
|
1370
1397
|
if (type !== 0x70737368) {
|
1371
|
-
return
|
1398
|
+
return { offset, size };
|
1372
1399
|
}
|
1373
|
-
|
1374
|
-
if (
|
1375
|
-
return
|
1400
|
+
const version = view.getUint32(8) >>> 24;
|
1401
|
+
if (version !== 0 && version !== 1) {
|
1402
|
+
return { offset, size };
|
1376
1403
|
}
|
1377
|
-
|
1404
|
+
const buffer = view.buffer;
|
1405
|
+
const systemId = Hex.hexDump(
|
1406
|
+
new Uint8Array(buffer, offset + 12, 16),
|
1407
|
+
) as KeySystemIds;
|
1378
1408
|
const dataSizeOrKidCount = view.getUint32(28);
|
1379
|
-
|
1380
|
-
|
1381
|
-
|
1409
|
+
let kids: null | Uint8Array[] = null;
|
1410
|
+
let data: null | Uint8Array = null;
|
1411
|
+
if (version === 0) {
|
1412
|
+
if (size - 32 < dataSizeOrKidCount || dataSizeOrKidCount < 22) {
|
1413
|
+
return { offset, size };
|
1414
|
+
}
|
1415
|
+
data = new Uint8Array(buffer, offset + 32, dataSizeOrKidCount);
|
1416
|
+
} else if (version === 1) {
|
1417
|
+
if (
|
1418
|
+
!dataSizeOrKidCount ||
|
1419
|
+
length < offset + 32 + dataSizeOrKidCount * 16 + 16
|
1420
|
+
) {
|
1421
|
+
return { offset, size };
|
1382
1422
|
}
|
1383
|
-
|
1384
|
-
} else if (result.version === 1) {
|
1385
|
-
result.kids = [];
|
1423
|
+
kids = [];
|
1386
1424
|
for (let i = 0; i < dataSizeOrKidCount; i++) {
|
1387
|
-
|
1425
|
+
kids.push(new Uint8Array(buffer, offset + 32 + i * 16, 16));
|
1388
1426
|
}
|
1389
1427
|
}
|
1390
|
-
return
|
1428
|
+
return {
|
1429
|
+
version,
|
1430
|
+
systemId,
|
1431
|
+
kids,
|
1432
|
+
data,
|
1433
|
+
offset,
|
1434
|
+
size,
|
1435
|
+
};
|
1391
1436
|
}
|