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/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,19 +162,14 @@ class MP4 {
125
162
  }
126
163
  }
127
164
  })
128
- this.videoTrak = Merge({}, videoTrak)
129
- if(!audioTrak){
130
- FMP4.videoOnly = this.videoOnly = true
131
- }
132
- if(!this.videoOnly) {
133
- this.audioTrak = Merge({}, audioTrak)
134
- }
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
135
170
  let mdat = this._boxes.find(item => item.type === 'mdat')
136
171
  let videoDuration = util.seekTrakDuration(videoTrak, videoTimeScale)
137
- let audioDuration
138
- if(!this.videoOnly) {
139
- audioDuration = util.seekTrakDuration(audioTrak, audioTimeScale)
140
- }
172
+ let audioDuration = audioTrak ? util.seekTrakDuration(audioTrak, audioTimeScale) : videoDuration
141
173
  this.mdatStart = mdat.start
142
174
  let vf = this.videoKeyFrames
143
175
  let videoKeyFramesLength = vf.length - 1
@@ -150,52 +182,54 @@ class MP4 {
150
182
  } else {
151
183
  this.timeRage.push([
152
184
  item.time.time / videoTimeScale,
153
- -1
185
+ mvhd.duration / mvhd.timeScale
154
186
  ])
155
187
  }
156
188
  })
157
189
  this.meta = {
158
190
  videoCodec,
191
+ audioCodec,
159
192
  createTime: mvhd.createTime,
160
193
  modifyTime: mvhd.modifyTime,
161
- duration: videoDuration,
194
+ duration: mvhd.duration / mvhd.timeScale,
162
195
  timeScale: mvhd.timeScale,
163
196
  videoDuration,
164
197
  videoTimeScale,
165
- endTime: videoDuration,
198
+ audioDuration,
199
+ audioTimeScale,
200
+ endTime: Math.min(videoDuration, audioDuration),
201
+ vps,
166
202
  sps,
167
203
  pps,
168
204
  width,
169
205
  height,
170
206
  profile,
171
- pixelRatio: [
172
- 1, 1
173
- ],
207
+ pixelRatio,
174
208
  channelCount,
175
209
  sampleRate,
176
- audioConfig: decoderConfig
177
- }
178
- if(!this.videoOnly) {
179
- this.meta.audioCodec = audioCodec
180
- this.meta.audioDuration = audioDuration
181
- this.meta.audioTimeScale = audioTimeScale
182
- this.meta.duration = mvhd.duration / mvhd.timeScale
183
- 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
184
220
  }
221
+ this.emit('metaReady', this.meta)
185
222
  }
186
223
 
