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/media/mse.js CHANGED
@@ -2,31 +2,53 @@ import EventEmitter from 'event-emitter'
2
2
  import Errors from '../error'
3
3
 
4
4
  class MSE {
5
- constructor (codecs = 'video/mp4; codecs="avc1.64001E, mp4a.40.5"') {
6
- let self = this
5
+ constructor (codecs = 'video/mp4; codecs="avc1.64001E, mp4a.40.5"', mediaType) {
7
6
  EventEmitter(this)
8
7
  this.codecs = codecs
9
- this.mediaSource = new window.MediaSource()
8
+ this.mediaSource = new window.MediaSource(mediaType)
10
9
  this.url = window.URL.createObjectURL(this.mediaSource)
11
10
  this.queue = []
12
11
  this.updating = false
13
- this.mediaSource.addEventListener('sourceopen', function () {
14
- self.sourceBuffer = self.mediaSource.addSourceBuffer(self.codecs)
15
- self.sourceBuffer.addEventListener('error', function (e) {
16
- self.emit('error', new Errors('mse', '', {line: 16, handle: '[MSE] constructor sourceopen', msg: e.message}))
17
- })
18
- self.sourceBuffer.addEventListener('updateend', function (e) {
19
- self.emit('updateend')
20
- let buffer = self.queue.shift()
21
- if (buffer && self.sourceBuffer && !self.sourceBuffer.updating && self.state === 'open') {
22
- self.sourceBuffer.appendBuffer(buffer)
23
- }
24
- })
25
- self.emit('sourceopen')
26
- })
27
- this.mediaSource.addEventListener('sourceclose', function () {
28
- self.emit('sourceclose')
29
- })
12
+ this._hasDestroyed = false;
13
+ this._hasEndOfStream = false;
14
+ this._hasEndOfStreamSuccess = false;
15
+ this._onSourceOpen = this._onSourceOpen.bind(this);
16
+ this._onMediaSourceClose = this._onMediaSourceClose.bind(this);
17
+ this._onSourceBufferError = this._onSourceBufferError.bind(this);
18
+ this._onSourceBufferUpdateEnd = this._onSourceBufferUpdateEnd.bind(this);
19
+ this.mediaSource.addEventListener('sourceopen', this._onSourceOpen);
20
+ this.mediaSource.addEventListener('sourceclose', this._onMediaSourceClose);
21
+ }
22
+
23
+ _onSourceOpen(){
24
+ let self = this;
25
+ self.sourceBuffer = self.mediaSource.addSourceBuffer(self.codecs);
26
+ self.sourceBuffer.addEventListener('error', this._onSourceBufferError);
27
+ self.sourceBuffer.addEventListener('updateend', this._onSourceBufferUpdateEnd);
28
+ self.emit('sourceopen')
29
+ }
30
+
31
+ _onSourceBufferError(e){
32
+ this.emit('error', new Errors('mse', '', {line: 16, handle: '[MSE] constructor sourceopen', msg: e.message}))
33
+ }
34
+
35
+ _onSourceBufferUpdateEnd(){
36
+ let self = this;
37
+ self.emit('updateend');
38
+ if(this._hasEndOfStream && !this._hasEndOfStreamSuccess){
39
+ this._endOfStream();
40
+ return;
41
+ }
42
+ let buffer = self.queue.shift()
43
+ if (buffer && self.sourceBuffer && self.sourceBuffer.updating === false && self.state === 'open') {
44
+ self.sourceBuffer.appendBuffer(buffer)
45
+ } else if(buffer) {
46
+ self.queue.unshift(buffer);
47
+ }
48
+ }
49
+
50
+ _onMediaSourceClose(){
51
+ this.emit('sourceclose')
30
52
  }
31
53
 
32
54
  get state () {
@@ -42,6 +64,8 @@ class MSE {
42
64
  }
43
65
 
44
66
  appendBuffer (buffer) {
67
+ if(!buffer) return;
68
+
45
69
  let sourceBuffer = this.sourceBuffer
46
70
  if (sourceBuffer && !sourceBuffer.updating && this.state === 'open') {
47
71
  sourceBuffer.appendBuffer(buffer)
@@ -53,11 +77,26 @@ class MSE {
53
77
  }
54
78
 
55
79
  removeBuffer (start, end) {
56
- this.sourceBuffer.remove(start, end)
80
+ let sourceBuffer = this.sourceBuffer
81
+ if (sourceBuffer && sourceBuffer.updating === false && this.state === 'open') {
82
+ sourceBuffer.remove(start, end)
83
+ }
57
84
  }
58
85
 
59
86
  endOfStream () {
60
- if (this.state === 'open') {
87
+ this._hasEndOfStream = true;
88
+ if (this.mediaSource.readyState === 'open') {
89
+ if(this.sourceBuffer && !this.sourceBuffer.updating){
90
+ this._hasEndOfStreamSuccess = true;
91
+ this._endOfStream();
92
+ }
93
+
94
+ }
95
+ }
96
+
97
+ _endOfStream(){
98
+ this.queue = [];
99
+ if(this.mediaSource.readyState === 'open'){
61
100
  this.mediaSource.endOfStream()
62
101
  }
63
102
  }
@@ -65,6 +104,22 @@ class MSE {
65
104
  static isSupported (codecs) {
66
105
  return window.MediaSource && window.MediaSource.isTypeSupported(codecs)
67
106
  }
107
+
108
+ destroy(){
109
+ if(this._hasDestroyed){
110
+ return;
111
+ }
112
+ this._hasDestroyed = true;
113
+ window.URL.revokeObjectURL(this.url);
114
+ if(this.mediaSource) {
115
+ this.mediaSource.removeEventListener('sourceclose', this._onMediaSourceClose);
116
+ this.mediaSource.removeEventListener('sourceopen', this._onSourceOpen);
117
+ }
118
+ if(this.sourceBuffer) {
119
+ this.sourceBuffer.removeEventListener('error', this._onSourceBufferError);
120
+ this.sourceBuffer.removeEventListener('updateend', this._onSourceBufferUpdateEnd);
121
+ }
122
+ }
68
123
  }
69
124
 
70
125
  export default MSE
package/src/media/task.js CHANGED
@@ -1,25 +1,64 @@
1
1
  import EventEmitter from 'event-emitter'
2
2
  import Errors from '../error'
3
+ import {CUSTOM_EVENTS, TASK_ERROR, TASK_ERROR_TYPES} from '../constants'
4
+ import getResponseHeaders from '../util/getHeaders';
3
5
 
4
6
  class Task {
5
- constructor (url, range, withCredentials, callback) {
7
+ constructor (url, range, xhrSetup, callback, ext = {}) {
6
8
  EventEmitter(this)
9
+ window.Task = Task
7
10
  this.url = url
8
11
  this.range = range
9
- this.withCredentials = withCredentials
10
- this.id = range.join('-')
11
- this.on = false
12
+ ext.start = range[0]
13
+ ext.end = range[1]
14
+ this.uniqueTag = `${this.url}&range=${range[0]}-${range[1]}`
15
+ this.playerId = ext.playerId;
16
+ //处理重复分片请求,只拦截同一播放器的相同请求
17
+ if (Task.queue.some(item => item.url === url && JSON.stringify(item.range) === JSON.stringify(range) && item.playerId === ext.playerId)) {
18
+ // console.log('task repeat playerid', ext.playerId)
19
+ return;
20
+ }
21
+ this.xhrSetup = xhrSetup
22
+ this.id = this.playerId + range.join('-')
23
+ this.running = false
24
+ this.canceled = false
25
+ this.initialize(url, range, callback);
26
+ }
27
+ initialize(url, range, callback) {
12
28
  let xhr = new window.XMLHttpRequest()
13
29
  xhr.target = this
14
30
  xhr.responseType = 'arraybuffer'
15
31
  xhr.withCredentials = this.withCredentials || false
16
32
  xhr.open('get', url)
33
+ if(typeof this.xhrSetup === 'function') {
34
+ this.xhrSetup(xhr, url)
35
+ }
17
36
  xhr.setRequestHeader('Range', `bytes=${range[0]}-${range[1]}`)
37
+ let self = this;
38
+ xhr.onreadystatechange = function (e) {
39
+ // HEADERS_RECEIVED
40
+ if (xhr.readyState === 2) {
41
+ self.headers = getResponseHeaders(xhr);
42
+ // self.emit('getHeaders', self.headers);
43
+ self.status = xhr.status;
44
+ // self.startDownloadTime = nowTime();
45
+ }
46
+ // OPENED
47
+ if (xhr.readyState === 1) {
48
+ // self.lastTime = nowTime();
49
+ }
50
+ };
18
51
  xhr.onload = function () {
19
52
  if (xhr.status === 200 || xhr.status === 206) {
20
53
  if (callback && callback instanceof Function) {
21
54
  callback(xhr.response)
22
55
  }
56
+ } else{
57
+ if(xhr.status === 403){
58
+ self.emit(CUSTOM_EVENTS.MEDIA_EXPIRED);
59
+ }else{
60
+ self._emitTaskError(TASK_ERROR_TYPES.CODE_ERROR);
61
+ }
23
62
  }
24
63
  xhr.target.remove()
25
64
  }
@@ -30,12 +69,20 @@ class Task {
30
69
  xhr.onabort = function () {
31
70
  xhr.target.remove()
32
71
  }
33
- this.xhr = xhr
34
- Task.queue.push(this)
35
- this.update()
72
+ if (!self.canceled) {
73
+ self.xhr = xhr;
74
+ Task.queue.push(self);
75
+ }
76
+ self.update()
36
77
  }
37
78
  cancel () {
38
79
  this.xhr.abort()
80
+ this._emitTaskError(TASK_ERROR_TYPES.CANCEL);
81
+ this.canceled = true;
82
+ }
83
+
84
+ _emitTaskError(code){
85
+ this.emit(TASK_ERROR, {code , url: this.uniqueTag, readyState: this.xhr.readyState, status: this.xhr.status})
39
86
  }
40
87
 
41
88
  remove () {
@@ -52,8 +99,8 @@ class Task {
52
99
 
53
100
  update () {
54
101
  let Queue = Task.queue
55
- let sended = Queue.filter((item) => item.on)
56
- let wait = Queue.filter(item => !item.on)
102
+ let sended = Queue.filter((item) => item.running)
103
+ let wait = Queue.filter(item => !item.running)
57
104
  let max = Task.limit - sended.length
58
105
  wait.forEach((item, idx) => {
59
106
  if (idx < max) {
@@ -64,25 +111,29 @@ class Task {
64
111
 
65
112
  run () {
66
113
  if (this.xhr.readyState === 1) {
67
- this.on = true
114
+ this.running = true
68
115
  this.xhr.send()
69
116
  } else {
70
117
  this.remove()
71
118
  }
72
119
  }
73
120
 
74
- static clear () {
75
- Task.queue.forEach(item => {
76
- if (item.on) {
77
- item.cancel()
121
+ /***
122
+ * 同时存在多播放器实例,存在问题
123
+ */
124
+ static clear (playerId) {
125
+ let queue = Task.queue;
126
+ for(let i = queue.length - 1; i > -1; i--){
127
+ let item = queue[i];
128
+ if(item.running && item.playerId === playerId){
129
+ item.cancel();
78
130
  }
79
- })
80
- Task.queue.length = 0
131
+ queue.splice(i, 1)
132
+ }
81
133
  }
82
134
  }
83
135
 
84
136
  Task.queue = []
85
137
  Task.limit = 2
86
- window.Task = Task
87
138
 
88
139
  export default Task