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.
Files changed (84) hide show
  1. package/browser/index.js +1 -1
  2. package/browser/index.js.map +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/index.js.map +1 -1
  5. package/package.json +5 -4
  6. package/src/constants.js +14 -0
  7. package/src/fmp4/buffer.js +6 -0
  8. package/src/fmp4/mp4.js +181 -84
  9. package/src/gap_jump.js +151 -0
  10. package/src/index.js +550 -315
  11. package/src/media/mse.js +77 -22
  12. package/src/media/task.js +68 -17
  13. package/src/mp4.js +284 -268
  14. package/src/parse/box/MP4DecConfigDescrTag.js +3 -0
  15. package/src/parse/box/MP4DecSpecificDescrTag.js +4 -0
  16. package/src/parse/box/avcC.js +4 -1
  17. package/src/parse/box/elst.js +0 -13
  18. package/src/parse/box/esds.js +9 -4
  19. package/src/parse/box/frma.js +10 -0
  20. package/src/parse/box/golomb.js +88 -0
  21. package/src/parse/box/hvc1.js +30 -0
  22. package/src/parse/box/hvcC.js +55 -0
  23. package/src/parse/box/pasp.js +2 -3
  24. package/src/parse/box/schm.js +18 -0
  25. package/src/parse/box/sps.js +286 -0
  26. package/src/parse/box/stsz.js +6 -1
  27. package/src/parse/box/tfhd.js +43 -0
  28. package/src/parse/box.js +5 -1
  29. package/src/parse/stream.js +4 -0
  30. package/src/util/getHeaders.js +18 -0
  31. package/src/util/index.js +138 -20
  32. package/src/util/intervalTimer.js +36 -0
  33. package/src/util/isSupport.js +20 -0
  34. package/src/util/proxyPromise.js +27 -0
  35. package/src/util/timer.js +46 -0
  36. package/src/util/xhr.js +46 -0
  37. package/version.json +1 -1
  38. package/webpack.config.js +45 -39
  39. package/src/util/download.js +0 -13
  40. package/src/write/box/MP4DecConfigDescrTag.js +0 -21
  41. package/src/write/box/MP4DecSpecificDescrTag.js +0 -19
  42. package/src/write/box/MP4ESDescrTag.js +0 -19
  43. package/src/write/box/SLConfigDescriptor.js +0 -16
  44. package/src/write/box/avc1.js +0 -33
  45. package/src/write/box/avcC.js +0 -32
  46. package/src/write/box/btrt.js +0 -14
  47. package/src/write/box/co64.js +0 -17
  48. package/src/write/box/ctts.js +0 -19
  49. package/src/write/box/dref.js +0 -25
  50. package/src/write/box/elst.js +0 -27
  51. package/src/write/box/esds.js +0 -11
  52. package/src/write/box/ftyp.js +0 -17
  53. package/src/write/box/hdlr.js +0 -15
  54. package/src/write/box/iods.js +0 -14
  55. package/src/write/box/mdat.js +0 -5
  56. package/src/write/box/mdhd.js +0 -27
  57. package/src/write/box/mehd.js +0 -12
  58. package/src/write/box/mfhd.js +0 -12
  59. package/src/write/box/mfro.js +0 -14
  60. package/src/write/box/mp4a.js +0 -26
  61. package/src/write/box/mvhd.js +0 -34
  62. package/src/write/box/pasp.js +0 -10
  63. package/src/write/box/smhd.js +0 -17
  64. package/src/write/box/stco.js +0 -17
  65. package/src/write/box/stsc.js +0 -19
  66. package/src/write/box/stsd.js +0 -23
  67. package/src/write/box/stss.js +0 -17
  68. package/src/write/box/stsz.js +0 -18
  69. package/src/write/box/stts.js +0 -18
  70. package/src/write/box/tfdt.js +0 -16
  71. package/src/write/box/tfhd.js +0 -18
  72. package/src/write/box/tfra.js +0 -29
  73. package/src/write/box/tkhd.js +0 -44
  74. package/src/write/box/trex.js +0 -16
  75. package/src/write/box/trun.js +0 -40
  76. package/src/write/box/udta.js +0 -5
  77. package/src/write/box/url.js +0 -16
  78. package/src/write/box/vmhd.js +0 -19
  79. package/src/write/box/wide.js +0 -12
  80. package/src/write/box.js +0 -37
  81. package/src/write/buffer.js +0 -12
  82. package/src/write/index.js +0 -33
  83. package/src/write/stream.js +0 -99
  84. package/webpack.config.test.js +0 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xgplayer-mp4",
