xgplayer-mp4 1.2.3 → 2.0.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.
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 +7 -5
  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 -265
  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/src/mp4.js CHANGED
@@ -1,53 +1,67 @@
1
1
  import EventEmitter from 'event-emitter'
2
- import Merge from 'deepmerge'
3
2
  import Parser from './parse'
4
3
  import Buffer from './fmp4/buffer'
5
4
  import FMP4 from './fmp4/mp4'
6
5
  import Task from './media/task'
7
6
  import util from './util'
8
7
  import Errors from './error'
8
+ import {CUSTOM_EVENTS, TASK_ERROR} from './constants'
9
+ import Player from 'xgplayer'
9
10
 
10
11
  class MP4 {
11
12
  /**
12
- * [constructor 构造函数]
13
- * @param {String} url [视频地址]
14
- * @param {Number} [chunk_size=Math.pow(25, 4)] [请求的数据块大小,对于长视频设置的较大些可以避免二次请求]
15
- */
16
- constructor (url, options, chunkSize = Math.pow(25, 4)) {
13
+ * [constructor 构造函数]
14
+ * @param {String} url [视频地址]
15
+ * @param {Number} [chunk_size=Math.pow(25, 4)] [请求的数据块大小,对于长视频设置的较大些可以避免二次请求]
16
+ */
17
+ constructor (url, xhrSetup, player, chunkSize = Math.pow(25, 4), ext = {}) {
17
18
  EventEmitter(this)
18
19
  this.url = url
19
- this.withCredentials = options.withCredentials
20
- FMP4.videoOnly = this.videoOnly = options.videoOnly || false
20
+ this.xhrSetup = xhrSetup
21
21
  this.CHUNK_SIZE = chunkSize
22
- this.init(url)
23
- this.once('moovReady', this.moovParse.bind(this))
24
- this.cache = new Buffer()
25
- this.bufferCache = new Set()
22
+ this.player = player
23
+ this.ext = ext
26
24
  this.timeRage = []
27
25
  this.canDownload = true
26
+ this.init()
27
+ Player.util.once(this, 'moovReady', this.moovParse.bind(this))
28
28
  }
29
29
 
30
30
  /**
31
- * [getData 根据字节区间下载二进制数据]
32
- * @param {Number} [start=0] [起始字节]
33
- * @param {Number} [end=start + this.CHUNK_SIZE] [截止字节]
34
- */
35
- getData (start = 0, end = start + this.CHUNK_SIZE) {
31
+ * [getData 根据字节区间下载二进制数据]
32
+ * @param {Number} [start=0] [起始字节]
33
+ * @param {Number} [end=start + this.CHUNK_SIZE] [截止字节]
34
+ */
35
+ getData (start = 0, end = start + this.CHUNK_SIZE - 1) {
36
36
  let self = this
37
37
  return new Promise((resolve, reject) => {
38
38
  let task = new Task(this.url, [
39
39
  start, end
40
- ], this.withCredentials, resolve)
41
- task.once('error', err => {
42
- self.emit('error', err)
40
+ ], this.xhrSetup, (data)=>{
41
+ if(self.hasDestroyed){
42
+ return;
43
+ }
44
+ resolve(data)
45
+ }, self.ext)
46
+ // Player.util.once(task, 'error', err => {
47
+ // self.emit('error', err)
48
+ // })
49
+
50
+ Player.util.once(task, CUSTOM_EVENTS.MEDIA_EXPIRED, ()=>{
51
+ self.player && self.player.onMediaExpired();
52
+ });
53
+
54
+ Player.util.once(task, TASK_ERROR, params => {
55
+ //非403状态或者非200,206状态逻辑
56
+ reject({code: params.code, status: params.status})
43
57
  })
44
58
  })
45
59
  }
46
60
 
47
61
  /**
48
- * [moovParse 解析视频信息]
49
- * @return {[type]} [description]
50
- */
62
+ * [moovParse 解析视频信息]
63
+ * @return {[type]} [description]
64
+ */
51
65
  moovParse () {
52
66
  let self = this
53
67
  let moov = this.moovBox
@@ -61,46 +75,69 @@ class MP4 {
61
75
  audioTimeScale
62
76
  let sps,
63
77
  pps,
78
+ vps,
64
79
  profile,
65
80
  width,
66
81
  height
67
82
  let channelCount,
68
83
  sampleRate,
69
84
  decoderConfig
70
- traks = [].concat(traks)
85
+ let hvc1Data, hvcCData
86
+ let pixelRatio = [1, 1]
87
+ if (!Array.isArray(traks)) {
88
+ traks = [traks]
89
+ }
71
90
  traks.forEach(trak => {
72
91
  let hdlr = util.findBox(trak, 'hdlr')
73
92
  let mdhd = util.findBox(trak, 'mdhd')
74
93
  if (!hdlr || !mdhd) {
75
- self.emit('error', new Errors('parse', '', {line: 72, handle: '[MP4] moovParse', url: self.url}))
94
+ self.emit('error', new Errors('parse', '', {line: 101, handle: '[MP4] moovParse', url: self.url}))
76
95
  return
77
96
  }
78
- if(hdlr.handleType === 'vide' && self.videoOnly) {
79
- let elst = util.findBox(trak, 'elst')
80
- trak.empty_duration = 0
81
- if (elst.empty_duration) {
82
- trak.empty_duration = elst.empty_duration * mdhd.timescale / mvhd.timeScale;
83
- }
84
-
85
- trak.time_offset = elst.start_time - trak.empty_duration;
86
- }
87
-
88
97
  let stsd = util.findBox(trak, 'stsd')
89
98
  let codecBox = stsd.subBox[0]
90
99
  if (hdlr.handleType === 'vide') {
91
100
  let avcC = util.findBox(trak, 'avcC')
101
+ let hvcC
102
+ if(!avcC) {
103
+ hvcC = util.findBox(trak, 'hvcC')
104
+ }
105
+
92
106
  let tkhd = util.findBox(trak, 'tkhd')
93
107
  videoTrak = trak
94
108
  videoTimeScale = mdhd.timescale
95
109
  if (avcC) {
96
110
  videoCodec = `${codecBox.type}.` + util.toHex(avcC.profile, avcC.profileCompatibility, avcC.AVCLevelIndication).join('')
97
- sps = avcC.sequence && avcC.sequence.map((item) => Number(`0x${item}`))
111
+ sps = avcC.sequence
112
+ pixelRatio = [avcC.spsInfo.par_ratio.width, avcC.spsInfo.par_ratio.height]
113
+ if (avcC.spsInfo.codec_size) {
114
+ width = avcC.spsInfo.codec_size.width
115
+ height = avcC.spsInfo.codec_size.height
116
+ }
98
117
  pps = avcC.pps && avcC.pps.map((item) => Number(`0x${item}`))
99
118
  profile = avcC.profile
119
+ } else if(hvcC) {
120
+ hvcCData = hvcC.data
121
+ let hvc1 = util.findBox(trak, 'hvc1')
122
+ if(hvc1) {
123
+ hvc1Data = hvc1.data
124
+ width = hvc1.width
125
+ height = hvc1.height
126
+ }
127
+ videoCodec = `${codecBox.type}.` + util.toHex(hvcC.profile, hvcC.profileCompatibility, hvcC.profileCompatibilityIndications).join('')
128
+ vps = hvcC.vps && hvcC.vps.map((item) => Number(`0x${item}`))
129
+ sps = hvcC.sequence
130
+ // pixelRatio = [hvcC.spsInfo.par_ratio.width, hvcC.spsInfo.par_ratio.height]
131
+ // if (hvcC.spsInfo.codec_size) {
132
+ // width = hvcC.spsInfo.codec_size.width
133
+ // height = hvcC.spsInfo.codec_size.height
134
+ // }
135
+ pps = hvcC.pps && hvcC.pps.map((item) => Number(`0x${item}`))
136
+ profile = hvcC.profile
100
137
  } else {
101
138
  videoCodec = `${codecBox.type}`
102
139
  }
103
- if (tkhd) {
140
+ if (tkhd && !width) {
104
141
  width = tkhd.width
105
142
  height = tkhd.height
106
143
  }
@@ -125,16 +162,14 @@ class MP4 {
125
162
  }
126
163
  }
127
164
  })
128
- this.videoTrak = Merge({}, videoTrak)
129
- if(!this.videoOnly) {
130
- this.audioTrak = Merge({}, audioTrak)
131
- }
165
+ if (!sps) return
166
+ // this.videoTrak = Merge({}, videoTrak)
167
+ // this.audioTrak = audioTrak ? Merge({}, audioTrak) : null
168
+ this.videoTrak = videoTrak;
169
+ this.audioTrak = audioTrak ? audioTrak : null
132
170
  let mdat = this._boxes.find(item => item.type === 'mdat')
133
171
  let videoDuration = util.seekTrakDuration(videoTrak, videoTimeScale)
134
- let audioDuration
135
- if(!this.videoOnly) {
136
- audioDuration = util.seekTrakDuration(audioTrak, audioTimeScale)
137
- }
172
+ let audioDuration = audioTrak ? util.seekTrakDuration(audioTrak, audioTimeScale) : videoDuration
138
173
  this.mdatStart = mdat.start
139
174
  let vf = this.videoKeyFrames
140
175
  let videoKeyFramesLength = vf.length - 1
@@ -147,52 +182,54 @@ class MP4 {
147
182
  } else {
148
183
  this.timeRage.push([
149
184
  item.time.time / videoTimeScale,
150
- -1
185
+ mvhd.duration / mvhd.timeScale
151
186
  ])
152
187
  }
153
188
  })
154
189
  this.meta = {
155
190
  videoCodec,
191
+ audioCodec,
156
192
  createTime: mvhd.createTime,
157
193
  modifyTime: mvhd.modifyTime,
158
- duration: videoDuration,
194
+ duration: mvhd.duration / mvhd.timeScale,
159
195
  timeScale: mvhd.timeScale,
160
196
  videoDuration,
161
197
  videoTimeScale,
162
- endTime: videoDuration,
198
+ audioDuration,
199
+ audioTimeScale,
200
+ endTime: Math.min(videoDuration, audioDuration),
201
+ vps,
163
202
  sps,
164
203
  pps,
165
204
  width,
166
205
  height,
167
206
  profile,
168
- pixelRatio: [
169
- 1, 1
170
- ],
207
+ pixelRatio,
171
208
  channelCount,
172
209
  sampleRate,
173
- audioConfig: decoderConfig
174
- }
175
- if(!this.videoOnly) {
176
- this.meta.audioCodec = audioCodec
177
- this.meta.audioDuration = audioDuration
178
- this.meta.audioTimeScale = audioTimeScale
179
- this.meta.duration = mvhd.duration / mvhd.timeScale
180
- this.meta.endTime = Math.min(videoDuration, audioDuration)
210
+ audioConfig: decoderConfig,
211
+ hvc1Data,
212
+ hvcCData,
213
+ ext: {
214
+ videoTrak: this.videoTrak,
215
+ audioTrak: this.audioTrak,
216
+ mdatStart: this.mdatStart,
217
+ timeRage: this.timeRage,
218
+ },
219
+ stss: this._stssObj
181
220
  }
221
+ this.emit('metaReady', this.meta)
182
222
  }
183
223
 
184
224
  /**
185
- * [init 实例的初始化,主要是获取视频的MOOV元信息]
186
- */
225
+ * [init 实例的初始化,主要是获取视频的MOOV元信息]
226
+ */
187
227
  init () {
188
228
  let self = this
189
- self.getData().then((res) => {
229
+ self.getData().then(res => {
190
230
  let parsed
191
-
192
231
  let moovStart = 0
193
-
194
232
  let moov
195
-
196
233
  let boxes
197
234
  try {
198
235
  parsed = new Parser(res)
@@ -217,7 +254,13 @@ class MP4 {
217
254
  if (nextBox) {
218
255
  if (nextBox.type === 'moov') {
219
256
  self.getData(moovStart, moovStart + nextBox.size + 28).then(res => {
220
- let parsed = new Parser(res)
257
+ let parsed
258
+ // try {
259
+ parsed = new Parser(res)
260
+ // }catch(e) {
261
+
262
+ // }
263
+
221
264
  self._boxes = self._boxes.concat(parsed.boxes)
222
265
  moov = parsed.boxes.filter(box => box.type === 'moov')
223
266
  if (moov.length) {
@@ -264,7 +307,8 @@ class MP4 {
264
307
  let stsz = util.findBox(trak, 'stsz') // sample-size
265
308
  let stts = util.findBox(trak, 'stts') // sample-time
266
309
  let stco = util.findBox(trak, 'stco') // chunk-offset
267
- let ctts = util.findBox(trak, 'ctts') // offset-compositime
310
+ let cttsObj = type === 'video' ? this._cttsObj : null;
311
+ let stscObj = type === 'video' ? this._stscVideoObj : this._stscAudioObj;
268
312
  let mdatStart = this.mdatStart
269
313
  let samples = []
270
314
  end = end !== undefined
@@ -275,8 +319,8 @@ class MP4 {
275
319
  samples.push({
276
320
  idx: item,
277
321
  size: stsz.entries[item],
278
- time: util.seekSampleTime(stts, ctts, item, trak.time_offset),
279
- offset: util.seekSampleOffset(stsc, stco, stsz, item, mdatStart)
322
+ time: util.seekSampleTime(stts, cttsObj, item),
323
+ offset: util.seekSampleOffset(stsc, stco, stsz, item, mdatStart, stscObj)
280
324
  })
281
325
  })
282
326
  } else if (end !== 0) {
@@ -284,16 +328,17 @@ class MP4 {
284
328
  samples.push({
285
329
  idx: i,
286
330
  size: stsz.entries[i],
287
- time: util.seekSampleTime(stts, ctts, i, trak.time_offset),
288
- offset: util.seekSampleOffset(stsc, stco, stsz, i, mdatStart)
331
+ time: util.seekSampleTime(stts, cttsObj, i),
332
+ offset: util.seekSampleOffset(stsc, stco, stsz, i, mdatStart, stscObj)
289
333
  })
290
334
  }
291
335
  } else {
336
+ let offset = util.seekSampleOffset(stsc, stco, stsz, start, mdatStart, stscObj)
292
337
  samples = {
293
338
  idx: start,
294
339
  size: stsz.entries[start],
295
- time: util.seekSampleTime(stts, ctts, start, trak.time_offset),
296
- offset: util.seekSampleOffset(stsc, stco, stsz, start, mdatStart)
340
+ time: util.seekSampleTime(stts, cttsObj, start),
341
+ offset: offset
297
342
  }
298
343
  }
299
344
  return samples
@@ -305,7 +350,33 @@ class MP4 {
305
350
  }
306
351
  let videoTrak = this.videoTrak
307
352
  let stss = util.findBox(videoTrak, 'stss')
353
+ let stsc = util.findBox(videoTrak, 'stsc') // chunk~samples
354
+ let ctts = util.findBox(videoTrak, 'ctts') // offset-compositime
355
+ this._cttsObj = null;
356
+ if(ctts){
357
+ this._cttsObj = {};
358
+ let count = 0;
359
+ for(let i = 0; i < ctts.entry.length; i++){
360
+ let entry = ctts.entry[i];
361
+ for(let j = 0; j < entry.count; j++){
362
+ this._cttsObj[count] = entry.offset;
363
+ count += 1;
364
+ }
365
+ }
366
+ }
367
+
368
+ this._stscVideoObj = {};
369
+ let sampleCount = 0;
370
+ for(let i = 0; i < stsc.count - 1; i++){
371
+ let entry = stsc.entries[i];
372
+ for(let j = 0; j < entry.chunk_count * entry.samples_per_chunk; j++){
373
+ sampleCount ++;
374
+ this._stscVideoObj[sampleCount] = entry;
375
+ }
376
+ }
377
+
308
378
  let frames = this.getSamplesByOrders('video', stss.entries.map(item => item - 1))
379
+ this._stssObj = stss;
309
380
  this._videoFrames = frames
310
381
  return frames
311
382
  }
@@ -317,6 +388,16 @@ class MP4 {
317
388
  let videoScale = util.findBox(this.videoTrak, 'mdhd').timescale
318
389
  let audioScale = util.findBox(this.audioTrak, 'mdhd').timescale
319
390
  let audioStts = util.findBox(this.audioTrak, 'stts').entry
391
+ let stsc = util.findBox(this.audioTrak, 'stsc') // chunk~samples
392
+ this._stscAudioObj = {};
393
+ let sampleCount = 0;
394
+ for(let i = 0; i < stsc.count - 1; i++){
395
+ let entry = stsc.entries[i];
396
+ for(let j = 0; j < entry.chunk_count * entry.samples_per_chunk; j++){
397
+ sampleCount ++;
398
+ this._stscAudioObj[sampleCount] = entry;
399
+ }
400
+ }
320
401
  let videoFrames = this.videoKeyFrames
321
402
  let audioIndex = []
322
403
  audioIndex = videoFrames.map(item => {
@@ -326,29 +407,33 @@ class MP4 {
326
407
  return this._audioFrames
327
408
  }
328
409
 
329
- packMeta () {
410
+ packMeta() {
330
411
  if (!this.meta) {
331
412
  return
332
413
  }
333
414
  let buffer = new Buffer()
334
415
  buffer.write(FMP4.ftyp())
335
416
  buffer.write(FMP4.moov(this.meta))
336
- this.cache.write(buffer.buffer)
417
+ // this.cache.write(buffer.buffer)
337
418
  return buffer.buffer
338
419
  }
339
420
 
340
- seek (time) {
341
- let timeStart = time * this.meta.videoTimeScale
342
- let fragIndex
421
+ getRangeFromTime(time){
422
+ let fragIndex = this.getFragmentIdx(time);
423
+ let range = this.getFragRange(fragIndex)
424
+ if(range === [0, 0]) return null;
425
+ return {
426
+ range,
427
+ fragIndex,
428
+ }
429
+ }
343
430
 
431
+ getFragmentIdx(time){
432
+ let timeStart = Math.round(time * this.meta.videoTimeScale)
433
+ let fragIndex
344
434
  let videoFrames = this.videoKeyFrames
345
- let audioFrames
346
- if(!this.videoOnly) {
347
- audioFrames = this.audioKeyFrames
348
- }
349
435
  videoFrames.every((item, idx) => {
350
436
  let nowTime = item.time.time
351
-
352
437
  let nextTime = videoFrames[idx + 1]
353
438
  ? videoFrames[idx + 1].time.time
354
439
  : Number.MAX_SAFE_INTEGER
@@ -359,10 +444,10 @@ class MP4 {
359
444
  return true
360
445
  }
361
446
  })
362
- if(!this.videoOnly) {
447
+ if (this.audioTrak) {
448
+ let audioFrames = this.audioKeyFrames
363
449
  audioFrames.every((item, idx) => {
364
450
  let nowTime = item.startTime
365
-
366
451
  let nextTime = audioFrames[idx + 1]
367
452
  ? audioFrames[idx + 1].startTime
368
453
  : Number.MAX_SAFE_INTEGER
@@ -374,197 +459,93 @@ class MP4 {
374
459
  }
375
460
  })
376
461
  }
377
- if (this.bufferCache.has(fragIndex)) {
378
- return Promise.resolve(null)
379
- } else {
380
- return this.loadFragment(fragIndex)
381
- }
462
+ return fragIndex;
382
463
  }
383
- loadFragment (fragIndex) {
384
- let start,
385
- end
464
+
465
+ seek (time) {
466
+ let fragIndex = this.getFragmentIdx(time);
467
+ this.timeRage[fragIndex].downloaded = true;
468
+ return this.loadFragment(fragIndex)
469
+ }
470
+
471
+ getFragRange (fragIndex) {
386
472
  let videoFrame = this.videoKeyFrames[fragIndex]
387
- let audioFrame
388
- start = videoFrame.offset
389
- if(!this.videoOnly) {
390
- audioFrame = this.getSamplesByOrders('audio', this.audioKeyFrames[fragIndex].order, 0)
391
- start = Math.min(videoFrame.offset, audioFrame.offset)
473
+ let start = videoFrame.offset
474
+ let end
475
+ if (this.audioTrak) {
476
+ let audioFrame = this.getSamplesByOrders('audio', this.audioKeyFrames[fragIndex].order, 0)
477
+ start = Math.min(start, audioFrame.offset)
392
478
  }
393
479
  if (fragIndex < this.videoKeyFrames.length - 1) {
394
480
  let videoNextFrame = this.videoKeyFrames[fragIndex + 1]
395
- let audioNextFrame
396
481
  end = videoNextFrame.offset
397
- if(!this.videoOnly) {
398
- audioNextFrame = this.getSamplesByOrders('audio', this.audioKeyFrames[fragIndex + 1].order, 0)
399
- end = Math.max(videoNextFrame.offset, audioNextFrame.offset)
482
+ if (this.audioTrak) {
483
+ let audioNextFrame = this.getSamplesByOrders('audio', this.audioKeyFrames[fragIndex + 1].order, 0)
484
+ end = Math.max(end, audioNextFrame.offset || 0)
400
485
  }
401
486
  }
402
- let self = this
403
487
  if (window.isNaN(start) || (end !== undefined && window.isNaN(end))) {
404
- self.emit('error', new Errors('parse', '', { line: 366, handle: '[MP4] loadFragment', url: self.url }))
405
- return false
406
- }
407
- if (this.bufferCache.has(fragIndex)) {
408
- return Promise.resolve(null)
409
- } else {
410
- return this.getData(
411
- start + self.mdatStart, end
412
- ? self.mdatStart + end
413
- : '').then((dat) => {
414
- return self.createFragment(new Uint8Array(dat), start, fragIndex)
415
- })
488
+ this.emit('error', new Errors('parse', '', { line: 366, handle: '[MP4] loadFragment', url: this.url }))
489
+ return [0, 0]
416
490
  }
491
+ return [start + this.mdatStart, end ? this.mdatStart + end : '']
417
492
  }
418
- addFragment (data) {
419
- let buffer = new Buffer()
420
- buffer.write(FMP4.moof(data))
421
- buffer.write(FMP4.mdat(data))
422
- this.cache.write(buffer.buffer)
423
- return buffer.buffer
424
- }
425
- createFragment (mdatData, start, fragIndex) {
493
+ loadFragment (fragIndex) {
426
494
  let self = this
427
- let resBuffers = []
428
- this.bufferCache.add(fragIndex)
429
- {
430
- let framesIndex = self.videoKeyFrames.map((item) => item.idx)
431
- let _samples = self.getSamplesByOrders('video', framesIndex[fragIndex], framesIndex[fragIndex + 1])
432
- let samples = _samples.map((item, idx) => {
433
- return {
434
- size: item.size,
435
- duration: item.time.duration,
436
- offset: item.time.offset,
437
- buffer: new Uint8Array(mdatData.slice(item.offset - start, item.offset - start + item.size)),
438
- key: idx === 0
439
- }
440
- })
441
- resBuffers.push(this.addFragment({id: 1, time: _samples[0].time.time, firstFlags: 0x2000000, flags: 0xf01, samples}))
442
- }
443
- if(!this.videoOnly) {
444
- let _samples = this.getSamplesByOrders(
445
- 'audio', this.audioKeyFrames[fragIndex].order, this.audioKeyFrames[fragIndex + 1]
446
- ? this.audioKeyFrames[fragIndex + 1].order
447
- : undefined)
448
- let samples = _samples.map((item, idx) => {
449
- return {
450
- size: item.size,
451
- duration: item.time.duration,
452
- offset: item.time.offset,
453
- buffer: new Uint8Array(mdatData.slice(item.offset - start, item.offset - start + item.size)),
454
- key: idx === 0
455
- }
456
- })
457
- resBuffers.push(this.addFragment({id: 2, time: _samples[0].time.time, firstFlags: 0x00, flags: 0x701, samples: samples}))
495
+ let range = this.getFragRange(fragIndex)
496
+ if(range === [0, 0]) {
497
+ debugger
498
+ return false;
458
499
  }
459
-
460
- let bufferSize = 0
461
- resBuffers.every(item => {
462
- bufferSize += item.byteLength
463
- return true
500
+ return this.getData(range[0], range[1]).then((dat) => {
501
+ return self.createFragment(new Uint8Array(dat), range[0] - this.mdatStart, fragIndex)
464
502
  })
465
- let buffer = new Uint8Array(bufferSize)
466
-
467
- let offset = 0
468
- resBuffers.every(item => {
469
- buffer.set(item, offset)
470
- offset += item.byteLength
471
- return true
503
+ .then(buf => {
504
+ return buf
472
505
  })
473
- return Promise.resolve(buffer)
474
506
  }
475
-
476
- download () {
477
- // new Download('fmp4.mp4', this.cache.buffer)
507
+ addFragment (data) {
508
+ let buffer = new Buffer()
509
+ return new Promise(resolve => {
510
+ buffer.write(FMP4.moof(data))
511
+ buffer.write(FMP4.mdat(data))
512
+ // this.cache.write(buffer.buffer)
513
+ resolve(buffer.buffer)
514
+ })
478
515
  }
479
-
480
- cut (start, end) {
516
+ getVideoBuffer(mdatData, start, fragIndex) {
481
517
  let self = this
482
- this.bufferCache.clear()
483
- let timeStart = start * this.meta.videoTimeScale
484
- let timeEnd = end * this.meta.videoTimeScale
485
- let fragIndexStart
486
- let fragIndexEnd
487
-
488
- let videoFrames = this.videoKeyFrames
489
- let audioFrames = this.audioKeyFrames
490
- videoFrames.every((item, idx) => {
491
- let nowTime = item.time.time
492
-
493
- let nextTime = videoFrames[idx + 1]
494
- ? videoFrames[idx + 1].time.time
495
- : Number.MAX_SAFE_INTEGER
496
- if (nowTime <= timeStart && timeStart < nextTime) {
497
- fragIndexStart = idx
498
- return true
499
- } else if (nowTime <= timeEnd && timeEnd < nextTime) {
500
- fragIndexEnd = idx
501
- return false
502
- } else {
503
- return true
504
- }
505
- })
506
- audioFrames.every((item, idx) => {
507
- let nowTime = item.startTime
508
-
509
- let nextTime = audioFrames[idx + 1]
510
- ? audioFrames[idx + 1].startTime
511
- : Number.MAX_SAFE_INTEGER
512
- if (nowTime <= timeStart && timeStart < nextTime) {
513
- fragIndexStart = Math.min(idx, fragIndexStart)
514
- return true
515
- } else if (nowTime <= timeEnd && timeEnd < nextTime) {
516
- fragIndexEnd = Math.min(idx, fragIndexEnd)
517
- return false
518
- } else {
519
- return true
518
+ let videoFlags = 0xf01
519
+ let framesIndex = self.videoKeyFrames.map((item) => item.idx)
520
+ let _samples = self.getSamplesByOrders('video', framesIndex[fragIndex], framesIndex[fragIndex + 1])
521
+ let samples = _samples.map((item, idx) => {
522
+ return {
523
+ size: item.size,
524
+ duration: item.time.duration,
525
+ offset: item.time.offset,
526
+ buffer: new Uint8Array(mdatData.slice(item.offset - start, item.offset - start + item.size)),
527
+ key: idx === 0,
528
+ idx: item.idx
520
529
  }
521
530
  })
522
- if (!fragIndexEnd) {
523
- fragIndexEnd = videoFrames.length
524
- }
525
- return self.loadFragmentForCut(fragIndexStart, fragIndexEnd)
526
- }
527
- loadFragmentForCut (fragIndexStart, fragIndexEnd) {
528
- let start,
529
- end
530
- let videoStartFrame = this.videoKeyFrames[fragIndexStart]
531
- let audioStartFrame = this.getSamplesByOrders('audio', this.audioKeyFrames[fragIndexStart].order, 0)
532
- start = Math.min(videoStartFrame.offset, audioStartFrame.offset)
533
- let videoEndFrame = this.videoKeyFrames[fragIndexEnd]
534
- let audioEndFrame = this.getSamplesByOrders('audio', this.audioKeyFrames[fragIndexEnd].order, 0)
535
- end = Math.max(videoEndFrame.offset, audioEndFrame.offset)
536
- let self = this
537
- if (window.isNaN(start) || (end !== undefined && window.isNaN(end))) {
538
- self.emit('error', new Errors('parse', '', { line: 366, handle: '[MP4] loadFragment', url: self.url }))
539
- return false
540
- }
541
- return this.getData(
542
- start + self.mdatStart, end
543
- ? self.mdatStart + end
544
- : '').then((dat) => {
545
- return self.createFragmentForCut(new Uint8Array(dat), start, fragIndexStart, end, fragIndexEnd)
531
+ return this.addFragment({
532
+ id: 1,
533
+ time: _samples[0].time.time,
534
+ firstFlags: 0x2000000,
535
+ flags: videoFlags,
536
+ samples,
537
+ sampleOffset: _samples[0].idx,
538
+ fragIndex
546
539
  })
547
540
  }
548
- createFragmentForCut (mdatData, start, fragIndexStart, end, fragIndexEnd) {
541
+ getAudioBuffer(mdatData, start, fragIndex) {
542
+
549
543
  let self = this
550
- let resBuffers = []
551
- {
552
- let framesIndex = self.videoKeyFrames.map((item) => item.idx)
553
- let _samples = self.getSamplesByOrders('video', framesIndex[fragIndexStart], framesIndex[fragIndexEnd])
554
- let samples = _samples.map((item, idx) => {
555
- return {
556
- size: item.size,
557
- duration: item.time.duration,
558
- offset: item.time.offset,
559
- buffer: new Uint8Array(mdatData.slice(item.offset - start, item.offset - start + item.size)),
560
- key: idx === 0
561
- }
562
- })
563
- resBuffers.push(this.addFragment({id: 1, time: 0, firstFlags: 0x2000000, flags: 0xf01, samples}))
564
- }
544
+ let audioFlags = 0x701
545
+
565
546
  let _samples = this.getSamplesByOrders(
566
- 'audio', this.audioKeyFrames[fragIndexStart].order, this.audioKeyFrames[fragIndexEnd]
567
- ? this.audioKeyFrames[fragIndexEnd].order
547
+ 'audio', this.audioKeyFrames[fragIndex].order, this.audioKeyFrames[fragIndex + 1]
548
+ ? this.audioKeyFrames[fragIndex + 1].order
568
549
  : undefined)
569
550
  let samples = _samples.map((item, idx) => {
570
551
  return {
@@ -575,22 +556,60 @@ class MP4 {
575
556
  key: idx === 0
576
557
  }
577
558
  })
578
- resBuffers.push(this.addFragment({id: 2, time: 0, firstFlags: 0x00, flags: 0x701, samples: samples}))
579
-
580
- let bufferSize = 0
581
- resBuffers.every(item => {
582
- bufferSize += item.byteLength
583
- return true
559
+ return this.addFragment({
560
+ id: 2,
561
+ time: _samples[0].time.time,
562
+ firstFlags: 0x00,
563
+ flags: audioFlags,
564
+ samples,
565
+ sampleOffset: _samples[0].idx,
566
+ fragIndex
584
567
  })
585
- let buffer = new Uint8Array(bufferSize)
568
+ }
569
+ createFragment (mdatData, start, fragIndex) {
570
+ let self = this
586
571
 
587
- let offset = 0
588
- resBuffers.every(item => {
589
- buffer.set(item, offset)
590
- offset += item.byteLength
591
- return true
572
+ let resBuffers = []
573
+ let promises = [
574
+ self.getVideoBuffer(mdatData, start, fragIndex)
575
+ ]
576
+ if (this.audioTrak) {
577
+ promises.push(self.getAudioBuffer(mdatData, start, fragIndex))
578
+ }
579
+ return Promise.all(promises)
580
+ .then(buffers => {
581
+ resBuffers.push(buffers[0])
582
+ if (buffers && buffers[1]) {
583
+ resBuffers.push(buffers[1])
584
+ }
585
+ let bufferSize = 0
586
+ resBuffers.every(item => {
587
+ bufferSize += item.byteLength
588
+ return true
589
+ })
590
+ let buffer = new Uint8Array(bufferSize)
591
+ let offset = 0
592
+ resBuffers.every(item => {
593
+ buffer.set(item, offset)
594
+ offset += item.byteLength
595
+ return true
596
+ })
597
+ return buffer
592
598
  })
593
- return Promise.resolve(buffer)
599
+ }
600
+
601
+ update(url){
602
+ this.url = url;
603
+ }
604
+
605
+ destroy(){
606
+ if(this.hasDestroyed){
607
+ return;
608
+ }
609
+ for (let k in this) {
610
+ delete this[k]
611
+ }
612
+ this.hasDestroyed = true;
594
613
  }
595
614
  }
596
615