xgplayer-mp4 1.2.4 → 2.0.2
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/browser/index.js +1 -1
- package/browser/index.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
- package/src/constants.js +14 -0
- package/src/fmp4/buffer.js +6 -0
- package/src/fmp4/mp4.js +181 -84
- package/src/gap_jump.js +151 -0
- package/src/index.js +550 -315
- package/src/media/mse.js +77 -22
- package/src/media/task.js +68 -17
- package/src/mp4.js +284 -268
- package/src/parse/box/MP4DecConfigDescrTag.js +3 -0
- package/src/parse/box/MP4DecSpecificDescrTag.js +4 -0
- package/src/parse/box/avcC.js +4 -1
- package/src/parse/box/elst.js +0 -13
- package/src/parse/box/esds.js +9 -4
- package/src/parse/box/frma.js +10 -0
- package/src/parse/box/golomb.js +88 -0
- package/src/parse/box/hvc1.js +30 -0
- package/src/parse/box/hvcC.js +55 -0
- package/src/parse/box/pasp.js +2 -3
- package/src/parse/box/schm.js +18 -0
- package/src/parse/box/sps.js +286 -0
- package/src/parse/box/stsz.js +6 -1
- package/src/parse/box/tfhd.js +43 -0
- package/src/parse/box.js +5 -1
- package/src/parse/stream.js +4 -0
- package/src/util/getHeaders.js +18 -0
- package/src/util/index.js +138 -20
- package/src/util/intervalTimer.js +36 -0
- package/src/util/isSupport.js +20 -0
- package/src/util/proxyPromise.js +27 -0
- package/src/util/timer.js +46 -0
- package/src/util/xhr.js +46 -0
- package/version.json +1 -1
- package/webpack.config.js +45 -39
- package/src/util/download.js +0 -13
- package/src/write/box/MP4DecConfigDescrTag.js +0 -21
- package/src/write/box/MP4DecSpecificDescrTag.js +0 -19
- package/src/write/box/MP4ESDescrTag.js +0 -19
- package/src/write/box/SLConfigDescriptor.js +0 -16
- package/src/write/box/avc1.js +0 -33
- package/src/write/box/avcC.js +0 -32
- package/src/write/box/btrt.js +0 -14
- package/src/write/box/co64.js +0 -17
- package/src/write/box/ctts.js +0 -19
- package/src/write/box/dref.js +0 -25
- package/src/write/box/elst.js +0 -27
- package/src/write/box/esds.js +0 -11
- package/src/write/box/ftyp.js +0 -17
- package/src/write/box/hdlr.js +0 -15
- package/src/write/box/iods.js +0 -14
- package/src/write/box/mdat.js +0 -5
- package/src/write/box/mdhd.js +0 -27
- package/src/write/box/mehd.js +0 -12
- package/src/write/box/mfhd.js +0 -12
- package/src/write/box/mfro.js +0 -14
- package/src/write/box/mp4a.js +0 -26
- package/src/write/box/mvhd.js +0 -34
- package/src/write/box/pasp.js +0 -10
- package/src/write/box/smhd.js +0 -17
- package/src/write/box/stco.js +0 -17
- package/src/write/box/stsc.js +0 -19
- package/src/write/box/stsd.js +0 -23
- package/src/write/box/stss.js +0 -17
- package/src/write/box/stsz.js +0 -18
- package/src/write/box/stts.js +0 -18
- package/src/write/box/tfdt.js +0 -16
- package/src/write/box/tfhd.js +0 -18
- package/src/write/box/tfra.js +0 -29
- package/src/write/box/tkhd.js +0 -44
- package/src/write/box/trex.js +0 -16
- package/src/write/box/trun.js +0 -40
- package/src/write/box/udta.js +0 -5
- package/src/write/box/url.js +0 -16
- package/src/write/box/vmhd.js +0 -19
- package/src/write/box/wide.js +0 -12
- package/src/write/box.js +0 -37
- package/src/write/buffer.js +0 -12
- package/src/write/index.js +0 -33
- package/src/write/stream.js +0 -99
- package/webpack.config.test.js +0 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xgplayer-mp4",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "xgplayer plugin for mp4 transform to fmp4",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"deepmerge": "^2.0.1",
|
|
37
37
|
"event-emitter": "^0.3.5"
|
|
38
38
|
},
|
|
39
|
-
"
|
|
40
|
-
"xgplayer": "^0.
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"xgplayer": "^2.0.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"babel-core": "^6.26.3",
|
|
@@ -48,12 +48,13 @@
|
|
|
48
48
|
"chai": "^4.1.2",
|
|
49
49
|
"json-loader": "^0.5.7",
|
|
50
50
|
"karma": "^3.0.0",
|
|
51
|
+
"karma-chrome-launcher": "^2.2.0",
|
|
51
52
|
"karma-mocha": "^1.3.0",
|
|
52
53
|
"karma-sourcemap-loader": "^0.3.7",
|
|
53
54
|
"karma-spec-reporter": "0.0.32",
|
|
54
|
-
"karma-chrome-launcher": "^2.2.0",
|
|
55
55
|
"karma-webpack": "^4.0.0-rc.1",
|
|
56
56
|
"mocha": "^5.2.0",
|
|
57
|
+
"uglifyjs-webpack-plugin": "^2.2.0",
|
|
57
58
|
"webpack": "^4.11.0",
|
|
58
59
|
"webpack-cli": "^3.0.2"
|
|
59
60
|
}
|
package/src/constants.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const CUSTOM_EVENTS = {
|
|
2
|
+
"MEDIA_EXPIRED":'MEDIA_EXPIRED',
|
|
3
|
+
"INIT_FAIL":"INIT_FAIL",
|
|
4
|
+
"PARSE_ERROR":"PARSE_ERROR",
|
|
5
|
+
"BUFFERED_RESET": "BUFFERED_RESET"
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const TASK_ERROR = 'TASK_ERROR';
|
|
9
|
+
|
|
10
|
+
export const TASK_ERROR_TYPES = {
|
|
11
|
+
ERROR:"ERROR",
|
|
12
|
+
CODE_ERROR:"CODE_ERROR",
|
|
13
|
+
CANCEL:"CANCEL",
|
|
14
|
+
}
|
package/src/fmp4/buffer.js
CHANGED
package/src/fmp4/mp4.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Buffer from './buffer'
|
|
2
2
|
const UINT32_MAX = Math.pow(2, 32) - 1
|
|
3
|
+
|
|
3
4
|
class FMP4 {
|
|
4
5
|
static type (name) {
|
|
5
6
|
return new Uint8Array([name.charCodeAt(0), name.charCodeAt(1), name.charCodeAt(2), name.charCodeAt(3)])
|
|
@@ -18,55 +19,46 @@ class FMP4 {
|
|
|
18
19
|
static ftyp () {
|
|
19
20
|
let buffer = new Buffer()
|
|
20
21
|
buffer.write(FMP4.size(24), FMP4.type('ftyp'), new Uint8Array([
|
|
21
|
-
0x69, 0x73, 0x6F,
|
|
22
|
+
0x69, 0x73, 0x6F, 0x36, // isom,
|
|
22
23
|
0x0, 0x0, 0x00, 0x01, // minor_version: 0x01
|
|
23
|
-
0x69, 0x73, 0x6F,
|
|
24
|
-
|
|
24
|
+
0x69, 0x73, 0x6F, 0x36, // isom
|
|
25
|
+
0x64, 0x61, 0x73, 0x68 // avc1
|
|
25
26
|
]))
|
|
26
27
|
return buffer.buffer
|
|
27
28
|
}
|
|
28
29
|
static moov (data) {
|
|
29
30
|
let buffer = new Buffer(); let size = 8
|
|
30
31
|
let mvhd = FMP4.mvhd(data.duration, data.timeScale)
|
|
32
|
+
let mvex = FMP4.mvex(data.duration, data.timeScale)
|
|
31
33
|
let trak1 = FMP4.videoTrak(data)
|
|
32
|
-
let trak2
|
|
33
|
-
if(
|
|
34
|
-
trak2 = FMP4.audioTrak(data)
|
|
34
|
+
let trak2 = new Uint8Array([])
|
|
35
|
+
if (data.channelCount) {
|
|
36
|
+
trak2 = FMP4.audioTrak(data);
|
|
35
37
|
}
|
|
36
|
-
|
|
37
|
-
let moovBoxes = FMP4.videoOnly ? [mvhd, trak1, mvex] : [mvhd, trak1, trak2, mvex];
|
|
38
|
-
moovBoxes.forEach(item => {
|
|
38
|
+
[mvhd, mvex, trak1, trak2].forEach(item => {
|
|
39
39
|
size += item.byteLength
|
|
40
40
|
})
|
|
41
|
-
|
|
42
|
-
buffer.write(FMP4.size(size), FMP4.type('moov'), mvhd, trak1, mvex)
|
|
43
|
-
} else {
|
|
44
|
-
buffer.write(FMP4.size(size), FMP4.type('moov'), mvhd, trak1, trak2, mvex)
|
|
45
|
-
}
|
|
41
|
+
buffer.write(FMP4.size(size), FMP4.type('moov'), mvhd, mvex, trak1, trak2)
|
|
46
42
|
return buffer.buffer
|
|
47
43
|
}
|
|
48
44
|
static mvhd (duration, timescale) {
|
|
49
45
|
let buffer = new Buffer()
|
|
50
46
|
duration *= timescale
|
|
51
|
-
const upperWordDuration = Math.floor(duration / (UINT32_MAX + 1))
|
|
52
|
-
const lowerWordDuration = Math.floor(duration % (UINT32_MAX + 1))
|
|
47
|
+
// const upperWordDuration = Math.floor(duration / (UINT32_MAX + 1))
|
|
48
|
+
// const lowerWordDuration = Math.floor(duration % (UINT32_MAX + 1))
|
|
53
49
|
let bytes = new Uint8Array([
|
|
54
|
-
|
|
50
|
+
0x00, // version 1
|
|
55
51
|
0x00, 0x00, 0x00, // flags
|
|
56
|
-
0x00, 0x00, 0x00, 0x00,
|
|
57
|
-
0x00, 0x00, 0x00, 0x00,
|
|
52
|
+
0x00, 0x00, 0x00, 0x00, // creation_time
|
|
53
|
+
0x00, 0x00, 0x00, 0x00, // modification_time
|
|
58
54
|
(timescale >> 24) & 0xff,
|
|
59
55
|
(timescale >> 16) & 0xff,
|
|
60
56
|
(timescale >> 8) & 0xff,
|
|
61
57
|
timescale & 0xff, // timescale
|
|
62
|
-
(
|
|
63
|
-
(
|
|
64
|
-
(
|
|
65
|
-
|
|
66
|
-
(lowerWordDuration >> 24),
|
|
67
|
-
(lowerWordDuration >> 16) & 0xff,
|
|
68
|
-
(lowerWordDuration >> 8) & 0xff,
|
|
69
|
-
lowerWordDuration & 0xff,
|
|
58
|
+
(duration >> 24) & 0xff,
|
|
59
|
+
(duration >> 16) & 0xff,
|
|
60
|
+
(duration >> 8) & 0xff,
|
|
61
|
+
duration & 0xff, // duration
|
|
70
62
|
0x00, 0x01, 0x00, 0x00, // 1.0 rate
|
|
71
63
|
0x01, 0x00, // 1.0 volume
|
|
72
64
|
0x00, 0x00, // reserved
|
|
@@ -87,7 +79,7 @@ class FMP4 {
|
|
|
87
79
|
0x00, 0x00, 0x00, 0x00,
|
|
88
80
|
0x00, 0x00, 0x00, 0x00,
|
|
89
81
|
0x00, 0x00, 0x00, 0x00, // pre_defined
|
|
90
|
-
|
|
82
|
+
0x00, 0x00, 0x00, 0x03 // next_track_ID
|
|
91
83
|
])
|
|
92
84
|
buffer.write(FMP4.size(8 + bytes.length), FMP4.type('mvhd'), new Uint8Array(bytes))
|
|
93
85
|
return buffer.buffer
|
|
@@ -106,11 +98,16 @@ class FMP4 {
|
|
|
106
98
|
type: 'video',
|
|
107
99
|
timescale: data.videoTimeScale,
|
|
108
100
|
duration: data.videoDuration,
|
|
101
|
+
vps: data.vps,
|
|
109
102
|
sps: data.sps,
|
|
110
103
|
pps: data.pps,
|
|
111
104
|
pixelRatio: data.pixelRatio,
|
|
112
105
|
width: data.width,
|
|
113
|
-
height: data.height
|
|
106
|
+
height: data.height,
|
|
107
|
+
videoCodec: data.videoCodec,
|
|
108
|
+
hvc1Data: data.hvc1Data,
|
|
109
|
+
hvcCData: data.hvcCData,
|
|
110
|
+
stss: data.stss
|
|
114
111
|
});
|
|
115
112
|
[tkhd, mdia].forEach(item => {
|
|
116
113
|
size += item.byteLength
|
|
@@ -128,12 +125,14 @@ class FMP4 {
|
|
|
128
125
|
height: 0,
|
|
129
126
|
type: 'audio'
|
|
130
127
|
})
|
|
128
|
+
let channelCount = data.channelCount
|
|
129
|
+
let sampleRate = data.sampleRate
|
|
131
130
|
let mdia = FMP4.mdia({
|
|
132
131
|
type: 'audio',
|
|
133
132
|
timescale: data.audioTimeScale,
|
|
134
133
|
duration: data.audioDuration,
|
|
135
|
-
channelCount
|
|
136
|
-
|
|
134
|
+
channelCount,
|
|
135
|
+
sampleRate,
|
|
137
136
|
audioConfig: data.audioConfig
|
|
138
137
|
});
|
|
139
138
|
[tkhd, mdia].forEach(item => {
|
|
@@ -154,27 +153,23 @@ class FMP4 {
|
|
|
154
153
|
|
|
155
154
|
let type = data.type
|
|
156
155
|
|
|
157
|
-
let upperWordDuration = Math.floor(duration / (UINT32_MAX + 1))
|
|
156
|
+
// let upperWordDuration = Math.floor(duration / (UINT32_MAX + 1))
|
|
158
157
|
|
|
159
|
-
let lowerWordDuration = Math.floor(duration % (UINT32_MAX + 1))
|
|
158
|
+
// let lowerWordDuration = Math.floor(duration % (UINT32_MAX + 1))
|
|
160
159
|
let content = new Uint8Array([
|
|
161
|
-
|
|
162
|
-
0x00, 0x00,
|
|
163
|
-
0x00, 0x00, 0x00, 0x00,
|
|
164
|
-
|
|
160
|
+
0x00, // version 1
|
|
161
|
+
0x00, 0x00, 0x03, // flags
|
|
162
|
+
0x00, 0x00, 0x00, 0x00, // creation_time
|
|
163
|
+
0xD9, 0xAC, 0xEC, 0x56, // modification_time
|
|
165
164
|
(id >> 24) & 0xff,
|
|
166
165
|
(id >> 16) & 0xff,
|
|
167
166
|
(id >> 8) & 0xff,
|
|
168
167
|
id & 0xff, // track_ID
|
|
169
168
|
0x00, 0x00, 0x00, 0x00, // reserved
|
|
170
|
-
(
|
|
171
|
-
(
|
|
172
|
-
(
|
|
173
|
-
|
|
174
|
-
(lowerWordDuration >> 24),
|
|
175
|
-
(lowerWordDuration >> 16) & 0xff,
|
|
176
|
-
(lowerWordDuration >> 8) & 0xff,
|
|
177
|
-
lowerWordDuration & 0xff,
|
|
169
|
+
(duration >> 24) & 0xff,
|
|
170
|
+
(duration >> 16) & 0xff,
|
|
171
|
+
(duration >> 8) & 0xff,
|
|
172
|
+
duration & 0xff, // duration
|
|
178
173
|
0x00, 0x00, 0x00, 0x00,
|
|
179
174
|
0x00, 0x00, 0x00, 0x00, // reserved
|
|
180
175
|
0x00, 0x00, // layer
|
|
@@ -215,7 +210,7 @@ class FMP4 {
|
|
|
215
210
|
}
|
|
216
211
|
static mdia (data) {
|
|
217
212
|
let buffer = new Buffer(); let size = 8
|
|
218
|
-
let mdhd = FMP4.mdhd(data.timescale
|
|
213
|
+
let mdhd = FMP4.mdhd(data.timescale)
|
|
219
214
|
let hdlr = FMP4.hdlr(data.type)
|
|
220
215
|
let minf = FMP4.minf(data);
|
|
221
216
|
[mdhd, hdlr, minf].forEach(item => {
|
|
@@ -230,21 +225,14 @@ class FMP4 {
|
|
|
230
225
|
const upperWordDuration = Math.floor(duration / (UINT32_MAX + 1))
|
|
231
226
|
const lowerWordDuration = Math.floor(duration % (UINT32_MAX + 1))
|
|
232
227
|
let content = new Uint8Array([
|
|
233
|
-
0x00, 0x00, 0x00, 0x00,
|
|
234
|
-
|
|
228
|
+
0x00, 0x00, 0x00, 0x00, // creation_time
|
|
229
|
+
0xD9, 0x14, 0x25, 0x5A, // modification_time
|
|
235
230
|
(timescale >> 24) & 0xff, (timescale >> 16) & 0xff, (timescale >> 8) & 0xff, timescale & 0xff,
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
(upperWordDuration >> 8) & 0xff,
|
|
239
|
-
upperWordDuration & 0xff,
|
|
240
|
-
(lowerWordDuration >> 24),
|
|
241
|
-
(lowerWordDuration >> 16) & 0xff,
|
|
242
|
-
(lowerWordDuration >> 8) & 0xff,
|
|
243
|
-
lowerWordDuration & 0xff,
|
|
244
|
-
0x55, 0xc4, // 'und' language
|
|
231
|
+
0x00, 0x00, 0x00, 0x00, // duration
|
|
232
|
+
0x15, 0xC7, // 'und' language
|
|
245
233
|
0x00, 0x00
|
|
246
234
|
])
|
|
247
|
-
buffer.write(FMP4.size(12 + content.byteLength), FMP4.type('mdhd'), FMP4.extension(
|
|
235
|
+
buffer.write(FMP4.size(12 + content.byteLength), FMP4.type('mdhd'), FMP4.extension(0, 0), content)
|
|
248
236
|
return buffer.buffer
|
|
249
237
|
}
|
|
250
238
|
static hdlr (type) {
|
|
@@ -322,26 +310,37 @@ class FMP4 {
|
|
|
322
310
|
let stsc = FMP4.stsc()
|
|
323
311
|
let stsz = FMP4.stsz()
|
|
324
312
|
let stco = FMP4.stco();
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
313
|
+
if(data.type === 'video') {
|
|
314
|
+
let stss = FMP4.stss(data.stss);
|
|
315
|
+
[stsd, stts, stss, stsc, stsz, stco].forEach(item => {
|
|
316
|
+
size += item.byteLength
|
|
317
|
+
})
|
|
318
|
+
buffer.write(FMP4.size(size), FMP4.type('stbl'), stsd, stts, stss, stsc, stsz, stco)
|
|
319
|
+
} else {
|
|
320
|
+
[stsd, stts, stsc, stsz, stco].forEach(item => {
|
|
321
|
+
size += item.byteLength
|
|
322
|
+
})
|
|
323
|
+
buffer.write(FMP4.size(size), FMP4.type('stbl'), stsd, stts, stsc, stsz, stco)
|
|
324
|
+
}
|
|
325
|
+
|
|
329
326
|
return buffer.buffer
|
|
330
327
|
}
|
|
331
328
|
static stsd (data) {
|
|
332
329
|
let buffer = new Buffer(); let content
|
|
333
330
|
if (data.type === 'audio') {
|
|
334
|
-
// if (!data.isAAC && data.codec === 'mp4') {
|
|
335
|
-
// content = FMP4.mp3(data);
|
|
336
|
-
// } else {
|
|
337
|
-
//
|
|
338
|
-
// }
|
|
339
|
-
// 支持mp4a
|
|
340
331
|
content = FMP4.mp4a(data)
|
|
332
|
+
} else if (data.videoCodec.indexOf('hvc1') > -1) {
|
|
333
|
+
content = FMP4.hvc1(data)
|
|
341
334
|
} else {
|
|
342
335
|
content = FMP4.avc1(data)
|
|
343
336
|
}
|
|
344
|
-
buffer.write(
|
|
337
|
+
buffer.write(
|
|
338
|
+
FMP4.size(16 + content.byteLength),
|
|
339
|
+
FMP4.type('stsd'),
|
|
340
|
+
FMP4.extension(0, 0),
|
|
341
|
+
new Uint8Array([0x00, 0x00, 0x00, 0x01]),
|
|
342
|
+
content
|
|
343
|
+
)
|
|
345
344
|
return buffer.buffer
|
|
346
345
|
}
|
|
347
346
|
static mp4a (data) {
|
|
@@ -355,8 +354,8 @@ class FMP4 {
|
|
|
355
354
|
0x00, data.channelCount, // channelcount
|
|
356
355
|
0x00, 0x10, // sampleSize:16bits
|
|
357
356
|
0x00, 0x00, 0x00, 0x00, // reserved2
|
|
358
|
-
(data.
|
|
359
|
-
data.
|
|
357
|
+
(data.sampleRate >> 8) & 0xff,
|
|
358
|
+
data.sampleRate & 0xff, //
|
|
360
359
|
0x00, 0x00
|
|
361
360
|
])
|
|
362
361
|
let esds = FMP4.esds(data.audioConfig)
|
|
@@ -451,6 +450,45 @@ class FMP4 {
|
|
|
451
450
|
)
|
|
452
451
|
return buffer.buffer
|
|
453
452
|
}
|
|
453
|
+
static hvc1 (data) {
|
|
454
|
+
const buffer = new Buffer()
|
|
455
|
+
const content = new Uint8Array([
|
|
456
|
+
0x00, 0x00, 0x00, // reserved
|
|
457
|
+
0x00, 0x00, 0x00, // reserved
|
|
458
|
+
0x00, 0x01, // data_reference_index
|
|
459
|
+
0x00, 0x00, // pre_defined
|
|
460
|
+
0x00, 0x00, // reserved
|
|
461
|
+
0x00, 0x00, 0x00, 0x00,
|
|
462
|
+
0x00, 0x00, 0x00, 0x00,
|
|
463
|
+
0x00, 0x00, 0x00, 0x00, // pre_defined
|
|
464
|
+
(data.width >> 8) & 0xFF,
|
|
465
|
+
data.width & 0xff, // width
|
|
466
|
+
(data.height >> 8) & 0xFF,
|
|
467
|
+
data.height & 0xff, // height
|
|
468
|
+
0x00, 0x48, 0x00, 0x00, // horizresolution
|
|
469
|
+
0x00, 0x48, 0x00, 0x00, // vertresolution
|
|
470
|
+
0x00, 0x00, 0x00, 0x00, // reserved
|
|
471
|
+
0x00, 0x01, // frame_count
|
|
472
|
+
0x00,
|
|
473
|
+
0x00, 0x00, 0x00, 0x00, // dailymotion/hls.js
|
|
474
|
+
0x00, 0x00, 0x00, 0x00,
|
|
475
|
+
0x00, 0x00, 0x00, 0x00,
|
|
476
|
+
0x00, 0x00, 0x00, 0x00,
|
|
477
|
+
0x00, 0x00, 0x00, 0x00,
|
|
478
|
+
0x00, 0x00, 0x00, 0x00,
|
|
479
|
+
0x00, 0x00, 0x00, 0x00,
|
|
480
|
+
0x00, 0x00, 0x00, // compressorname
|
|
481
|
+
0x00, 0x18, // depth = 24
|
|
482
|
+
0xFF, 0xFF,
|
|
483
|
+
]);
|
|
484
|
+
|
|
485
|
+
buffer.write(
|
|
486
|
+
FMP4.size(8 + content.byteLength + 8 + data.hvcCData.byteLength + 10), FMP4.type('hvc1'), content,
|
|
487
|
+
FMP4.size(8 + data.hvcCData.byteLength), FMP4.type('hvcC'), new Uint8Array(data.hvcCData),
|
|
488
|
+
FMP4.size(10), FMP4.type('fiel'), new Uint8Array([0x01, 0x00])
|
|
489
|
+
)
|
|
490
|
+
return buffer.buffer
|
|
491
|
+
}
|
|
454
492
|
static stts () {
|
|
455
493
|
let buffer = new Buffer()
|
|
456
494
|
let content = new Uint8Array([
|
|
@@ -461,6 +499,26 @@ class FMP4 {
|
|
|
461
499
|
buffer.write(FMP4.size(16), FMP4.type('stts'), content)
|
|
462
500
|
return buffer.buffer
|
|
463
501
|
}
|
|
502
|
+
static stss (stssObj) {
|
|
503
|
+
let buffer = new Buffer()
|
|
504
|
+
let entries = [];
|
|
505
|
+
stssObj.entries.forEach(item => {
|
|
506
|
+
entries.push(item >> 24)
|
|
507
|
+
entries.push((item >> 16) & 0xff)
|
|
508
|
+
entries.push((item >> 8) & 0xff)
|
|
509
|
+
entries.push(item & 0xff)
|
|
510
|
+
})
|
|
511
|
+
let content = new Uint8Array([
|
|
512
|
+
0x00, // version
|
|
513
|
+
0x00, 0x00, 0x00, // flags
|
|
514
|
+
(stssObj.count >> 24), // entry_count
|
|
515
|
+
(stssObj.count >> 16) & 0xff,
|
|
516
|
+
(stssObj.count >> 8) & 0xff,
|
|
517
|
+
stssObj.count & 0xff,
|
|
518
|
+
].concat(entries))
|
|
519
|
+
buffer.write(FMP4.size(8+8+4*stssObj.count), FMP4.type('stss'), content)
|
|
520
|
+
return buffer.buffer
|
|
521
|
+
}
|
|
464
522
|
static stsc () {
|
|
465
523
|
let buffer = new Buffer()
|
|
466
524
|
let content = new Uint8Array([
|
|
@@ -495,7 +553,7 @@ class FMP4 {
|
|
|
495
553
|
static mvex (duration, timeScale) {
|
|
496
554
|
let buffer = new Buffer()
|
|
497
555
|
let mehd = Buffer.writeUint32(duration * timeScale)
|
|
498
|
-
buffer.write(FMP4.size(88), FMP4.type('mvex'), FMP4.size(16), FMP4.type('mehd'), FMP4.extension(0, 0), mehd, FMP4.
|
|
556
|
+
buffer.write(FMP4.size(88), FMP4.type('mvex'), FMP4.size(16), FMP4.type('mehd'), FMP4.extension(0, 0), mehd, FMP4.trex1(1), FMP4.trex2(2))
|
|
499
557
|
return buffer.buffer
|
|
500
558
|
}
|
|
501
559
|
static trex (id) {
|
|
@@ -515,9 +573,43 @@ class FMP4 {
|
|
|
515
573
|
buffer.write(FMP4.size(8 + content.byteLength), FMP4.type('trex'), content)
|
|
516
574
|
return buffer.buffer
|
|
517
575
|
}
|
|
576
|
+
static trex1 (id) {
|
|
577
|
+
let buffer = new Buffer()
|
|
578
|
+
let content = new Uint8Array([
|
|
579
|
+
0x00, // version 0
|
|
580
|
+
0x00, 0x00, 0x00, // flags
|
|
581
|
+
(id >> 24),
|
|
582
|
+
(id >> 16) & 0xff,
|
|
583
|
+
(id >> 8) & 0xff,
|
|
584
|
+
(id & 0xff), // track_ID
|
|
585
|
+
0x00, 0x00, 0x00, 0x01, // default_sample_description_index
|
|
586
|
+
0x00, 0x00, 0x02, 0x00, // default_sample_duration
|
|
587
|
+
0x00, 0x00, 0x00, 0x00, // default_sample_size
|
|
588
|
+
0x00, 0x01, 0x00, 0x00 // default_sample_flags
|
|
589
|
+
])
|
|
590
|
+
buffer.write(FMP4.size(8 + content.byteLength), FMP4.type('trex'), content)
|
|
591
|
+
return buffer.buffer
|
|
592
|
+
}
|
|
593
|
+
static trex2 (id) {
|
|
594
|
+
let buffer = new Buffer()
|
|
595
|
+
let content = new Uint8Array([
|
|
596
|
+
0x00, // version 0
|
|
597
|
+
0x00, 0x00, 0x00, // flags
|
|
598
|
+
(id >> 24),
|
|
599
|
+
(id >> 16) & 0xff,
|
|
600
|
+
(id >> 8) & 0xff,
|
|
601
|
+
(id & 0xff), // track_ID
|
|
602
|
+
0x00, 0x00, 0x00, 0x01, // default_sample_description_index
|
|
603
|
+
0x00, 0x00, 0x04, 0x00, // default_sample_duration
|
|
604
|
+
0x00, 0x00, 0x00, 0x00, // default_sample_size
|
|
605
|
+
0x02, 0x00, 0x00, 0x00 // default_sample_flags
|
|
606
|
+
])
|
|
607
|
+
buffer.write(FMP4.size(8 + content.byteLength), FMP4.type('trex'), content)
|
|
608
|
+
return buffer.buffer
|
|
609
|
+
}
|
|
518
610
|
static moof (data) {
|
|
519
611
|
let buffer = new Buffer(); let size = 8
|
|
520
|
-
let mfhd = FMP4.mfhd()
|
|
612
|
+
let mfhd = FMP4.mfhd(data)
|
|
521
613
|
let traf = FMP4.traf(data);
|
|
522
614
|
[mfhd, traf].forEach(item => {
|
|
523
615
|
size += item.byteLength
|
|
@@ -525,17 +617,22 @@ class FMP4 {
|
|
|
525
617
|
buffer.write(FMP4.size(size), FMP4.type('moof'), mfhd, traf)
|
|
526
618
|
return buffer.buffer
|
|
527
619
|
}
|
|
528
|
-
static mfhd () {
|
|
620
|
+
static mfhd (data) {
|
|
529
621
|
let buffer = new Buffer()
|
|
530
|
-
let content =
|
|
531
|
-
|
|
622
|
+
let content = null;
|
|
623
|
+
if (data.id === 1) {
|
|
624
|
+
content = Buffer.writeUint32((data.fragIndex || 0) + 1)
|
|
625
|
+
}
|
|
626
|
+
else {
|
|
627
|
+
content = Buffer.writeUint32((data.fragIndex || 0) + 1)
|
|
628
|
+
}
|
|
532
629
|
buffer.write(FMP4.size(16), FMP4.type('mfhd'), FMP4.extension(0, 0), content)
|
|
533
630
|
return buffer.buffer
|
|
534
631
|
}
|
|
535
632
|
static traf (data) {
|
|
536
633
|
let buffer = new Buffer(); let size = 8
|
|
537
634
|
let tfhd = FMP4.tfhd(data.id)
|
|
538
|
-
let tfdt = FMP4.tfdt(data.time)
|
|
635
|
+
let tfdt = FMP4.tfdt(data, data.time)
|
|
539
636
|
let sdtp = FMP4.sdtp(data)
|
|
540
637
|
let trun = FMP4.trun(data, sdtp.byteLength);
|
|
541
638
|
[tfhd, tfdt, sdtp, trun].forEach(item => {
|
|
@@ -547,13 +644,14 @@ class FMP4 {
|
|
|
547
644
|
static tfhd (id) {
|
|
548
645
|
let buffer = new Buffer()
|
|
549
646
|
let content = Buffer.writeUint32(id)
|
|
550
|
-
buffer.write(FMP4.size(16), FMP4.type('tfhd'),
|
|
647
|
+
buffer.write(FMP4.size(16), FMP4.type('tfhd'), new Uint8Array([
|
|
648
|
+
0x00, 0x02, 0x00, 0x00
|
|
649
|
+
]), content)
|
|
551
650
|
return buffer.buffer
|
|
552
651
|
}
|
|
553
|
-
static tfdt (time) {
|
|
652
|
+
static tfdt (data, time) {
|
|
554
653
|
let buffer = new Buffer()
|
|
555
654
|
let upper = Math.floor(time / (UINT32_MAX + 1))
|
|
556
|
-
|
|
557
655
|
let lower = Math.floor(time % (UINT32_MAX + 1))
|
|
558
656
|
buffer.write(FMP4.size(20), FMP4.type('tfdt'), FMP4.extension(1, 0), Buffer.writeUint32(upper), Buffer.writeUint32(lower))
|
|
559
657
|
return buffer.buffer
|
|
@@ -596,7 +694,8 @@ class FMP4 {
|
|
|
596
694
|
return buffer.buffer
|
|
597
695
|
}
|
|
598
696
|
static mdat (data) {
|
|
599
|
-
let buffer = new Buffer();
|
|
697
|
+
let buffer = new Buffer();
|
|
698
|
+
let size = 8;
|
|
600
699
|
data.samples.forEach(item => {
|
|
601
700
|
size += item.size
|
|
602
701
|
})
|
|
@@ -608,6 +707,4 @@ class FMP4 {
|
|
|
608
707
|
}
|
|
609
708
|
}
|
|
610
709
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
export default FMP4
|
|
710
|
+
export default FMP4
|
package/src/gap_jump.js
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/***
|
|
2
|
+
* 音视频源数据不对齐或者 关键视频帧存在cts,导致浏览器播不动场景下
|
|
3
|
+
*
|
|
4
|
+
* reference shakaplayer, 借鉴shakaplayer,根据项目逻辑进行改造
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import IntervalTimer from './util/intervalTimer';
|
|
8
|
+
export default class GapJump {
|
|
9
|
+
|
|
10
|
+
constructor(player, config) {
|
|
11
|
+
this.player = player;
|
|
12
|
+
this.mediaElem = player.video;
|
|
13
|
+
this.config = config;
|
|
14
|
+
this.timer = new IntervalTimer();
|
|
15
|
+
|
|
16
|
+
this.prevReadyState = this.mediaElem.readyState;
|
|
17
|
+
this.didFireLargeGap = false;
|
|
18
|
+
this.seekingEventReceived = false;
|
|
19
|
+
this.segmentAppended = false;
|
|
20
|
+
this.onWaitFunc = this._onWaiting.bind(this);
|
|
21
|
+
this.onPlayFunc = this._onPlay.bind(this);
|
|
22
|
+
this.isSafari = /(Safari|iPhone|iPad|iPod)/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent) && !/BlackBerry/.test(navigator.platform);
|
|
23
|
+
if (this.config.useGapJump !== false) {
|
|
24
|
+
this._start();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
this.hasPlayed = false;
|
|
28
|
+
}
|
|
29
|
+
_onWaiting() {
|
|
30
|
+
this.onGapJump('_onWaiting');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
_onPlay() {
|
|
34
|
+
this.hasPlayed = true;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
_start() {
|
|
38
|
+
this.mediaElem.addEventListener('waiting', this.onWaitFunc);
|
|
39
|
+
this.mediaElem.addEventListener('play', this.onPlayFunc);
|
|
40
|
+
//250ms
|
|
41
|
+
this.timer.repeat(() => {
|
|
42
|
+
this.onGapJump('repeat');
|
|
43
|
+
}, 250);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
onSegmentAppend() {
|
|
47
|
+
this.segmentAppended = true;
|
|
48
|
+
this.onGapJump('onSegmentAppend');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
onSeeking() {
|
|
52
|
+
this.seekingEventReceived = true;
|
|
53
|
+
this.segmentAppended = false;
|
|
54
|
+
this.didFireLargeGap = false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
onGapJump(type) {
|
|
58
|
+
if (this.mediaElem.readyState === HTMLMediaElement.HAVE_NOTHING) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (this.mediaElem.seeking) {
|
|
62
|
+
if (!this.seekingEventReceived) { return; }
|
|
63
|
+
} else {
|
|
64
|
+
this.seekingEventReceived = false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (this.mediaElem.paused && this.mediaElem.currentTime !== 0 && this.hasPlayed) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (this.mediaElem.readyState !== this.prevReadyState) {
|
|
71
|
+
this.didFireLargeGap = false;
|
|
72
|
+
this.prevReadyState = this.mediaElem.readyState;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const buffered = this.mediaElem.buffered;
|
|
76
|
+
const smallGapLimit = this.config.smallGapLimit || 0.5;
|
|
77
|
+
const gapDetectionThreshold = this.config.gapDetectionThreshold || 0.1;
|
|
78
|
+
const currentTime = this.mediaElem.currentTime;
|
|
79
|
+
const idx = this._getIndex(buffered, currentTime, gapDetectionThreshold);
|
|
80
|
+
if (idx === null) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (idx === 0 && !this.segmentAppended) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const jumpTo = buffered.start(idx) + 0.1;
|
|
88
|
+
const seekEnd = this.mediaElem.duration;
|
|
89
|
+
|
|
90
|
+
if (jumpTo > seekEnd) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const jumpSize = jumpTo - currentTime;
|
|
94
|
+
const isGapSmall = jumpSize <= smallGapLimit;
|
|
95
|
+
let jumpLargeGap = false;
|
|
96
|
+
if (jumpSize < GapJump.BROWSER_GAP_TOLERANCE) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
//对于分片缺失,目前未处理
|
|
100
|
+
if (isGapSmall) {
|
|
101
|
+
if (this.config.disableGapSetPosition !== true) {
|
|
102
|
+
this.mediaElem.currentTime = this.isSafari ? jumpTo + 0.1 : jumpTo;
|
|
103
|
+
}
|
|
104
|
+
this.player && this.player.emit('detectGap');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
_getIndex(buffered, time, threshold) {
|
|
110
|
+
if (!buffered || !buffered.length) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
if (buffered.length === 1 && buffered.end(0) - buffered.start(0) < 1e-6) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
const bufferedInfo = this._getBuffered(buffered);
|
|
117
|
+
let idx = null;
|
|
118
|
+
for (let i = 0; i < bufferedInfo.length; i++) {
|
|
119
|
+
let item = bufferedInfo[i];
|
|
120
|
+
if (item.start > time && (i === 0 || bufferedInfo[i - 1].end - time <= threshold)) {
|
|
121
|
+
idx = i;
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return idx;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
_getBuffered(b) {
|
|
129
|
+
if (!b) {
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
const ret = [];
|
|
133
|
+
for (let i = 0; i < b.length; i++) {
|
|
134
|
+
ret.push({
|
|
135
|
+
start: b.start(i),
|
|
136
|
+
end: b.end(i)
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return ret;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
destroy() {
|
|
143
|
+
this.mediaElem.removeEventListener('waiting', this.onWaitFunc);
|
|
144
|
+
this.mediaElem.removeEventListener('play', this.onPlayFunc);
|
|
145
|
+
this.timer.clear();
|
|
146
|
+
this.timer = null;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
GapJump.BROWSER_GAP_TOLERANCE = 0.001;
|
|
151
|
+
|