hls.js 1.5.13 → 1.5.14-0.canary.10415
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/README.md +4 -3
- package/dist/hls-demo.js +41 -38
- package/dist/hls-demo.js.map +1 -1
- package/dist/hls.js +4211 -2666
- package/dist/hls.js.d.ts +179 -110
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +2841 -1921
- 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 +2569 -1639
- 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 +3572 -2017
- 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 +38 -38
- package/src/config.ts +5 -2
- package/src/controller/abr-controller.ts +39 -25
- package/src/controller/audio-stream-controller.ts +156 -136
- package/src/controller/audio-track-controller.ts +1 -1
- package/src/controller/base-playlist-controller.ts +27 -10
- package/src/controller/base-stream-controller.ts +234 -89
- package/src/controller/buffer-controller.ts +250 -97
- package/src/controller/buffer-operation-queue.ts +16 -19
- package/src/controller/cap-level-controller.ts +3 -2
- package/src/controller/cmcd-controller.ts +51 -14
- package/src/controller/content-steering-controller.ts +29 -15
- package/src/controller/eme-controller.ts +10 -23
- package/src/controller/error-controller.ts +28 -22
- package/src/controller/fps-controller.ts +8 -3
- package/src/controller/fragment-finders.ts +44 -16
- package/src/controller/fragment-tracker.ts +58 -25
- package/src/controller/gap-controller.ts +43 -16
- package/src/controller/id3-track-controller.ts +45 -35
- package/src/controller/latency-controller.ts +18 -13
- package/src/controller/level-controller.ts +37 -19
- package/src/controller/stream-controller.ts +100 -83
- package/src/controller/subtitle-stream-controller.ts +35 -47
- package/src/controller/subtitle-track-controller.ts +5 -3
- package/src/controller/timeline-controller.ts +20 -22
- package/src/crypt/aes-crypto.ts +21 -2
- package/src/crypt/decrypter-aes-mode.ts +4 -0
- package/src/crypt/decrypter.ts +32 -16
- package/src/crypt/fast-aes-key.ts +28 -5
- package/src/demux/audio/aacdemuxer.ts +2 -2
- package/src/demux/audio/ac3-demuxer.ts +4 -3
- package/src/demux/audio/adts.ts +9 -4
- package/src/demux/audio/base-audio-demuxer.ts +16 -14
- package/src/demux/audio/mp3demuxer.ts +4 -3
- package/src/demux/audio/mpegaudio.ts +1 -1
- package/src/demux/mp4demuxer.ts +7 -7
- package/src/demux/sample-aes.ts +2 -0
- package/src/demux/transmuxer-interface.ts +8 -16
- package/src/demux/transmuxer-worker.ts +4 -4
- package/src/demux/transmuxer.ts +16 -3
- package/src/demux/tsdemuxer.ts +75 -38
- package/src/demux/video/avc-video-parser.ts +210 -121
- package/src/demux/video/base-video-parser.ts +135 -2
- package/src/demux/video/exp-golomb.ts +0 -208
- package/src/demux/video/hevc-video-parser.ts +749 -0
- package/src/events.ts +8 -1
- package/src/exports-named.ts +1 -1
- package/src/hls.ts +84 -47
- package/src/loader/date-range.ts +71 -5
- package/src/loader/fragment-loader.ts +23 -21
- package/src/loader/fragment.ts +8 -4
- package/src/loader/key-loader.ts +3 -1
- package/src/loader/level-details.ts +6 -6
- package/src/loader/level-key.ts +10 -9
- package/src/loader/m3u8-parser.ts +138 -144
- package/src/loader/playlist-loader.ts +5 -7
- package/src/remux/mp4-generator.ts +196 -1
- package/src/remux/mp4-remuxer.ts +32 -62
- package/src/remux/passthrough-remuxer.ts +1 -1
- package/src/task-loop.ts +5 -2
- package/src/types/component-api.ts +3 -1
- package/src/types/demuxer.ts +3 -0
- package/src/types/events.ts +19 -6
- package/src/types/fragment-tracker.ts +2 -2
- package/src/types/media-playlist.ts +9 -1
- package/src/types/remuxer.ts +1 -1
- package/src/utils/attr-list.ts +96 -9
- package/src/utils/buffer-helper.ts +12 -31
- package/src/utils/cea-608-parser.ts +1 -3
- package/src/utils/codecs.ts +34 -5
- package/src/utils/encryption-methods-util.ts +21 -0
- package/src/utils/fetch-loader.ts +1 -1
- package/src/utils/hash.ts +10 -0
- package/src/utils/hdr.ts +4 -7
- package/src/utils/imsc1-ttml-parser.ts +1 -1
- package/src/utils/keysystem-util.ts +1 -6
- package/src/utils/level-helper.ts +71 -44
- package/src/utils/logger.ts +58 -23
- package/src/utils/mp4-tools.ts +5 -3
- package/src/utils/rendition-helper.ts +100 -74
- package/src/utils/utf8-utils.ts +18 -0
- package/src/utils/variable-substitution.ts +0 -19
- package/src/utils/webvtt-parser.ts +2 -12
- package/src/demux/id3.ts +0 -411
- package/src/types/general.ts +0 -6
package/src/demux/audio/adts.ts
CHANGED
@@ -17,6 +17,7 @@ type AudioConfig = {
|
|
17
17
|
samplerate: number;
|
18
18
|
channelCount: number;
|
19
19
|
codec: string;
|
20
|
+
parsedCodec: string;
|
20
21
|
manifestCodec: string;
|
21
22
|
};
|
22
23
|
|
@@ -32,6 +33,7 @@ export function getAudioConfig(
|
|
32
33
|
audioCodec: string,
|
33
34
|
): AudioConfig | void {
|
34
35
|
let adtsObjectType: number;
|
36
|
+
let originalAdtsObjectType: number;
|
35
37
|
let adtsExtensionSamplingIndex: number;
|
36
38
|
let adtsChannelConfig: number;
|
37
39
|
let config: number[];
|
@@ -42,7 +44,8 @@ export function getAudioConfig(
|
|
42
44
|
8000, 7350,
|
43
45
|
];
|
44
46
|
// byte 2
|
45
|
-
adtsObjectType =
|
47
|
+
adtsObjectType = originalAdtsObjectType =
|
48
|
+
((data[offset + 2] & 0xc0) >>> 6) + 1;
|
46
49
|
const adtsSamplingIndex = (data[offset + 2] & 0x3c) >>> 2;
|
47
50
|
if (adtsSamplingIndex > adtsSamplingRates.length - 1) {
|
48
51
|
const error = new Error(`invalid ADTS sampling index:${adtsSamplingIndex}`);
|
@@ -61,8 +64,8 @@ export function getAudioConfig(
|
|
61
64
|
logger.log(
|
62
65
|
`manifest codec:${audioCodec}, ADTS type:${adtsObjectType}, samplingIndex:${adtsSamplingIndex}`,
|
63
66
|
);
|
64
|
-
//
|
65
|
-
if (/firefox/i.test(userAgent)) {
|
67
|
+
// Firefox and Pale Moon: freq less than 24kHz = AAC SBR (HE-AAC)
|
68
|
+
if (/firefox|palemoon/i.test(userAgent)) {
|
66
69
|
if (adtsSamplingIndex >= 6) {
|
67
70
|
adtsObjectType = 5;
|
68
71
|
config = new Array(4);
|
@@ -167,6 +170,7 @@ export function getAudioConfig(
|
|
167
170
|
samplerate: adtsSamplingRates[adtsSamplingIndex],
|
168
171
|
channelCount: adtsChannelConfig,
|
169
172
|
codec: 'mp4a.40.' + adtsObjectType,
|
173
|
+
parsedCodec: 'mp4a.40.' + originalAdtsObjectType,
|
170
174
|
manifestCodec,
|
171
175
|
};
|
172
176
|
}
|
@@ -244,8 +248,9 @@ export function initTrackConfig(
|
|
244
248
|
track.channelCount = config.channelCount;
|
245
249
|
track.codec = config.codec;
|
246
250
|
track.manifestCodec = config.manifestCodec;
|
251
|
+
track.parsedCodec = config.parsedCodec;
|
247
252
|
logger.log(
|
248
|
-
`parsed codec:${track.codec}, rate:${config.samplerate}, channels:${config.channelCount}`,
|
253
|
+
`parsed codec:${track.parsedCodec}, codec:${track.codec}, rate:${config.samplerate}, channels:${config.channelCount}`,
|
249
254
|
);
|
250
255
|
}
|
251
256
|
}
|
@@ -1,19 +1,21 @@
|
|
1
|
-
import * as ID3 from '../id3';
|
2
1
|
import {
|
3
|
-
DemuxerResult,
|
4
|
-
Demuxer,
|
5
|
-
DemuxedAudioTrack,
|
6
|
-
AudioFrame,
|
7
|
-
DemuxedMetadataTrack,
|
8
|
-
DemuxedVideoTrackBase,
|
9
|
-
DemuxedUserdataTrack,
|
10
|
-
KeyData,
|
2
|
+
type DemuxerResult,
|
3
|
+
type Demuxer,
|
4
|
+
type DemuxedAudioTrack,
|
5
|
+
type AudioFrame,
|
6
|
+
type DemuxedMetadataTrack,
|
7
|
+
type DemuxedVideoTrackBase,
|
8
|
+
type DemuxedUserdataTrack,
|
9
|
+
type KeyData,
|
11
10
|
MetadataSchema,
|
12
11
|
} from '../../types/demuxer';
|
13
12
|
import { dummyTrack } from '../dummy-demuxed-track';
|
14
13
|
import { appendUint8Array } from '../../utils/mp4-tools';
|
15
14
|
import { sliceUint8 } from '../../utils/typed-array';
|
16
15
|
import { RationalTimestamp } from '../../utils/timescale-conversion';
|
16
|
+
import { getId3Data } from '@svta/common-media-library/id3/getId3Data';
|
17
|
+
import { getId3Timestamp } from '@svta/common-media-library/id3/getId3Timestamp';
|
18
|
+
import { canParseId3 } from '@svta/common-media-library/id3/canParseId3';
|
17
19
|
|
18
20
|
class BaseAudioDemuxer implements Demuxer {
|
19
21
|
protected _audioTrack!: DemuxedAudioTrack;
|
@@ -69,12 +71,12 @@ class BaseAudioDemuxer implements Demuxer {
|
|
69
71
|
this.cachedData = null;
|
70
72
|
}
|
71
73
|
|
72
|
-
let id3Data: Uint8Array | undefined =
|
74
|
+
let id3Data: Uint8Array | undefined = getId3Data(data, 0);
|
73
75
|
let offset = id3Data ? id3Data.length : 0;
|
74
76
|
let lastDataIndex;
|
75
77
|
const track = this._audioTrack;
|
76
78
|
const id3Track = this._id3Track;
|
77
|
-
const timestamp = id3Data ?
|
79
|
+
const timestamp = id3Data ? getId3Timestamp(id3Data) : undefined;
|
78
80
|
const length = data.length;
|
79
81
|
|
80
82
|
if (
|
@@ -111,9 +113,9 @@ class BaseAudioDemuxer implements Demuxer {
|
|
111
113
|
} else {
|
112
114
|
offset = length;
|
113
115
|
}
|
114
|
-
} else if (
|
115
|
-
// after a
|
116
|
-
id3Data =
|
116
|
+
} else if (canParseId3(data, offset)) {
|
117
|
+
// after a canParse, a call to getId3Data *should* always returns some data
|
118
|
+
id3Data = getId3Data(data, offset)!;
|
117
119
|
id3Track.samples.push({
|
118
120
|
pts: this.lastPTS,
|
119
121
|
dts: this.lastPTS,
|
@@ -2,10 +2,11 @@
|
|
2
2
|
* MP3 demuxer
|
3
3
|
*/
|
4
4
|
import BaseAudioDemuxer from './base-audio-demuxer';
|
5
|
-
import { getID3Data, getTimeStamp } from '../id3';
|
6
5
|
import { getAudioBSID } from './dolby';
|
7
6
|
import { logger } from '../../utils/logger';
|
8
7
|
import * as MpegAudio from './mpegaudio';
|
8
|
+
import { getId3Data } from '@svta/common-media-library/id3/getId3Data';
|
9
|
+
import { getId3Timestamp } from '@svta/common-media-library/id3/getId3Timestamp';
|
9
10
|
|
10
11
|
class MP3Demuxer extends BaseAudioDemuxer {
|
11
12
|
resetInitSegment(
|
@@ -39,7 +40,7 @@ class MP3Demuxer extends BaseAudioDemuxer {
|
|
39
40
|
// Look for MPEG header | 1111 1111 | 111X XYZX | where X can be either 0 or 1 and Y or Z should be 1
|
40
41
|
// Layer bits (position 14 and 15) in header should be always different from 0 (Layer I or Layer II or Layer III)
|
41
42
|
// More info http://www.mp3-tech.org/programmer/frame_header.html
|
42
|
-
const id3Data =
|
43
|
+
const id3Data = getId3Data(data, 0);
|
43
44
|
let offset = id3Data?.length || 0;
|
44
45
|
|
45
46
|
// Check for ac-3|ec-3 sync bytes and return false if present
|
@@ -47,7 +48,7 @@ class MP3Demuxer extends BaseAudioDemuxer {
|
|
47
48
|
id3Data &&
|
48
49
|
data[offset] === 0x0b &&
|
49
50
|
data[offset + 1] === 0x77 &&
|
50
|
-
|
51
|
+
getId3Timestamp(id3Data) !== undefined &&
|
51
52
|
// check the bsid to confirm ac-3 or ec-3 (not mp3)
|
52
53
|
getAudioBSID(data, offset) <= 16
|
53
54
|
) {
|
package/src/demux/mp4demuxer.ts
CHANGED
@@ -2,13 +2,13 @@
|
|
2
2
|
* MP4 demuxer
|
3
3
|
*/
|
4
4
|
import {
|
5
|
-
Demuxer,
|
6
|
-
DemuxerResult,
|
7
|
-
PassthroughTrack,
|
8
|
-
DemuxedAudioTrack,
|
9
|
-
DemuxedUserdataTrack,
|
10
|
-
DemuxedMetadataTrack,
|
11
|
-
KeyData,
|
5
|
+
type Demuxer,
|
6
|
+
type DemuxerResult,
|
7
|
+
type PassthroughTrack,
|
8
|
+
type DemuxedAudioTrack,
|
9
|
+
type DemuxedUserdataTrack,
|
10
|
+
type DemuxedMetadataTrack,
|
11
|
+
type KeyData,
|
12
12
|
MetadataSchema,
|
13
13
|
} from '../types/demuxer';
|
14
14
|
import {
|
package/src/demux/sample-aes.ts
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
|
5
5
|
import { HlsConfig } from '../config';
|
6
6
|
import Decrypter from '../crypt/decrypter';
|
7
|
+
import { DecrypterAesMode } from '../crypt/decrypter-aes-mode';
|
7
8
|
import { HlsEventEmitter } from '../events';
|
8
9
|
import type {
|
9
10
|
AudioSample,
|
@@ -30,6 +31,7 @@ class SampleAesDecrypter {
|
|
30
31
|
encryptedData,
|
31
32
|
this.keyData.key.buffer,
|
32
33
|
this.keyData.iv.buffer,
|
34
|
+
DecrypterAesMode.cbc,
|
33
35
|
);
|
34
36
|
}
|
35
37
|
|
@@ -12,14 +12,13 @@ import Transmuxer, {
|
|
12
12
|
} from '../demux/transmuxer';
|
13
13
|
import { logger } from '../utils/logger';
|
14
14
|
import { ErrorTypes, ErrorDetails } from '../errors';
|
15
|
-
import { getMediaSource } from '../utils/mediasource-helper';
|
16
15
|
import { EventEmitter } from 'eventemitter3';
|
17
|
-
import {
|
16
|
+
import { MediaFragment, Part } from '../loader/fragment';
|
17
|
+
import { getM2TSSupportedAudioTypes } from '../utils/codecs';
|
18
18
|
import type { ChunkMetadata, TransmuxerResult } from '../types/transmuxer';
|
19
19
|
import type Hls from '../hls';
|
20
20
|
import type { HlsEventEmitter, HlsListeners } from '../events';
|
21
21
|
import type { PlaylistLevelType } from '../types/loader';
|
22
|
-
import type { TypeSupported } from './tsdemuxer';
|
23
22
|
import type { RationalTimestamp } from '../utils/timescale-conversion';
|
24
23
|
|
25
24
|
export default class TransmuxerInterface {
|
@@ -27,7 +26,7 @@ export default class TransmuxerInterface {
|
|
27
26
|
private hls: Hls;
|
28
27
|
private id: PlaylistLevelType;
|
29
28
|
private observer: HlsEventEmitter;
|
30
|
-
private frag:
|
29
|
+
private frag: MediaFragment | null = null;
|
31
30
|
private part: Part | null = null;
|
32
31
|
private useWorker: boolean;
|
33
32
|
private workerContext: WorkerContext | null = null;
|
@@ -66,16 +65,9 @@ export default class TransmuxerInterface {
|
|
66
65
|
this.observer.on(Events.FRAG_DECRYPTED, forwardMessage);
|
67
66
|
this.observer.on(Events.ERROR, forwardMessage);
|
68
67
|
|
69
|
-
const
|
70
|
-
|
71
|
-
|
72
|
-
const m2tsTypeSupported: TypeSupported = {
|
73
|
-
mpeg: MediaSource.isTypeSupported('audio/mpeg'),
|
74
|
-
mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
|
75
|
-
ac3: __USE_M2TS_ADVANCED_CODECS__
|
76
|
-
? MediaSource.isTypeSupported('audio/mp4; codecs="ac-3"')
|
77
|
-
: false,
|
78
|
-
};
|
68
|
+
const m2tsTypeSupported = getM2TSSupportedAudioTypes(
|
69
|
+
config.preferManagedMediaSource,
|
70
|
+
);
|
79
71
|
|
80
72
|
if (this.useWorker && typeof Worker !== 'undefined') {
|
81
73
|
const canCreateWorker = config.workerPath || hasUMDWorker();
|
@@ -181,7 +173,7 @@ export default class TransmuxerInterface {
|
|
181
173
|
initSegmentData: Uint8Array | undefined,
|
182
174
|
audioCodec: string | undefined,
|
183
175
|
videoCodec: string | undefined,
|
184
|
-
frag:
|
176
|
+
frag: MediaFragment,
|
185
177
|
part: Part | null,
|
186
178
|
duration: number,
|
187
179
|
accurateTimeOffset: boolean,
|
@@ -197,7 +189,7 @@ export default class TransmuxerInterface {
|
|
197
189
|
|
198
190
|
const discontinuity = !(lastFrag && frag.cc === lastFrag.cc);
|
199
191
|
const trackSwitch = !(lastFrag && chunkMeta.level === lastFrag.level);
|
200
|
-
const snDiff = lastFrag ? chunkMeta.sn -
|
192
|
+
const snDiff = lastFrag ? chunkMeta.sn - lastFrag.sn : -1;
|
201
193
|
const partDiff = this.part ? chunkMeta.part - this.part.index : -1;
|
202
194
|
const progressive =
|
203
195
|
snDiff === 0 &&
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import Transmuxer, { isPromise } from '../demux/transmuxer';
|
2
2
|
import { Events } from '../events';
|
3
|
-
import {
|
3
|
+
import { enableLogs, type ILogFunction, type ILogger } from '../utils/logger';
|
4
4
|
import { EventEmitter } from 'eventemitter3';
|
5
5
|
import { ErrorDetails, ErrorTypes } from '../errors';
|
6
6
|
import type { RemuxedTrack, RemuxerResult } from '../types/remuxer';
|
@@ -21,7 +21,7 @@ function startWorker(self) {
|
|
21
21
|
observer.on(Events.ERROR, forwardMessage);
|
22
22
|
|
23
23
|
// forward logger events to main thread
|
24
|
-
const forwardWorkerLogs = () => {
|
24
|
+
const forwardWorkerLogs = (logger: ILogger) => {
|
25
25
|
for (const logFn in logger) {
|
26
26
|
const func: ILogFunction = (message?) => {
|
27
27
|
forwardMessage('workerLog', {
|
@@ -46,8 +46,8 @@ function startWorker(self) {
|
|
46
46
|
'',
|
47
47
|
data.id,
|
48
48
|
);
|
49
|
-
enableLogs(config.debug, data.id);
|
50
|
-
forwardWorkerLogs();
|
49
|
+
const logger = enableLogs(config.debug, data.id);
|
50
|
+
forwardWorkerLogs(logger);
|
51
51
|
forwardMessage('init', null);
|
52
52
|
break;
|
53
53
|
}
|
package/src/demux/transmuxer.ts
CHANGED
@@ -4,18 +4,23 @@ import { ErrorTypes, ErrorDetails } from '../errors';
|
|
4
4
|
import Decrypter from '../crypt/decrypter';
|
5
5
|
import AACDemuxer from './audio/aacdemuxer';
|
6
6
|
import MP4Demuxer from '../demux/mp4demuxer';
|
7
|
-
import TSDemuxer
|
7
|
+
import TSDemuxer from '../demux/tsdemuxer';
|
8
8
|
import MP3Demuxer from './audio/mp3demuxer';
|
9
9
|
import { AC3Demuxer } from './audio/ac3-demuxer';
|
10
10
|
import MP4Remuxer from '../remux/mp4-remuxer';
|
11
11
|
import PassThroughRemuxer from '../remux/passthrough-remuxer';
|
12
12
|
import { logger } from '../utils/logger';
|
13
|
+
import {
|
14
|
+
isFullSegmentEncryption,
|
15
|
+
getAesModeFromFullSegmentMethod,
|
16
|
+
} from '../utils/encryption-methods-util';
|
13
17
|
import type { Demuxer, DemuxerResult, KeyData } from '../types/demuxer';
|
14
18
|
import type { Remuxer } from '../types/remuxer';
|
15
19
|
import type { TransmuxerResult, ChunkMetadata } from '../types/transmuxer';
|
16
20
|
import type { HlsConfig } from '../config';
|
17
21
|
import type { DecryptData } from '../loader/level-key';
|
18
22
|
import type { PlaylistLevelType } from '../types/loader';
|
23
|
+
import type { TypeSupported } from '../utils/codecs';
|
19
24
|
import type { RationalTimestamp } from '../utils/timescale-conversion';
|
20
25
|
import { optionalSelf } from '../utils/global';
|
21
26
|
|
@@ -114,8 +119,10 @@ export default class Transmuxer {
|
|
114
119
|
} = transmuxConfig;
|
115
120
|
|
116
121
|
const keyData = getEncryptionType(uintData, decryptdata);
|
117
|
-
if (keyData && keyData.method
|
122
|
+
if (keyData && isFullSegmentEncryption(keyData.method)) {
|
118
123
|
const decrypter = this.getDecrypter();
|
124
|
+
const aesMode = getAesModeFromFullSegmentMethod(keyData.method);
|
125
|
+
|
119
126
|
// Software decryption is synchronous; webCrypto is not
|
120
127
|
if (decrypter.isSync()) {
|
121
128
|
// Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
|
@@ -124,6 +131,7 @@ export default class Transmuxer {
|
|
124
131
|
uintData,
|
125
132
|
keyData.key.buffer,
|
126
133
|
keyData.iv.buffer,
|
134
|
+
aesMode,
|
127
135
|
);
|
128
136
|
// For Low-Latency HLS Parts, decrypt in place, since part parsing is expected on push progress
|
129
137
|
const loadingParts = chunkMeta.part > -1;
|
@@ -137,7 +145,12 @@ export default class Transmuxer {
|
|
137
145
|
uintData = new Uint8Array(decryptedData);
|
138
146
|
} else {
|
139
147
|
this.decryptionPromise = decrypter
|
140
|
-
.webCryptoDecrypt(
|
148
|
+
.webCryptoDecrypt(
|
149
|
+
uintData,
|
150
|
+
keyData.key.buffer,
|
151
|
+
keyData.iv.buffer,
|
152
|
+
aesMode,
|
153
|
+
)
|
141
154
|
.then((decryptedData): TransmuxerResult => {
|
142
155
|
// Calling push here is important; if flush() is called while this is still resolving, this ensures that
|
143
156
|
// the decrypted data has been transmuxed
|
package/src/demux/tsdemuxer.ts
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
* highly optimized TS demuxer:
|
3
3
|
* parse PAT, PMT
|
4
4
|
* extract PES packet from audio and video PIDs
|
5
|
-
* extract AVC/H264 NAL units and AAC/ADTS samples from PES packet
|
5
|
+
* extract AVC/H264 (or HEVC/H265) NAL units and AAC/ADTS samples from PES packet
|
6
6
|
* trigger the remuxer upon parsing completion
|
7
7
|
* it also tries to workaround as best as it can audio codec switch (HE-AAC to AAC and vice versa), without having to restart the MediaSource.
|
8
8
|
* it also controls the remuxing process :
|
@@ -12,7 +12,9 @@
|
|
12
12
|
import * as ADTS from './audio/adts';
|
13
13
|
import * as MpegAudio from './audio/mpegaudio';
|
14
14
|
import * as AC3 from './audio/ac3-demuxer';
|
15
|
+
import BaseVideoParser from './video/base-video-parser';
|
15
16
|
import AvcVideoParser from './video/avc-video-parser';
|
17
|
+
import HevcVideoParser from './video/hevc-video-parser';
|
16
18
|
import SampleAesDecrypter from './sample-aes';
|
17
19
|
import { Events } from '../events';
|
18
20
|
import { appendUint8Array, RemuxerTrackIdConfig } from '../utils/mp4-tools';
|
@@ -20,20 +22,21 @@ import { logger } from '../utils/logger';
|
|
20
22
|
import { ErrorTypes, ErrorDetails } from '../errors';
|
21
23
|
import type { HlsConfig } from '../config';
|
22
24
|
import type { HlsEventEmitter } from '../events';
|
25
|
+
import type { TypeSupported } from '../utils/codecs';
|
23
26
|
import {
|
24
|
-
DemuxedVideoTrack,
|
25
|
-
DemuxedAudioTrack,
|
26
|
-
DemuxedTrack,
|
27
|
-
Demuxer,
|
28
|
-
DemuxerResult,
|
29
|
-
VideoSample,
|
30
|
-
DemuxedMetadataTrack,
|
31
|
-
DemuxedUserdataTrack,
|
32
|
-
ElementaryStreamData,
|
33
|
-
KeyData,
|
34
27
|
MetadataSchema,
|
28
|
+
type DemuxedVideoTrack,
|
29
|
+
type DemuxedAudioTrack,
|
30
|
+
type DemuxedTrack,
|
31
|
+
type Demuxer,
|
32
|
+
type DemuxerResult,
|
33
|
+
type VideoSample,
|
34
|
+
type DemuxedMetadataTrack,
|
35
|
+
type DemuxedUserdataTrack,
|
36
|
+
type ElementaryStreamData,
|
37
|
+
type KeyData,
|
35
38
|
} from '../types/demuxer';
|
36
|
-
import { AudioFrame } from '../types/demuxer';
|
39
|
+
import type { AudioFrame } from '../types/demuxer';
|
37
40
|
|
38
41
|
export type ParsedTimestamp = {
|
39
42
|
pts?: number;
|
@@ -48,12 +51,6 @@ export type PES = ParsedTimestamp & {
|
|
48
51
|
export type ParsedVideoSample = ParsedTimestamp &
|
49
52
|
Omit<VideoSample, 'pts' | 'dts'>;
|
50
53
|
|
51
|
-
export interface TypeSupported {
|
52
|
-
mpeg: boolean;
|
53
|
-
mp3: boolean;
|
54
|
-
ac3: boolean;
|
55
|
-
}
|
56
|
-
|
57
54
|
const PACKET_LENGTH = 188;
|
58
55
|
|
59
56
|
class TSDemuxer implements Demuxer {
|
@@ -74,7 +71,7 @@ class TSDemuxer implements Demuxer {
|
|
74
71
|
private _txtTrack?: DemuxedUserdataTrack;
|
75
72
|
private aacOverFlow: AudioFrame | null = null;
|
76
73
|
private remainderData: Uint8Array | null = null;
|
77
|
-
private videoParser:
|
74
|
+
private videoParser: BaseVideoParser | null;
|
78
75
|
|
79
76
|
constructor(
|
80
77
|
observer: HlsEventEmitter,
|
@@ -84,7 +81,7 @@ class TSDemuxer implements Demuxer {
|
|
84
81
|
this.observer = observer;
|
85
82
|
this.config = config;
|
86
83
|
this.typeSupported = typeSupported;
|
87
|
-
this.videoParser =
|
84
|
+
this.videoParser = null;
|
88
85
|
}
|
89
86
|
|
90
87
|
static probe(data: Uint8Array) {
|
@@ -292,13 +289,27 @@ class TSDemuxer implements Demuxer {
|
|
292
289
|
case videoPid:
|
293
290
|
if (stt) {
|
294
291
|
if (videoData && (pes = parsePES(videoData))) {
|
295
|
-
this.videoParser
|
296
|
-
videoTrack
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
292
|
+
if (this.videoParser === null) {
|
293
|
+
switch (videoTrack.segmentCodec) {
|
294
|
+
case 'avc':
|
295
|
+
this.videoParser = new AvcVideoParser();
|
296
|
+
break;
|
297
|
+
case 'hevc':
|
298
|
+
if (__USE_M2TS_ADVANCED_CODECS__) {
|
299
|
+
this.videoParser = new HevcVideoParser();
|
300
|
+
}
|
301
|
+
break;
|
302
|
+
}
|
303
|
+
}
|
304
|
+
if (this.videoParser !== null) {
|
305
|
+
this.videoParser.parsePES(
|
306
|
+
videoTrack,
|
307
|
+
textTrack,
|
308
|
+
pes,
|
309
|
+
false,
|
310
|
+
this._duration,
|
311
|
+
);
|
312
|
+
}
|
302
313
|
}
|
303
314
|
|
304
315
|
videoData = { data: [], size: 0 };
|
@@ -467,14 +478,28 @@ class TSDemuxer implements Demuxer {
|
|
467
478
|
// try to parse last PES packets
|
468
479
|
let pes: PES | null;
|
469
480
|
if (videoData && (pes = parsePES(videoData))) {
|
470
|
-
this.videoParser
|
471
|
-
videoTrack
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
481
|
+
if (this.videoParser === null) {
|
482
|
+
switch (videoTrack.segmentCodec) {
|
483
|
+
case 'avc':
|
484
|
+
this.videoParser = new AvcVideoParser();
|
485
|
+
break;
|
486
|
+
case 'hevc':
|
487
|
+
if (__USE_M2TS_ADVANCED_CODECS__) {
|
488
|
+
this.videoParser = new HevcVideoParser();
|
489
|
+
}
|
490
|
+
break;
|
491
|
+
}
|
492
|
+
}
|
493
|
+
if (this.videoParser !== null) {
|
494
|
+
this.videoParser.parsePES(
|
495
|
+
videoTrack as DemuxedVideoTrack,
|
496
|
+
textTrack as DemuxedUserdataTrack,
|
497
|
+
pes,
|
498
|
+
true,
|
499
|
+
this._duration,
|
500
|
+
);
|
501
|
+
videoTrack.pesData = null;
|
502
|
+
}
|
478
503
|
} else {
|
479
504
|
// either avcData null or PES truncated, keep it for next frag parsing
|
480
505
|
videoTrack.pesData = videoData;
|
@@ -864,9 +889,21 @@ function parsePMT(
|
|
864
889
|
emitParsingError(observer, new Error('Unsupported EC-3 in M2TS found'));
|
865
890
|
return result;
|
866
891
|
|
867
|
-
case 0x24:
|
868
|
-
|
869
|
-
|
892
|
+
case 0x24: // ITU-T Rec. H.265 and ISO/IEC 23008-2 (HEVC)
|
893
|
+
if (__USE_M2TS_ADVANCED_CODECS__) {
|
894
|
+
if (result.videoPid === -1) {
|
895
|
+
result.videoPid = pid;
|
896
|
+
result.segmentVideoCodec = 'hevc';
|
897
|
+
logger.log('HEVC in M2TS found');
|
898
|
+
}
|
899
|
+
} else {
|
900
|
+
emitParsingError(
|
901
|
+
observer,
|
902
|
+
new Error('Unsupported HEVC in M2TS found'),
|
903
|
+
);
|
904
|
+
return result;
|
905
|
+
}
|
906
|
+
break;
|
870
907
|
|
871
908
|
default:
|
872
909
|
// logger.log('unknown stream type:' + data[offset]);
|