187
224
  /**
188
- * [init 实例的初始化,主要是获取视频的MOOV元信息]
189
- */
225
+ * [init 实例的初始化,主要是获取视频的MOOV元信息]
226
+ */
190
227
  init () {
191
228
  let self = this
192
- self.getData().then((res) => {
229
+ self.getData().then(res => {
193
230
  let parsed
194
-
195
231
  let moovStart = 0
196
-
197
232
  let moov
198
-
199
233
  let boxes
200
234
  try {
201
235
  parsed = new Parser(res)
@@ -220,7 +254,13 @@ class MP4 {
220
254
  if (nextBox) {
221
255
  if (nextBox.type === 'moov') {
222
256
  self.getData(moovStart, moovStart + nextBox.size + 28).then(res => {
223
- let parsed = new Parser(res)
257
+ let parsed
258
+ // try {
259
+ parsed = new Parser(res)
260
+ // }catch(e) {
261
+
262
+ // }
263
+
224
264
  self._boxes = self._boxes.concat(parsed.boxes)
225
265
  moov = parsed.boxes.filter(box => box.type === 'moov')
226
266
  if (moov.length) {
@@ -267,7 +307,8 @@ class MP4 {
267
307
  let stsz = util.findBox(trak, 'stsz') // sample-size
268
308
  let stts = util.findBox(trak, 'stts') // sample-time
269
309
  let stco = util.findBox(trak, 'stco') // chunk-offset
270
- 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;
271
312
  let mdatStart = this.mdatStart
272
313
  let samples = []
273
314
  end = end !== undefined
@@ -278,8 +319,8 @@ class MP4 {
278
319
  samples.push({
279
320
  idx: item,
280
321
  size: stsz.entries[item],
281
- time: util.seekSampleTime(stts, ctts, item, trak.time_offset),
282
- 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)
283
324
  })
284
325
  })
285
326
  } else if (end !== 0) {
@@ -287,16 +328,17 @@ class MP4 {
287
328
  samples.push({
288
329
  idx: i,
289
330
  size: stsz.entries[i],
290
- time: util.seekSampleTime(stts, ctts, i, trak.time_offset),
291
- 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)
292
333
  })
293
334
  }
294
335
  } else {
336
+ let offset = util.seekSampleOffset(stsc, stco, stsz, start, mdatStart, stscObj)
295
337
  samples = {
296
338
  idx: start,
297
339
  size: stsz.entries[start],
298
- time: util.seekSampleTime(stts, ctts, start, trak.time_offset),
299
- offset: util.seekSampleOffset(stsc, stco, stsz, start, mdatStart)
340
+ time: util.seekSampleTime(stts, cttsObj, start),
341
+ offset: offset
300
342
  }
301
343
  }
302
344
  return samples
@@ -308,7 +350,33 @@ class MP4 {
308
350
  }
309
351
  let videoTrak = this.videoTrak
310
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
+
311
378
  let frames = this.getSamplesByOrders('video', stss.entries.map(item => item - 1))
379
+ this._stssObj = stss;
312
380
  this._videoFrames = frames
313
381
  return frames
314
382
  }
@@ -320,6 +388,16 @@ class MP4 {
320
388
  let videoScale = util.findBox(this.videoTrak, 'mdhd').timescale
321
389
  let audioScale = util.findBox(this.audioTrak, 'mdhd').timescale
322
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
+ }
323
401
  let videoFrames = this.videoKeyFrames
324
402
  let audioIndex = []
325
403
  audioIndex = videoFrames.map(item => {
@@ -329,29 +407,33 @@ class MP4 {
329
407
  return this._audioFrames
330
408
  }
331
409
 
332
- packMeta () {
410
+ packMeta() {
333
411
  if (!this.meta) {
334
412
  return
335
413
  }
336
414
  let buffer = new Buffer()
337
415
  buffer.write(FMP4.ftyp())
338
416
  buffer.write(FMP4.moov(this.meta))
339
- this.cache.write(buffer.buffer)
417
+ // this.cache.write(buffer.buffer)
340
418
  return buffer.buffer
341
419
  }
342
420
 
343
- seek (time) {
344
- let timeStart = time * this.meta.videoTimeScale
345
- 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
+ }
346
430
 
431
+ getFragmentIdx(time){
432
+ let timeStart = Math.round(time * this.meta.videoTimeScale)
433
+ let fragIndex
347
434
  let videoFrames = this.videoKeyFrames
348
- let audioFrames
349
- if(!this.videoOnly) {
350
- audioFrames = this.audioKeyFrames
351
- }
352
435
  videoFrames.every((item, idx) => {
353
436
  let nowTime = item.time.time
354
-
355
437
  let nextTime = videoFrames[idx + 1]
356
438
  ? videoFrames[idx + 1].time.time
357
439
  : Number.MAX_SAFE_INTEGER
@@ -362,10 +444,10 @@ class MP4 {
362
444
  return true
363
445
  }
364
446
  })
365
- if(!this.videoOnly) {
447
+ if (this.audioTrak) {
448
+ let audioFrames = this.audioKeyFrames
366
449
  audioFrames.every((item, idx) => {
367
450
  let nowTime = item.startTime
368
-
369
451
  let nextTime = audioFrames[idx + 1]
370
452
  ? audioFrames[idx + 1].startTime
371
453
  : Number.MAX_SAFE_INTEGER
@@ -377,197 +459,93 @@ class MP4 {
377
459
  }
378
460
  })
379
461
  }
380
- if (this.bufferCache.has(fragIndex)) {
381
- return Promise.resolve(null)
382
- } else {
383
- return this.loadFragment(fragIndex)
384
- }
462
+ return fragIndex;
385
463
  }
386
- loadFragment (fragIndex) {
387
- let start,
388
- 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) {
389
472
  let videoFrame = this.videoKeyFrames[fragIndex]
390
- let audioFrame
391
- start = videoFrame.offset
392
- if(!this.videoOnly) {
393
- audioFrame = this.getSamplesByOrders('audio', this.audioKeyFrames[fragIndex].order, 0)
394
- 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)
395
478
  }
396
479
  if (fragIndex < this.videoKeyFrames.length - 1) {
397
480
  let videoNextFrame = this.videoKeyFrames[fragIndex + 1]
398
- let audioNextFrame
399
481
  end = videoNextFrame.offset
400
- if(!this.videoOnly) {
401
- audioNextFrame = this.getSamplesByOrders('audio', this.audioKeyFrames[fragIndex + 1].order, 0)
402
- 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)
403
485
  }
404
486
  }
405
- let self = this
406
487
  if (window.isNaN(start) || (end !== undefined && window.isNaN(end))) {
407
- self.emit('error', new Errors('parse', '', { line: 366, handle: '[MP4] loadFragment', url: self.url }))
408
- return false
409
- }
410
- if (this.bufferCache.has(fragIndex)) {
411
- return Promise.resolve(null)
412
- } else {
413
- return this.getData(
414
- start + self.mdatStart, end
415
- ? self.mdatStart + end
416
- : '').then((dat) => {
417
- return self.createFragment(new Uint8Array(dat), start, fragIndex)
418
- })
488
+ this.emit('error', new Errors('parse', '', { line: 366, handle: '[MP4] loadFragment', url: this.url }))
489
+ return [0, 0]
419
490
  }
491
+ return [start + this.mdatStart, end ? this.mdatStart + end : '']
420
492
  }
421
- addFragment (data) {
422
- let buffer = new Buffer()
423
- buffer.write(FMP4.moof(data))
424
- buffer.write(FMP4.mdat(data))
425
- this.cache.write(buffer.buffer)
426
- return buffer.buffer
427
- }
428
- createFragment (mdatData, start, fragIndex) {
493
+ loadFragment (fragIndex) {
429
494
  let self = this
430
- let resBuffers = []
431
- this.bufferCache.add(fragIndex)
432
- {
433
- let framesIndex = self.videoKeyFrames.map((item) => item.idx)
434
- let _samples = self.getSamplesByOrders('video', framesIndex[fragIndex], framesIndex[fragIndex + 1])
435
- let samples = _samples.map((item, idx) => {
436
- return {
437
- size: item.size,
438
- duration: item.time.duration,
439
- offset: item.time.offset,
440
- buffer: new Uint8Array(mdatData.slice(item.offset - start, item.offset - start + item.size)),
441
- key: idx === 0
442
- }
443
- })
444
- resBuffers.push(this.addFragment({id: 1, time: _samples[0].time.time, firstFlags: 0x2000000, flags: 0xf01, samples}))
495
+ let range = this.getFragRange(fragIndex)
496
+ if(range === [0, 0]) {
497
+ debugger
498
+ return false;
445
499
  }
446
- if(!this.videoOnly) {
447
- let _samples = this.getSamplesByOrders(
448
- 'audio', this.audioKeyFrames[fragIndex].order, this.audioKeyFrames[fragIndex + 1]
449
- ? this.audioKeyFrames[fragIndex + 1].order
450
- : undefined)
451
- let samples = _samples.map((item, idx) => {
452
- return {
453
- size: item.size,
454
- duration: item.time.duration,
455
- offset: item.time.offset,
456
- buffer: new Uint8Array(mdatData.slice(item.offset - start, item.offset - start + item.size)),
457
- key: idx === 0
458
- }
459
- })
460
- resBuffers.push(this.addFragment({id: 2, time: _samples[0].time.time, firstFlags: 0x00, flags: 0x701, samples: samples}))
461
- }
462
-
463
- let bufferSize = 0
464
- resBuffers.every(item => {
465
- bufferSize += item.byteLength
466
- return true
500
+ return this.getData(range[0], range[1]).then((dat) => {
501
+ return self.createFragment(new Uint8Array(dat), range[0] - this.mdatStart, fragIndex)
467
502
  })
468
- let buffer = new Uint8Array(bufferSize)
469
-
470
- let offset = 0
471
- resBuffers.every(item => {
472
- buffer.set(item, offset)
473
- offset += item.byteLength
474
- return true
503
+ .then(buf => {
504
+ return buf
475
505
  })
476
- return Promise.resolve(buffer)
477
506
  }
478
-
479
- download () {
480
- // 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
+ })
481
515
  }
482
-
483
- cut (start, end) {
516
+ getVideoBuffer(mdatData, start, fragIndex) {
484
517
  let self = this
485
- this.bufferCache.clear()
486
- let timeStart = start * this.meta.videoTimeScale
487
- let timeEnd = end * this.meta.videoTimeScale
488
- let fragIndexStart
489
- let fragIndexEnd
490
-
491
- let videoFrames = this.videoKeyFrames
492
- let audioFrames = this.audioKeyFrames
493
- videoFrames.every((item, idx) => {
494
- let nowTime = item.time.time
495
-
496
- let nextTime = videoFrames[idx + 1]
497
- ? videoFrames[idx + 1].time.time
498
- : Number.MAX_SAFE_INTEGER
499
- if (nowTime <= timeStart && timeStart < nextTime) {
500
- fragIndexStart = idx
501
- return true
502
- } else if (nowTime <= timeEnd && timeEnd < nextTime) {
503
- fragIndexEnd = idx
504
- return false
505
- } else {
506
- return true
507
- }
508
- })
509
- audioFrames.every((item, idx) => {
510
- let nowTime = item.startTime
511
-
512
- let nextTime = audioFrames[idx + 1]
513
- ? audioFrames[idx + 1].startTime
514
- : Number.MAX_SAFE_INTEGER
515
- if (nowTime <= timeStart && timeStart < nextTime) {
516
- fragIndexStart = Math.min(idx, fragIndexStart)
517
- return true
518
- } else if (nowTime <= timeEnd && timeEnd < nextTime) {
519
- fragIndexEnd = Math.min(idx, fragIndexEnd)
520
- return false
521
- } else {
522
- 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
523
529
  }
524
530
  })
525
- if (!fragIndexEnd) {
526
- fragIndexEnd = videoFrames.length
527
- }
528
- return self.loadFragmentForCut(fragIndexStart, fragIndexEnd)
529
- }
530
- loadFragmentForCut (fragIndexStart, fragIndexEnd) {
531
- let start,
532
- end
533
- let videoStartFrame = this.videoKeyFrames[fragIndexStart]
534
- let audioStartFrame = this.getSamplesByOrders('audio', this.audioKeyFrames[fragIndexStart].order, 0)
535
- start = Math.min(videoStartFrame.offset, audioStartFrame.offset)
536
- let videoEndFrame = this.videoKeyFrames[fragIndexEnd]
537
- let audioEndFrame = this.getSamplesByOrders('audio', this.audioKeyFrames[fragIndexEnd].order, 0)
538
- end = Math.max(videoEndFrame.offset, audioEndFrame.offset)
539
- let self = this
540
- if (window.isNaN(start) || (end !== undefined && window.isNaN(end))) {
541
- self.emit('error', new Errors('parse', '', { line: 366, handle: '[MP4] loadFragment', url: self.url }))
542
- return false
543
- }
544
- return this.getData(
545
- start + self.mdatStart, end
546
- ? self.mdatStart + end
547
- : '').then((dat) => {
548
- 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
549
539
  })
550
540
  }
551
- createFragmentForCut (mdatData, start, fragIndexStart, end, fragIndexEnd) {
541
+ getAudioBuffer(mdatData, start, fragIndex) {
542
+
552
543
  let self = this
553
- let resBuffers = []
554
- {
555
- let framesIndex = self.videoKeyFrames.map((item) => item.idx)
556
- let _samples = self.getSamplesByOrders('video', framesIndex[fragIndexStart], framesIndex[fragIndexEnd])
557
- let samples = _samples.map((item, idx) => {
558
- return {
559
- size: item.size,
560
- duration: item.time.duration,
561
- offset: item.time.offset,
562
- buffer: new Uint8Array(mdatData.slice(item.offset - start, item.offset - start + item.size)),
563
- key: idx === 0
564
- }
565
- })
566
- resBuffers.push(this.addFragment({id: 1, time: 0, firstFlags: 0x2000000, flags: 0xf01, samples}))
567
- }
544
+ let audioFlags = 0x701
545
+
568
546
  let _samples = this.getSamplesByOrders(
569
- 'audio', this.audioKeyFrames[fragIndexStart].order, this.audioKeyFrames[fragIndexEnd]
570
- ? this.audioKeyFrames[fragIndexEnd].order
547
+ 'audio', this.audioKeyFrames[fragIndex].order, this.audioKeyFrames[fragIndex + 1]
548
+ ? this.audioKeyFrames[fragIndex + 1].order
571
549
  : undefined)
572
550
  let samples = _samples.map((item, idx) => {
573
551
  return {
@@ -578,22 +556,60 @@ class MP4 {
578
556
  key: idx === 0
579
557
  }
580
558
  })
581
- resBuffers.push(this.addFragment({id: 2, time: 0, firstFlags: 0x00, flags: 0x701, samples: samples}))
582
-
583
- let bufferSize = 0
584
- resBuffers.every(item => {
585
- bufferSize += item.byteLength
586
- 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
587
567
  })
588
- let buffer = new Uint8Array(bufferSize)
568
+ }
569
+ createFragment (mdatData, start, fragIndex) {
570
+ let self = this
589
571
 
590
- let offset = 0
591
- resBuffers.every(item => {
592
- buffer.set(item, offset)
593
- offset += item.byteLength
594
- 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
595
598
  })
596
- 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;
597
613
  }
598
614
  }
599
615