3
- "version": "1.2.4",
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
- "peerDependency": {
40
- "xgplayer": "^0.1.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
  }
@@ -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
+ }
@@ -14,6 +14,12 @@ class Buffer {
14
14
  }
15
15
  })
16
16
  }
17
+ static writeUint16 (value) {
18
+ return new Uint8Array([
19
+ (value >> 8) & 0xff,
20
+ value & 0xff
21
+ ])
22
+ }
17
23
  static writeUint32 (value) {
18
24
  return new Uint8Array([
19
25
  value >> 24,
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, 0x6D, // isom,
22
+ 0x69, 0x73, 0x6F, 0x36, // isom,
22
23
  0x0, 0x0, 0x00, 0x01, // minor_version: 0x01
23
- 0x69, 0x73, 0x6F, 0x6D, // isom
24
- 0x61, 0x76, 0x63, 0x31 // avc1
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(!FMP4.videoOnly) {
34
- trak2 = FMP4.audioTrak(data)
34
+ let trak2 = new Uint8Array([])
35
+ if (data.channelCount) {
36
+ trak2 = FMP4.audioTrak(data);
35
37
  }
36
- let mvex = FMP4.mvex(data.duration, data.timeScale);
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
- if(FMP4.videoOnly) {
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
- 0x01, // version 1
50
+ 0x00, // version 1
55
51
  0x00, 0x00, 0x00, // flags
56
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, // creation_time
57
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // modification_time
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
- (upperWordDuration >> 24),
63
- (upperWordDuration >> 16) & 0xff,
64
- (upperWordDuration >> 8) & 0xff,
65
- upperWordDuration & 0xff,
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
- 0xff, 0xff, 0xff, 0xff // next_track_ID
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: data.channelCount,
136
- samplerate: data.sampleRate,
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
- 0x01, // version 1
162
- 0x00, 0x00, 0x07, // flags
163
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, // creation_time
164
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // modification_time
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
- (upperWordDuration >> 24),
171
- (upperWordDuration >> 16) & 0xff,
172
- (upperWordDuration >> 8) & 0xff,
173
- upperWordDuration & 0xff,
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, data.duration)
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, 0x00, 0x00, 0x00, 0x02, // creation_time
234
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // modification_time
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
- (upperWordDuration >> 24),
237
- (upperWordDuration >> 16) & 0xff,
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(1, 0), content)
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
- [stsd, stts, stsc, stsz, stco].forEach(item => {
326
- size += item.byteLength
327
- })
328
- buffer.write(FMP4.size(size), FMP4.type('stbl'), stsd, stts, stsc, stsz, stco)
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(FMP4.size(16 + content.byteLength), FMP4.type('stsd'), FMP4.extension(0, 0), new Uint8Array([0x00, 0x00, 0x00, 0x01]), content)
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.samplerate >> 8) & 0xff,
359
- data.samplerate & 0xff, //
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.trex(1), FMP4.trex(2))
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 = Buffer.writeUint32(FMP4.sequence)
531
- FMP4.sequence += 1
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'), FMP4.extension(0, 0), content)
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(); let size = 8
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
- FMP4.sequence = 1
612
-
613
- export default FMP4
710
+ export default FMP4
@@ -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
+