jmuxer 2.0.7 → 2.1.1
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 +29 -36
- package/dist/jmuxer.js +2770 -2020
- package/dist/jmuxer.min.js +1 -1
- package/eslint.config.mjs +21 -0
- package/package.json +20 -28
- package/rollup.config.js +13 -4
- package/src/controller/remux.js +63 -46
- package/src/jmuxer.js +40 -145
- package/src/parsers/aac.js +11 -38
- package/src/parsers/h264.js +106 -99
- package/src/parsers/h265.js +489 -0
- package/src/remuxer/aac.js +63 -7
- package/src/remuxer/base.js +2 -1
- package/src/remuxer/h264.js +176 -16
- package/src/remuxer/h265.js +295 -0
- package/src/util/debug.js +3 -5
- package/src/util/event.js +2 -2
- package/src/util/mp4-generator.js +124 -9
- package/src/util/utils.js +20 -0
- package/.idea/codeStyles/Project.xml +0 -13
- package/.idea/codeStyles/codeStyleConfig.xml +0 -5
- package/.idea/inspectionProfiles/Project_Default.xml +0 -6
- package/.idea/jmuxer.iml +0 -9
- package/.idea/misc.xml +0 -6
- package/.idea/modules.xml +0 -8
- package/.idea/vcs.xml +0 -6
- package/karma.conf.js +0 -77
- package/loader-thumb.jpg +0 -0
- package/packet-format.png +0 -0
- package/src/util/nalu.js +0 -72
- package/test/event.js +0 -30
- package/test/parser.js +0 -35
- package/test/utils.js +0 -19
package/src/remuxer/h264.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import * as debug from '../util/debug';
|
|
2
|
-
import { H264Parser } from '../parsers/h264.js';
|
|
2
|
+
import { H264Parser, NALU264 } from '../parsers/h264.js';
|
|
3
3
|
import { BaseRemuxer } from './base.js';
|
|
4
|
+
import { appendByteArray } from '../util/utils.js';
|
|
4
5
|
|
|
5
6
|
export class H264Remuxer extends BaseRemuxer {
|
|
6
7
|
|
|
7
|
-
constructor(timescale) {
|
|
8
|
-
super();
|
|
8
|
+
constructor(timescale, duration, frameDuration) {
|
|
9
|
+
super('H264Remuxer');
|
|
10
|
+
this.frameDuration = frameDuration;
|
|
9
11
|
this.readyToDecode = false;
|
|
10
12
|
this.nextDts = 0;
|
|
11
13
|
this.dts = 0;
|
|
@@ -20,11 +22,13 @@ export class H264Remuxer extends BaseRemuxer {
|
|
|
20
22
|
width: 0,
|
|
21
23
|
height: 0,
|
|
22
24
|
timescale: timescale,
|
|
23
|
-
duration:
|
|
25
|
+
duration: duration,
|
|
24
26
|
samples: [],
|
|
25
27
|
};
|
|
26
28
|
this.samples = [];
|
|
27
|
-
this.
|
|
29
|
+
this.remainingData = new Uint8Array();
|
|
30
|
+
this.kfCounter = 0;
|
|
31
|
+
this.pendingUnits = {};
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
resetTrack() {
|
|
@@ -33,22 +37,119 @@ export class H264Remuxer extends BaseRemuxer {
|
|
|
33
37
|
this.mp4track.pps = '';
|
|
34
38
|
this.nextDts = 0;
|
|
35
39
|
this.dts = 0;
|
|
40
|
+
this.remainingData = new Uint8Array();
|
|
41
|
+
this.kfCounter = 0;
|
|
42
|
+
this.pendingUnits = {};
|
|
36
43
|
}
|
|
37
44
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
feed(data, duration, compositionTimeOffset, isLastFrameComplete = false) {
|
|
46
|
+
let slices = [];
|
|
47
|
+
let left;
|
|
48
|
+
data = appendByteArray(this.remainingData, data);
|
|
49
|
+
[slices, left] = H264Parser.extractNALu(data);
|
|
50
|
+
if (left) {
|
|
51
|
+
if (isLastFrameComplete) {
|
|
52
|
+
slices.push(left);
|
|
53
|
+
this.remainingData = new Uint8Array();
|
|
54
|
+
} else {
|
|
55
|
+
this.remainingData = left;
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
this.remainingData = new Uint8Array();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (slices.length > 0) {
|
|
62
|
+
this.remux(this.getVideoFrames(slices, duration, compositionTimeOffset));
|
|
63
|
+
return true;
|
|
64
|
+
} else {
|
|
65
|
+
debug.log('Failed to extract any NAL units from video data:', left);
|
|
66
|
+
this.dispatch('outOfData');
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
getVideoFrames(nalus, duration, compositionTimeOffset) {
|
|
72
|
+
let units = [],
|
|
73
|
+
frames = [],
|
|
74
|
+
fd = 0, // frame duration
|
|
75
|
+
tt = 0, // time ticks (remainder adjustment counter)
|
|
76
|
+
keyFrame = false,
|
|
77
|
+
vcl = false; // Video Coding Layer data (i.e., a "real" frame)
|
|
78
|
+
if (this.pendingUnits.units) {
|
|
79
|
+
units = this.pendingUnits.units;
|
|
80
|
+
vcl = this.pendingUnits.vcl;
|
|
81
|
+
keyFrame = this.pendingUnits.keyFrame;
|
|
82
|
+
this.pendingUnits = {};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
for (let nalu of nalus) {
|
|
86
|
+
let unit = new NALU264(nalu);
|
|
87
|
+
|
|
88
|
+
if (!this.parseNAL(unit)) continue;
|
|
89
|
+
|
|
90
|
+
// frame boundary detection
|
|
91
|
+
if (units.length && vcl && (unit.isFirstSlice || !unit.isVCL)) {
|
|
92
|
+
frames.push({
|
|
93
|
+
units,
|
|
94
|
+
keyFrame
|
|
95
|
+
});
|
|
96
|
+
units = [];
|
|
97
|
+
keyFrame = false;
|
|
98
|
+
vcl = false;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
units.push(unit);
|
|
102
|
+
keyFrame = keyFrame || unit.isKeyframe;
|
|
103
|
+
vcl = vcl || unit.isVCL;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (units.length) {
|
|
107
|
+
// lets keep indecisive nalus as pending in case of fixed fps
|
|
108
|
+
if (!duration) {
|
|
109
|
+
this.pendingUnits = {
|
|
110
|
+
units,
|
|
111
|
+
keyFrame,
|
|
112
|
+
vcl
|
|
113
|
+
};
|
|
114
|
+
} else if (vcl) {
|
|
115
|
+
frames.push({
|
|
116
|
+
units,
|
|
117
|
+
keyFrame
|
|
118
|
+
});
|
|
119
|
+
} else {
|
|
120
|
+
let last = frames.length - 1;
|
|
121
|
+
if (last >= 0) {
|
|
122
|
+
frames[last].units = frames[last].units.concat(units);
|
|
46
123
|
}
|
|
47
124
|
}
|
|
48
|
-
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
fd = duration ? duration / frames.length | 0 : this.frameDuration;
|
|
128
|
+
tt = duration ? (duration - (fd * frames.length)) : 0;
|
|
129
|
+
|
|
130
|
+
frames.map((frame) => {
|
|
131
|
+
frame.duration = fd;
|
|
132
|
+
frame.compositionTimeOffset = compositionTimeOffset;
|
|
133
|
+
if (tt > 0) {
|
|
134
|
+
frame.duration++;
|
|
135
|
+
tt--;
|
|
136
|
+
}
|
|
137
|
+
this.kfCounter++;
|
|
138
|
+
if (frame.keyFrame) {
|
|
139
|
+
this.dispatch('keyframePosition', (this.kfCounter * fd) / 1000);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
debug.log(`jmuxer: No. of H264 frames of the last chunk: ${frames.length}`);
|
|
143
|
+
return frames;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
remux(frames) {
|
|
147
|
+
for (let frame of frames) {
|
|
148
|
+
let size = frame.units.reduce((acc, cur) => acc + cur.getSize(), 0);
|
|
149
|
+
if (frame.units.length > 0 && this.readyToDecode) {
|
|
49
150
|
this.mp4track.len += size;
|
|
50
151
|
this.samples.push({
|
|
51
|
-
units: units,
|
|
152
|
+
units: frame.units,
|
|
52
153
|
size: size,
|
|
53
154
|
keyFrame: frame.keyFrame,
|
|
54
155
|
duration: frame.duration,
|
|
@@ -67,7 +168,6 @@ export class H264Remuxer extends BaseRemuxer {
|
|
|
67
168
|
let samples = this.mp4track.samples;
|
|
68
169
|
let mp4Sample,
|
|
69
170
|
duration;
|
|
70
|
-
|
|
71
171
|
this.dts = this.nextDts;
|
|
72
172
|
while (this.samples.length) {
|
|
73
173
|
let sample = this.samples.shift(),
|
|
@@ -105,4 +205,64 @@ export class H264Remuxer extends BaseRemuxer {
|
|
|
105
205
|
|
|
106
206
|
return new Uint8Array(payload.buffer, 0, this.mp4track.len);
|
|
107
207
|
}
|
|
208
|
+
|
|
209
|
+
parseSPS(sps) {
|
|
210
|
+
var config = H264Parser.readSPS(new Uint8Array(sps));
|
|
211
|
+
|
|
212
|
+
this.mp4track.fps = config.fps || this.mp4track.fps;
|
|
213
|
+
this.mp4track.width = config.width;
|
|
214
|
+
this.mp4track.height = config.height;
|
|
215
|
+
this.mp4track.sps = [new Uint8Array(sps)];
|
|
216
|
+
this.mp4track.codec = 'avc1.';
|
|
217
|
+
|
|
218
|
+
let codecarray = new DataView(sps.buffer, sps.byteOffset + 1, 4);
|
|
219
|
+
for (let i = 0; i < 3; ++i) {
|
|
220
|
+
var h = codecarray.getUint8(i).toString(16);
|
|
221
|
+
if (h.length < 2) {
|
|
222
|
+
h = '0' + h;
|
|
223
|
+
}
|
|
224
|
+
this.mp4track.codec += h;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
parsePPS(pps) {
|
|
229
|
+
this.mp4track.pps = [new Uint8Array(pps)];
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
parseNAL(unit) {
|
|
233
|
+
if (!unit) return false;
|
|
234
|
+
|
|
235
|
+
if (unit.isVCL) {
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
let push = false;
|
|
240
|
+
switch (unit.type()) {
|
|
241
|
+
case NALU264.PPS:
|
|
242
|
+
if (!this.mp4track.pps) {
|
|
243
|
+
this.parsePPS(unit.getPayload());
|
|
244
|
+
}
|
|
245
|
+
push = true;
|
|
246
|
+
break;
|
|
247
|
+
case NALU264.SPS:
|
|
248
|
+
if (!this.mp4track.sps) {
|
|
249
|
+
this.parseSPS(unit.getPayload());
|
|
250
|
+
}
|
|
251
|
+
push = true;
|
|
252
|
+
break;
|
|
253
|
+
case NALU264.AUD:
|
|
254
|
+
debug.log('AUD - ignoing');
|
|
255
|
+
break;
|
|
256
|
+
case NALU264.SEI:
|
|
257
|
+
debug.log('SEI - ignoing');
|
|
258
|
+
break;
|
|
259
|
+
default:
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (!this.readyToDecode && this.mp4track.pps && this.mp4track.sps) {
|
|
263
|
+
this.readyToDecode = true;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return push;
|
|
267
|
+
}
|
|
108
268
|
}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import * as debug from '../util/debug';
|
|
2
|
+
import { H265Parser, NALU265 } from '../parsers/h265.js';
|
|
3
|
+
import { BaseRemuxer } from './base.js';
|
|
4
|
+
import { appendByteArray, reverseBits, removeTrailingDotZero } from '../util/utils.js';
|
|
5
|
+
|
|
6
|
+
export class H265Remuxer extends BaseRemuxer {
|
|
7
|
+
|
|
8
|
+
constructor(timescale, duration, frameDuration) {
|
|
9
|
+
super('H264Remuxer');
|
|
10
|
+
this.frameDuration = frameDuration;
|
|
11
|
+
this.readyToDecode = false;
|
|
12
|
+
this.nextDts = 0;
|
|
13
|
+
this.dts = 0;
|
|
14
|
+
this.mp4track = {
|
|
15
|
+
id: BaseRemuxer.getTrackID(),
|
|
16
|
+
type: 'video',
|
|
17
|
+
len: 0,
|
|
18
|
+
fragmented: true,
|
|
19
|
+
vps: '',
|
|
20
|
+
sps: '',
|
|
21
|
+
pps: '',
|
|
22
|
+
hvcC: {},
|
|
23
|
+
fps: 30,
|
|
24
|
+
width: 0,
|
|
25
|
+
height: 0,
|
|
26
|
+
timescale: timescale,
|
|
27
|
+
duration: duration,
|
|
28
|
+
samples: [],
|
|
29
|
+
};
|
|
30
|
+
this.samples = [];
|
|
31
|
+
this.remainingData = new Uint8Array();
|
|
32
|
+
this.kfCounter = 0;
|
|
33
|
+
this.pendingUnits = {};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
resetTrack() {
|
|
37
|
+
this.readyToDecode = false;
|
|
38
|
+
this.mp4track.vps = '';
|
|
39
|
+
this.mp4track.sps = '';
|
|
40
|
+
this.mp4track.pps = '';
|
|
41
|
+
this.mp4track.hvcC = {};
|
|
42
|
+
this.nextDts = 0;
|
|
43
|
+
this.dts = 0;
|
|
44
|
+
this.remainingData = new Uint8Array();
|
|
45
|
+
this.kfCounter = 0;
|
|
46
|
+
this.pendingUnits = {};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
feed(data, duration, compositionTimeOffset, isLastFrameComplete = false) {
|
|
50
|
+
let slices = [];
|
|
51
|
+
let left;
|
|
52
|
+
data = appendByteArray(this.remainingData, data);
|
|
53
|
+
[slices, left] = H265Parser.extractNALu(data);
|
|
54
|
+
if (left) {
|
|
55
|
+
if (isLastFrameComplete) {
|
|
56
|
+
slices.push(left);
|
|
57
|
+
this.remainingData = new Uint8Array();
|
|
58
|
+
} else {
|
|
59
|
+
this.remainingData = left;
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
this.remainingData = new Uint8Array();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (slices.length > 0) {
|
|
66
|
+
this.remux(this.getVideoFrames(slices, duration, compositionTimeOffset));
|
|
67
|
+
return true;
|
|
68
|
+
} else {
|
|
69
|
+
debug.log('Failed to extract any NAL units from video data:', left);
|
|
70
|
+
this.dispatch('outOfData');
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
getVideoFrames(nalus, duration, compositionTimeOffset) {
|
|
76
|
+
let units = [],
|
|
77
|
+
frames = [],
|
|
78
|
+
fd = 0,
|
|
79
|
+
tt = 0,
|
|
80
|
+
keyFrame = false,
|
|
81
|
+
vcl = false;
|
|
82
|
+
|
|
83
|
+
if (this.pendingUnits.units) {
|
|
84
|
+
units = this.pendingUnits.units;
|
|
85
|
+
vcl = this.pendingUnits.vcl;
|
|
86
|
+
keyFrame = this.pendingUnits.keyFrame;
|
|
87
|
+
this.pendingUnits = {};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
for (let nalu of nalus) {
|
|
91
|
+
let unit = new NALU265(nalu);
|
|
92
|
+
|
|
93
|
+
if (!this.parseNAL(unit)) continue;
|
|
94
|
+
|
|
95
|
+
// frame boundary detection
|
|
96
|
+
if (units.length && vcl && (unit.isFirstSlice || !unit.isVCL)) {
|
|
97
|
+
frames.push({
|
|
98
|
+
units,
|
|
99
|
+
keyFrame
|
|
100
|
+
});
|
|
101
|
+
units = [];
|
|
102
|
+
keyFrame = false;
|
|
103
|
+
vcl = false;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
units.push(unit);
|
|
107
|
+
keyFrame = keyFrame || unit.isKeyframe;
|
|
108
|
+
vcl = vcl || unit.isVCL;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (units.length) {
|
|
112
|
+
if (!duration) {
|
|
113
|
+
this.pendingUnits = {
|
|
114
|
+
units,
|
|
115
|
+
keyFrame,
|
|
116
|
+
vcl
|
|
117
|
+
};
|
|
118
|
+
} else if (vcl) {
|
|
119
|
+
frames.push({
|
|
120
|
+
units,
|
|
121
|
+
keyFrame
|
|
122
|
+
});
|
|
123
|
+
} else {
|
|
124
|
+
let last = frames.length - 1;
|
|
125
|
+
if (last >= 0) {
|
|
126
|
+
frames[last].units = frames[last].units.concat(units);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
fd = duration ? (duration / frames.length) | 0 : this.frameDuration;
|
|
132
|
+
tt = duration ? duration - fd * frames.length : 0;
|
|
133
|
+
|
|
134
|
+
frames.map((frame) => {
|
|
135
|
+
frame.duration = fd;
|
|
136
|
+
frame.compositionTimeOffset = compositionTimeOffset;
|
|
137
|
+
if (tt > 0) {
|
|
138
|
+
frame.duration++;
|
|
139
|
+
tt--;
|
|
140
|
+
}
|
|
141
|
+
this.kfCounter++;
|
|
142
|
+
if (frame.keyFrame) {
|
|
143
|
+
this.dispatch('keyframePosition', (this.kfCounter * fd) / 1000);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
debug.log(`jmuxer: No. of H265 frames of the last chunk: ${frames.length}`);
|
|
148
|
+
return frames;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
remux(frames) {
|
|
152
|
+
for (let frame of frames) {
|
|
153
|
+
let size = frame.units.reduce((acc, cur) => acc + cur.getSize(), 0);
|
|
154
|
+
if (frame.units.length > 0 && this.readyToDecode) {
|
|
155
|
+
this.mp4track.len += size;
|
|
156
|
+
this.samples.push({
|
|
157
|
+
units: frame.units,
|
|
158
|
+
size: size,
|
|
159
|
+
keyFrame: frame.keyFrame,
|
|
160
|
+
duration: frame.duration,
|
|
161
|
+
compositionTimeOffset: frame.compositionTimeOffset
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
getPayload() {
|
|
168
|
+
if (!this.isReady()) {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
let payload = new Uint8Array(this.mp4track.len);
|
|
172
|
+
let offset = 0;
|
|
173
|
+
let samples = this.mp4track.samples;
|
|
174
|
+
let mp4Sample,
|
|
175
|
+
duration;
|
|
176
|
+
this.dts = this.nextDts;
|
|
177
|
+
while (this.samples.length) {
|
|
178
|
+
let sample = this.samples.shift(),
|
|
179
|
+
units = sample.units;
|
|
180
|
+
|
|
181
|
+
duration = sample.duration;
|
|
182
|
+
if (duration <= 0) {
|
|
183
|
+
debug.log(`remuxer: invalid sample duration at DTS: ${this.nextDts} :${duration}`);
|
|
184
|
+
this.mp4track.len -= sample.size;
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
this.nextDts += duration;
|
|
188
|
+
mp4Sample = {
|
|
189
|
+
size: sample.size,
|
|
190
|
+
duration: duration,
|
|
191
|
+
cts: sample.compositionTimeOffset || 0,
|
|
192
|
+
flags: {
|
|
193
|
+
isLeading: 0,
|
|
194
|
+
isDependedOn: 0,
|
|
195
|
+
hasRedundancy: 0,
|
|
196
|
+
degradPrio: 0,
|
|
197
|
+
isNonSync: sample.keyFrame ? 0 : 1,
|
|
198
|
+
dependsOn: sample.keyFrame ? 2 : 1,
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
for (const unit of units) {
|
|
203
|
+
payload.set(unit.getData(), offset);
|
|
204
|
+
offset += unit.getSize();
|
|
205
|
+
}
|
|
206
|
+
samples.push(mp4Sample);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (!samples.length) return null;
|
|
210
|
+
|
|
211
|
+
return new Uint8Array(payload.buffer, 0, this.mp4track.len);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
parseSPS(sps) {
|
|
215
|
+
this.mp4track.sps = [new Uint8Array(sps)];
|
|
216
|
+
|
|
217
|
+
sps = H265Parser.removeEmulationPreventionBytes(sps);
|
|
218
|
+
const config = H265Parser.readSPS(new Uint8Array(sps));
|
|
219
|
+
|
|
220
|
+
this.mp4track.fps = config.fps || this.mp4track.fps;
|
|
221
|
+
this.mp4track.width = config.width;
|
|
222
|
+
this.mp4track.height = config.height;
|
|
223
|
+
|
|
224
|
+
this.mp4track.codec = 'hvc1'
|
|
225
|
+
+ '.' + (config.profile_space ? String.fromCharCode(64 + config.profile_space) : '') // Map [0,1,2,3] to ['','A','B','C']
|
|
226
|
+
+ config.profile_idc
|
|
227
|
+
+ '.' + reverseBits(config.profile_compatibility_flags).toString(16)
|
|
228
|
+
+ '.' + (config.tier_flag ? 'H' : 'L') + config.level_idc
|
|
229
|
+
+ '.' + removeTrailingDotZero(config.constraint_indicator_flags.map(function (b) { return b.toString(16); }).join('.').toUpperCase());
|
|
230
|
+
|
|
231
|
+
this.mp4track.hvcC = {
|
|
232
|
+
profile_space: config.profile_space,
|
|
233
|
+
tier_flag: config.tier_flag,
|
|
234
|
+
profile_idc: config.profile_idc,
|
|
235
|
+
profile_compatibility_flags: config.profile_compatibility_flags,
|
|
236
|
+
constraint_indicator_flags: config.constraint_indicator_flags,
|
|
237
|
+
level_idc: config.level_idc,
|
|
238
|
+
chroma_format_idc: config.chroma_format_idc
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
parsePPS(pps) {
|
|
243
|
+
this.mp4track.pps = [pps];
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
parseVPS(vps) {
|
|
247
|
+
this.mp4track.vps = [vps];
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
parseNAL(unit) {
|
|
251
|
+
if (!unit) return false;
|
|
252
|
+
|
|
253
|
+
if (unit.isVCL) {
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
let push = false;
|
|
258
|
+
switch (unit.type()) {
|
|
259
|
+
case NALU265.VPS:
|
|
260
|
+
if (!this.mp4track.vps) {
|
|
261
|
+
this.parseVPS(unit.getPayload());
|
|
262
|
+
}
|
|
263
|
+
push = true;
|
|
264
|
+
break;
|
|
265
|
+
|
|
266
|
+
case NALU265.SPS:
|
|
267
|
+
if (!this.mp4track.sps) {
|
|
268
|
+
this.parseSPS(unit.getPayload());
|
|
269
|
+
}
|
|
270
|
+
push = true;
|
|
271
|
+
break;
|
|
272
|
+
|
|
273
|
+
case NALU265.PPS:
|
|
274
|
+
if (!this.mp4track.pps) {
|
|
275
|
+
this.parsePPS(unit.getPayload());
|
|
276
|
+
}
|
|
277
|
+
push = true;
|
|
278
|
+
break;
|
|
279
|
+
case NALU265.AUD:
|
|
280
|
+
debug.log('AUD - ignoing');
|
|
281
|
+
break;
|
|
282
|
+
case NALU265.SEI:
|
|
283
|
+
case NALU265.SEI2:
|
|
284
|
+
debug.log('SEI - ignoing');
|
|
285
|
+
break;
|
|
286
|
+
default:
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (!this.readyToDecode && this.mp4track.vps && this.mp4track.sps && this.mp4track.pps) {
|
|
290
|
+
this.readyToDecode = true;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return push;
|
|
294
|
+
}
|
|
295
|
+
}
|
package/src/util/debug.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
let logger;
|
|
2
2
|
let errorLogger;
|
|
3
3
|
|
|
4
|
-
export function setLogger() {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
errorLogger = console.error;
|
|
8
|
-
/*eslint-enable */
|
|
4
|
+
export function setLogger(log, err) {
|
|
5
|
+
logger = log;
|
|
6
|
+
errorLogger = err;
|
|
9
7
|
}
|
|
10
8
|
|
|
11
9
|
export function isEnable() {
|
package/src/util/event.js
CHANGED
|
@@ -27,10 +27,10 @@ export default class Event {
|
|
|
27
27
|
this.listener = {};
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
dispatch(event, data) {
|
|
30
|
+
dispatch(event, ...data) {
|
|
31
31
|
if (this.listener[event]) {
|
|
32
32
|
this.listener[event].map((each) => {
|
|
33
|
-
each.apply(null,
|
|
33
|
+
each.apply(null, data);
|
|
34
34
|
});
|
|
35
35
|
return true;
|
|
36
36
|
}
|