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/index.js CHANGED
@@ -1,380 +1,615 @@
1
- import 'core-js/modules/es6.promise.js'
2
- import 'core-js/modules/es7.string.pad-start'
3
1
  import Player from 'xgplayer'
4
2
  import MP4 from './mp4'
5
3
  import MSE from './media/mse'
6
4
  import Task from './media/task'
7
- import Buffer from './fmp4/buffer'
5
+ import { isSupported, isSupportedWithXgmse, isMediaSourceSupported } from './util/isSupport';
6
+ import ProxyPromise from './util/proxyPromise'
7
+ import Timer from './util/timer'
8
+ import { CUSTOM_EVENTS } from './constants'
9
+ import GapJump from './gap_jump';
10
+
11
+ const DESTROYED = 'DESTROYED';
12
+
13
+ const sniffer = Player.sniffer;
8
14
 
9
15
  let isEnded = (player, mp4) => {
10
- if (mp4.meta.endTime - player.currentTime < 2) {
11
- let range = player.getBufferedRange()
12
- if (player.currentTime - range[1] < 0.1) {
16
+ if (mp4.meta.endTime - player.currentTime < 0.5) {
17
+ // let range = player.getBufferedRange(player.buffered2)
18
+ let offsetTime = player.duration - player.currentTime
19
+ if (offsetTime < 0.5) {
13
20
  player.mse.endOfStream()
21
+ player._stopProgress()
14
22
  }
15
23
  }
16
24
  }
17
25
 
18
- let mp4player = function () {
19
- let player = this; let sniffer = Player.sniffer; let util = Player.util
20
- let Errors = Player.Errors; let mainURL; let backupURL
21
- let preloadTime = player.config.preloadTime || 15
22
- let waiterTimer
23
- let url = player.config.url
24
- let rule = player.config.pluginRule || function () { return true }
25
- if (!url) {
26
- player.emit('error', new Errors('other', player.config.vid))
27
- return
28
- }
29
- if (util.typeOf(url) === 'String') {
30
- mainURL = url
31
- } else if (util.typeOf(url) === 'Array' && url.length) {
32
- mainURL = url[0].src
33
- if(url.length > 1) {
34
- backupURL = url[1].src
26
+ class Mp4Player extends Player {
27
+ constructor (options) {
28
+ let hasStartProgress = true;
29
+ if(options.onlyInit || options.videoInit){
30
+ options.onlyInit = true;
31
+ options.autoplay = false;
32
+ options.videoInit = false;
33
+ hasStartProgress = false;
35
34
  }
35
+ super(options);
36
+
37
+ this._pendingPromises = [];
38
+ this._allInitPromise = new ProxyPromise();
39
+ this._maxBufferLength = options.maxBufferLength || 5
40
+ this._playerId = Mp4Player.uniqueId ++;
41
+ this._onBufferedResetFunc = this._onBufferedReset.bind(this);
42
+ this._onSeekingFunc = this._onSeeking.bind(this);
43
+ this._onMp4InitFunc = this._onMp4Init.bind(this);
44
+ this._onWaitingFunc = this._onWaiting.bind(this);
45
+ this._onEndedFunc = this._onEnded.bind(this);
46
+ this._onDestroyFunc = this._onDestroy.bind(this);
47
+ this._replay = this._onReplay.bind(this);
48
+ this._onOnlineHandlerFunc = this._onOnlineHandler.bind(this);
49
+ this._onOfflineHandlerFunc = this._onOfflineHandler.bind(this);
50
+ this._tickInSeconds = options.tickInSeconds || 0.2;
51
+ this._hasStartProgress = hasStartProgress;
52
+ this._hasStartProgressBack = hasStartProgress;
53
+ this.video.addEventListener(CUSTOM_EVENTS.BUFFERED_RESET, this._onBufferedResetFunc);
54
+ this._bindNetworkStateChange();
55
+ this._initMp4Kernal();
56
+
57
+ this.once('ready', () => {
58
+ this.gapJumpInst = new GapJump(this, this.config);
59
+ Player.util.on(this, 'addVideoBufferEnd', () => {
60
+ this.gapJumpInst.onSegmentAppend();
61
+ });
62
+ })
36
63
  }
37
- player.config._mainURL = mainURL
38
- player.config._backupURL = backupURL
39
- let loadData = (i = 0, time = player.currentTime) => {
40
- if (player.timer) {
41
- clearTimeout(player.timer)
42
- }
43
- time = Math.max(time, player.currentTime)
44
- player.timer = setTimeout(function () {
45
- player.mp4.seek(time + i * 0.1).then(buffer => {
46
- if (buffer) {
47
- let mse = player.mse
48
- mse.updating = true
49
- mse.appendBuffer(buffer)
50
- mse.once('updateend', () => {
51
- mse.updating = false
64
+
65
+ _initMp4Kernal(){
66
+ let player = this;
67
+ let rule = player.config.pluginRule || function () { return true }
68
+ if (MSE.isSupported('video/mp4; codecs="avc1.64001E, mp4a.40.5"')) {
69
+ if (!rule.call(player)) {
70
+ return false
71
+ }
72
+ Object.defineProperty(player, 'src', {
73
+ get () {
74
+ return player.currentSrc
75
+ },
76
+ set (url) {
77
+ player.mse.endOfStream()
78
+ player._onDestroy();
79
+ player.config.autoplay = player.autoplay = true
80
+ player.config.url = url
81
+
82
+ player._init(url).then((result) => {
83
+ let mp4 = result[0];
84
+ let mse = result[1]
85
+ player.proxyOnce('canplay', () => {
86
+ player.play()
87
+ player.proxyOn('waiting', player._onWaitingFunc)
88
+ })
89
+ player._startProgress();
90
+ player._onSuperStart(mse.url)
91
+ player.mp4 = mp4
92
+ player.mse = mse
93
+ // player.currentTime = 0
94
+ }, err => {
95
+ player._errorHandle(err)
52
96
  })
53
- }
54
- }, () => {
55
- if (i < 10) {
56
- setTimeout(function () {
57
- loadData(i + 1)
58
- }, 2000)
59
- }
97
+ },
98
+ configurable: true
60
99
  })
61
- }, 50)
62
- }
63
- let init = (url) => {
64
- let mp4 = new MP4(url, player.config)
65
- let mse
66
- return new Promise((resolve, reject) => {
67
- mp4.once('moovReady', () => {
68
- mse = new MSE(mp4.videoOnly ? 'video/mp4; codecs="avc1.64001E"' : 'video/mp4; codecs="avc1.64001E, mp4a.40.5"')
69
- mse.on('sourceopen', function () {
70
- mse.appendBuffer(mp4.packMeta())
71
- mse.once('updateend', loadData.bind(player))
72
- })
73
- resolve([mp4, mse])
74
- })
75
- mp4.on('error', (e) => {
76
- reject(e)
77
- })
78
- })
79
- }
80
- if (['chrome', 'firfox', 'safari'].some(item => item === sniffer.browser) && MSE.isSupported('video/mp4; codecs="avc1.64001E, mp4a.40.5"')) {
81
- player._start = player.start
82
- if (!rule.call(player)) {
83
- return false
100
+
101
+ player.proxyOn('ended', player._onEndedFunc)
102
+
103
+ player.proxyOnce('destroy', player._onDestroyFunc)
104
+
105
+ if (player.config.videoInit || player.config.onlyInit){
106
+ player.start(player.config.url)
107
+ }
84
108
  }
109
+ }
85
110
 
86
- let errorHandle = (player, err) => {
87
- err.vid = player.config.vid
88
- err.url = player.src
89
- if (err.errd && typeof err.errd === 'object') {
90
- if (player.mp4) {
91
- err.errd.url = player.mp4.url
92
- err.url = player.mp4.url
93
- player.mp4.canDownload = false
94
- }
95
- }
96
- player.emit('DATA_REPORT', err)
97
- Task.clear()
98
- if (player.mp4 && player.mp4.bufferCache) {
99
- player.mp4.bufferCache.clear()
111
+ start(url) {
112
+ let player = this;
113
+ url = url ? url : player.config.url;
114
+ if (player.config.autoplay && Player.sniffer.browser == 'chrome' && !Player.util.hasClass(player.root, 'xgplayer-is-enter')) {
115
+ Player.util.addClass(player.root, 'xgplayer-is-enter')
116
+ }
117
+ player.proxyOnce('error', () => {
118
+ if (Player.util.hasClass(player.root, 'xgplayer-is-enter')) {
119
+ Player.util.removeClass(player.root, 'xgplayer-is-enter')
100
120
  }
101
- if (player.currentTime) {
102
- player._currentTime = player.currentTime
121
+ })
122
+ player.proxyOn('timeupdate', function () {
123
+ if (Player.util.hasClass(player.root, 'xgplayer-isloading')) {
124
+ Player.util.removeClass(player.root, 'xgplayer-isloading')
103
125
  }
104
- if (player._start) {
105
- player.start = player._start
106
- player._start = null
126
+ })
127
+ player.proxyOnce('canplay', () => {
128
+ if (Player.util.hasClass(player.root, 'xgplayer-is-enter')) {
129
+ Player.util.removeClass(player.root, 'xgplayer-is-enter')
107
130
  }
108
- player.switchURL = null
109
- player._replay = null
110
-
111
- // player.off('timeupdate', timeupdateFunc)
112
- clearInterval(player.mp4ProgressTimer)
113
- player.off('seeking', seekingFunc)
114
- player.off('pause', pauseFunc)
115
- player.off('playing', playingFunc)
116
- player.off('waiting', waitingFunc)
117
- player.off('ended', endedFunc)
118
- player.off('destroy', destroyFunc)
119
-
120
- if (err.errt === 'network' && player.config._backupURL) {
121
- player.src = player.config._backupURL
122
- } else {
123
- player.src = player.config._mainURL
131
+ // safari decoder time offset
132
+ if (sniffer.browser === 'safari' && player.buffered && player.config.autoplay) {
133
+ let start = player.buffered.start(0)
134
+ player.currentTime = start + 0.1
124
135
  }
125
- player.once('canplay', () => {
126
- if (player._currentTime) {
127
- player.currentTime = player._currentTime
128
- }
129
- player.play()
130
- })
131
- }
136
+ })
132
137
 
133
- player.start = function (url = mainURL) {
134
- init(url).then((result) => {
135
- player.once('canplay', () => {
138
+ let initPromise = player._init(url)
139
+ initPromise.id = 'init'
140
+ player._addPendingPromise(initPromise)
141
+ initPromise.then(result => {
142
+
143
+ player._allInitPromise.resolve();
144
+ player._hasInited = true;
145
+ player._removePendingPromise(initPromise);
146
+ let mp4 = result[0]; let mse = result[1]
147
+ if(player.config.autoplay) {
148
+ player.proxyOnce('canplay', () => {
136
149
  player.play()
137
150
  })
138
- let mp4 = result[0]; let mse = result[1]
139
- player._start(mse.url)
140
- player.mp4 = mp4
141
- player.mse = mse
142
- mp4.on('error', err => {
143
- errorHandle(player, err)
144
- })
145
- }, err => {
146
- player._start(url)
147
- errorHandle(player, err)
148
- })
149
- player.once('canplay', () => {
150
- // safari decoder time offset
151
- if (sniffer.browser === 'safari' && player.buffered) {
152
- let start = player.buffered.start(0)
153
- player.currentTime = start + 0.1
154
- }
151
+ }
152
+ player._onSuperStart(mse.url)
153
+ player.mp4 = mp4
154
+ player.mse = mse
155
+ Player.util.on(mp4, 'error', err => {
156
+ player._errorHandle(err)
155
157
  })
158
+ player.proxyOn('seeking', player._onSeekingFunc)
159
+ player.proxyOnce('playing', player._onMp4InitFunc)
160
+ player.proxyOn('waiting', player._onWaitingFunc)
161
+ // if(!player.config.onlyInit || player._hasStartProgressBack){
162
+ player._startProgress();
163
+ // }
164
+ }, err => {
165
+ if(err !== DESTROYED){
166
+ player._onSuperStart(url)
167
+ player._errorHandle(err)
168
+ }
169
+ })
170
+ }
171
+
172
+ switchURL(url){
173
+ let player = this;
174
+ let mp5 = new MP4(url, player.config.xhrSetup, player, player.config.preloadSize, {
175
+ playerId: player._playerId
176
+ })
177
+ let mp4 = player.mp4
178
+ Player.util.on(mp5, 'moovReady', () => {
179
+ let timeRange = mp4.timeRage;
180
+ let curTime = player.currentTime
181
+ timeRange = mp4.timeRage
182
+ let start = timeRange.find(item => item[0] - curTime > 2)[0]
183
+ let end = player.getBufferedRange(player.buffered2)[1]
184
+ if (end - start > 0 && sniffer.browser !== 'safari') {
185
+ player.mse.removeBuffer(start, end)
186
+ }
187
+ if (!Player.util.hasClass(player.root, 'xgplayer-ended')) {
188
+ player.emit('urlchange')
189
+ }
190
+ player.mp4 = mp5
191
+ player.mse.appendBuffer(mp5.packMeta(mp4.meta))
192
+ })
193
+ Player.util.on(mp5, 'error', err => {
194
+ player._errorHandle(err)
195
+ })
196
+ }
197
+
198
+ _onBufferedReset(){
199
+ if(this.mp4 && this.mp4.timeRage) {
200
+ this.mp4.timeRage.forEach(item => {
201
+ // if(item[0] <= time) item.downloaded = false;
202
+ item.downloaded = false;
203
+ });
156
204
  }
205
+ };
157
206
 
158
- player.cut = function (start = 0, end) {
159
- let segment = new Buffer()
160
- let mp4 = new MP4(url, player.config)
161
- return new Promise((resolve, reject) => {
162
- mp4.once('moovReady', () => {
163
- if (!end || end <= start) {
164
- end = start + 15
165
- }
166
- if (end > mp4.meta.duration) {
167
- start = mp4.meta.duration - (end - start)
168
- end = mp4.meta.duration
169
- }
170
- mp4.cut(start, end).then(buffer => {
171
- if (buffer) {
172
- let meta = Player.util.deepCopy({
173
- duration: end - start,
174
- audioDuration: end - start,
175
- endTime: end - start
176
- }, mp4.meta)
177
- meta.duration = end - start
178
- meta.videoDuration = end - start
179
- meta.audioDuration = end - start
180
- meta.endTime = end - start
181
- segment.write(mp4.packMeta(meta), buffer)
182
- resolve(new Blob([segment.buffer], {type: 'video/mp4; codecs="avc1.64001E, mp4a.40.5"'}))
183
- }
184
- })
185
- })
186
- mp4.on('error', (e) => {
187
- reject(e)
188
- })
189
- })
207
+ _onOnlineHandler(){
208
+ if(!this._hasInited){
209
+ this.src = this.config.url;
210
+ }else{
211
+ if(this._hasStartProgressBack){
212
+ this._startProgress();
213
+ }
214
+ this._hasStartProgressBack = false;
190
215
  }
216
+ }
191
217
 
192
- player.switchURL = (url) => {
193
- let mp5 = new MP4(url, player.config)
194
- let mp4 = player.mp4
195
- mp5.on('moovReady', () => {
196
- let timeRange = mp4.timeRage; let curTime = player.currentTime
197
- timeRange = mp4.timeRage
198
- let start = timeRange.find(item => item[0] - curTime > 2)[0]
199
- let end = player.getBufferedRange()[1]
200
- if (end - start > 0 && sniffer.browser !== 'safari') {
201
- player.mse.removeBuffer(start, end)
202
- }
203
- if (!Player.util.hasClass(player.root, 'xgplayer-ended')) {
204
- player.emit('urlchange')
205
- }
206
- player.mp4 = mp5
207
- player.mse.appendBuffer(mp5.packMeta())
208
- })
209
- mp5.on('error', err => {
210
- errorHandle(player, err)
218
+ _onOfflineHandler(){
219
+ if(this._hasStartProgress){
220
+ this._stopProgress();
221
+ this._hasStartProgressBack = true;
222
+ }
223
+ }
224
+
225
+ _bindNetworkStateChange(){
226
+ window.addEventListener('online', this._onOnlineHandlerFunc)
227
+ window.addEventListener('offline', this._onOfflineHandlerFunc)
228
+ }
229
+
230
+ _unbindNetworkStateChange(){
231
+ window.removeEventListener('online', this._onOnlineHandlerFunc)
232
+ window.removeEventListener('offline', this._onOfflineHandlerFunc)
233
+ }
234
+
235
+ _onSuperStart(url){
236
+ super.start(url)
237
+ }
238
+
239
+ _init(url){
240
+ let player = this;
241
+ let promise = new ProxyPromise();
242
+
243
+ player._initMp4(url, promise);
244
+ return promise;
245
+ }
246
+
247
+ _initMse(mp4, meta, promise){
248
+ let player = this;
249
+ const isHvc = meta.videoCodec.indexOf('hvc1') > -1 || (meta.encv && meta.encv.data_format.indexOf('hvc1') > -1)
250
+
251
+ let hasVideo = !!meta.videoCodec
252
+ let hasAudio = !!meta.audioCodec
253
+ let codec
254
+ if(hasVideo && hasAudio){
255
+ codec = isHvc ? 'video/mp4; codecs="hev1.1.6.L93.B0, mp4a.40.5"':'video/mp4; codecs="avc1.64001E, mp4a.40.5"'
256
+ }else if(hasVideo){
257
+ codec = isHvc ? 'video/mp4; codecs="hev1.1.6.L93.B0"':'video/mp4; codecs="avc1.64001E"'
258
+ }else{
259
+ codec = 'video/mp4; codecs="mp4a.40.5"'
260
+ }
261
+
262
+ let mse = new MSE(codec, player.config.mediaType)
263
+ Player.util.on(mse, 'sourceopen', function () {
264
+ const initSeg = mp4.packMeta(mp4.meta);
265
+ mse.appendBuffer(initSeg)
266
+ Player.util.once(mse, 'updateend', function () {
267
+ player._loadData();
211
268
  })
269
+ })
270
+ Player.util.on(mse, 'error', function (e) {
271
+ promise.reject(e)
272
+ })
273
+ promise.resolve([mp4, mse])
274
+ }
275
+
276
+ _initMp4(url, promise){
277
+ let player = this;
278
+ let mp4 = new MP4(url, player.config.xhrSetup, player, player.config.preloadSize, {
279
+ playerId: player._playerId
280
+ })
281
+
282
+ Player.util.once(mp4, 'metaReady', meta => {
283
+ this._initMse(mp4, meta, promise)
284
+ })
285
+
286
+ Player.util.on(mp4, 'error', (e) => {
287
+ promise.reject(e)
288
+ })
289
+ }
290
+
291
+ _loadData(i = 0, time = null){
292
+ if(!navigator.onLine){
293
+ return;
212
294
  }
295
+ let player = this;
296
+ if(!player.mp4){
297
+ return;
298
+ }
299
+ time = time ? time : player.currentTime;
300
+ player.mp4.seek(time + i * 0.1).then(buffer => {
301
+ if (buffer && player.mse) {
302
+ let mse = player.mse
303
+ mse.updating = true
304
+ Player.util.once(mse, 'updateend', () => {
305
+ // if (player.currentTime === 0 && player.video.buffered.length && player.video.buffered.end(player.video.buffered.length - 1) > 0) {
306
+ // player.emit('canplay')
307
+ // }
308
+ mse.updating = false
309
+ player.emit('addVideoBufferEnd');
310
+ })
311
+ mse.appendBuffer(buffer)
312
+ }
313
+ }, () => {
314
+ if (i < 10) {
315
+ setTimeout(function () {
316
+ player._loadData(i + 1)
317
+ }, 2000)
318
+ }
319
+ })
320
+ }
213
321
 
214
- player.playNext = (url) => {
215
- let mp5 = new MP4(url, player.config)
216
- let mp4 = player.mp4
217
- mp5.on('moovReady', () => {
218
- let range = [0, 0]
219
- let buffered = player.video.buffered
220
- let currentTime = player.video.currentTime
221
- let max = 0
222
- if (buffered) {
223
- for (let i = 0, len = buffered.length; i < len; i++) {
224
- range[0] = buffered.start(i)
225
- range[1] = buffered.end(i)
226
- if (range[0] <= currentTime && range[1] <= currentTime) {
227
- max = range[1] > max ? range[1] : max
228
- player.mse.removeBuffer(range[0], range[1])
229
- }
322
+ _onTimeUpdate(){
323
+ let player = this;
324
+ let mse = player.mse;
325
+ let mp4 = player.mp4
326
+ if (mse && !mse.updating && mp4 && mp4.canDownload) {
327
+ let timeRage = mp4.timeRage
328
+ let range = player.getBufferedRange(player.buffered2);
329
+ let cacheMaxTime = player.currentTime + player._maxBufferLength
330
+ if (range[1] - cacheMaxTime > 0) {
331
+ return
332
+ }
333
+ timeRage.every((item, idx) => {
334
+ if(item.downloaded) {
335
+ return true;
336
+ } else if (range[1] === 0) { //当前播放时刻无缓存
337
+ if(item[0] <= player.currentTime && (player.currentTime < item[1] || player.duration - item[1] < 0.5)) {
338
+ player._loadData(0, item[0])
339
+ return false
340
+ } else {
341
+ return true
230
342
  }
231
- }
232
- player.mp4 = mp5
233
- player.mse.appendBuffer(mp5.packMeta())
234
- let flag = true
235
- player.on('timeupdate', function () {
236
- if (flag && mp4.meta.endTime - player.currentTime < 2) {
237
- let range = player.getBufferedRange()
238
- if (player.currentTime - range[1] < 0.1) {
239
- flag = false
240
- player.currentTime = 0
241
- buffered = player.video.buffered
242
- if (buffered) {
243
- for (let i = 0, len = buffered.length; i < len; i++) {
244
- range[0] = buffered.start(i)
245
- range[1] = buffered.end(i)
246
- if (range[0] >= max) {
247
- player.mse.removeBuffer(range[0], range[1])
248
- }
249
- }
250
- }
251
- }
343
+ } else { //当前播放时刻有缓存
344
+ if (item[0] >= range[1] || item[1] - 1 >= range[1] || (range[1] >= item[0] && range[1] <= item[0] + 1)) {
345
+ player._loadData(0, item[0])
346
+ return false
347
+ } else {
348
+ return true
252
349
  }
253
- })
350
+ }
254
351
  })
255
- mp5.on('error', err => {
256
- errorHandle(player, err)
352
+ isEnded(player, mp4)// hack for older webkit
353
+ }
354
+ }
355
+
356
+
357
+ _onWaiting(){
358
+ let player = this;
359
+ let curTime = player.currentTime
360
+ player._onInnerWait(curTime)
361
+ if(curTime + 2 < player.duration) player._onInnerWait(curTime + 2)
362
+ if(curTime - 2 > 0) player._onInnerWait(curTime - 2)
363
+ }
364
+
365
+ _onEnded(){
366
+ this.off('waiting', this._onWaitingFunc)
367
+ this._stopProgress();
368
+ }
369
+
370
+ _onReplay() {
371
+ let player = this;
372
+ player._onDestroy();
373
+ player._init(player.config.url).then((result) => {
374
+ let mp4 = result[0];
375
+ let mse = result[1]
376
+ player._startProgress();
377
+ player._onSuperStart(mse.url)
378
+ player.mp4 = mp4
379
+ player.mse = mse
380
+ // player.currentTime = 0
381
+ player.proxyOnce('canplay', () => {
382
+ player.play()
383
+ player.proxyOn('waiting', player._onWaitingFunc)
257
384
  })
385
+ }, err => {
386
+ player._errorHandle(err)
387
+ })
388
+ }
389
+
390
+ _onDestroy(){
391
+ let player = this;
392
+ player._hasInited = false;
393
+ player._unbindNetworkStateChange();
394
+ Task.clear(player._playerId)
395
+ if (player.mp4) {
396
+ player.mp4.destroy();
397
+ player.mp4 = null;
398
+ }
399
+ if(player.mse){
400
+ player.mse.destroy();
401
+ }
402
+ player.unloadVideo();
403
+ player._stopProgress();
404
+ player.cancelPendingPromises();
405
+ }
406
+
407
+ _errorHandle(err){
408
+ if(err.errt === 'network' || err.errorType === 'network'){
409
+ return;
410
+ }
411
+ if(err.errt === 'parse' || err.errorType === 'parse'){
412
+
413
+ return;
414
+ }
415
+ let player = this;
416
+ err.url = player.src
417
+ if (err.errd && typeof err.errd === 'object') {
418
+ if (player.mp4) {
419
+ err.errd.url = player.mp4.url
420
+ err.url = player.mp4.url
421
+ player.mp4.canDownload = false
422
+ }
423
+ }
424
+ player.emit('DATA_REPORT', err)
425
+ Task.clear(player._playerId)
426
+ if (player.mp4 && player.mp4.bufferCache) {
427
+ player.mp4.bufferCache.clear()
428
+ }
429
+ if (player.currentTime) {
430
+ player._currentTime = player.currentTime
431
+ }
432
+ if (player._start) {
433
+ player.start = player._start
434
+ player._start = null
258
435
  }
436
+ player.switchURL = null
437
+ player._replay = null
438
+
439
+ player.off('seeking', player._onSeekingFunc)
440
+ player.off('playing', player._onMp4InitFunc)
441
+ player.off('waiting', player._onWaitingFunc)
442
+ player.off('ended', player._onEndedFunc)
443
+ player.off('destroy', player._onDestroyFunc)
444
+
445
+ iplayer.emit('error', err)
446
+ player.src = player.config.url
447
+ player.proxyOnce('canplay', () => {
448
+ if (player._currentTime) {
449
+ player.currentTime = player._currentTime
450
+ }
451
+ player.play()
452
+ })
453
+
454
+ }
455
+
456
+ _onSeeking() {
457
+ let curTime = this.currentTime
458
+ this._onCheckLoad(curTime);
459
+ isEnded(this, this.mp4)
460
+ }
259
461
 
260
- let timeupdateFunc = function () {
261
- let mse = player.mse; let mp4 = player.mp4
262
- if (mse && !mse.updating && mp4.canDownload) {
263
- let timeRage = mp4.timeRage
264
- let range = player.getBufferedRange(); let cacheMaxTime = player.currentTime + preloadTime
265
- if (range[1] - cacheMaxTime > 0) {
266
- return
462
+ _onInnerWait(curTime) {
463
+ this._onCheckLoad(curTime);
464
+ }
465
+
466
+ _onCheckLoad(curTime){
467
+ let player = this;
468
+ let buffered = player.buffered2 || player.buffered;
469
+ let hasBuffered = false;
470
+ let timeRage = player.mp4.timeRage
471
+ if (buffered.length) {
472
+ for (let i = 0, len = buffered.length; i < len; i++) {
473
+ if (curTime >= buffered.start(i) && curTime <= buffered.end(i)) {
474
+ hasBuffered = true
475
+ break
267
476
  }
477
+ }
478
+ if (!hasBuffered) {
268
479
  timeRage.every((item, idx) => {
269
- let start = item[0]; let end = item[1]; let center = (start + end) / 2
270
- if (range[1] === 0) {
480
+ if (item[0] <= curTime && (item[1] > curTime || player.duration - item[1] < 0.5)) {
481
+ player._loadData(0, item[0])
271
482
  return false
272
483
  } else {
273
- if (center > range[1] && !mp4.bufferCache.has(idx)) {
274
- loadData(0, center)
275
- } else {
276
- return true
277
- }
484
+ return true
278
485
  }
279
486
  })
280
- isEnded(player, mp4)// hack for older webkit
281
487
  }
282
- }
283
-
284
- // player.on('timeupdate', timeupdateFunc)
285
- player.mp4ProgressTimer = setInterval(timeupdateFunc, player.config.mp4ProgressTimer || 300)
286
-
287
- let seekingFunc = function () {
288
- let buffered = player.buffered; let hasBuffered = false; let curTime = player.currentTime
289
- Task.clear()
290
- if (buffered.length) {
291
- for (let i = 0, len = buffered.length; i < len; i++) {
292
- if (curTime >= buffered.start(i) && curTime <= buffered.end(i)) {
293
- hasBuffered = true
294
- break
295
- }
488
+ } else {
489
+ timeRage.every((item, idx) => {
490
+ if (item[0] <= curTime && item[1] > curTime) {
491
+ player._loadData(0, item[0])
492
+ return false
493
+ } else {
494
+ return true
296
495
  }
297
- if (!hasBuffered) {
298
- loadData(0, curTime)
299
- }
300
- } else {
301
- loadData(0, player.currentTime)
302
- }
496
+ })
303
497
  }
304
- player.on('seeking', seekingFunc)
498
+ }
305
499
 
306
- let pauseFunc = function () {
307
- Task.clear()
500
+ _onMp4Init(){
501
+ let player = this;
502
+ if(player.config.mp4Init) {
503
+ player.pause()
308
504
  }
309
- player.on('pause', pauseFunc)
505
+ // if(player.config.onlyInit){
506
+ // player._startProgress();
507
+ // }
508
+ }
310
509
 
311
- let playingFunc = function () {
312
- if (waiterTimer) {
313
- clearTimeout(waiterTimer)
314
- }
510
+ _stopProgress(){
511
+ let player = this;
512
+ this._hasStartProgress = false;
513
+ if(player._requestTimer){
514
+ player._requestTimer.stop();
515
+ player._requestTimer = null;
315
516
  }
316
- player.on('playing', playingFunc)
517
+ }
317
518
 
318
- let waitingFunc = function () {
319
- let mp4 = player.mp4
320
- if (!mp4 || !mp4.meta) {
321
- return
519
+ _startProgress(){
520
+ let player = this;
521
+ player._stopProgress();
522
+ player._requestTimer = new Timer(()=>{
523
+ if(player._requestTimer) {
524
+ player._onTimeUpdate()
322
525
  }
323
- let range = player.getBufferedRange()
324
- let duration = mp4.meta.videoDuration
325
- if (duration - player.currentTime < 0.5 && duration - range[1] < 0.5) {
326
- player.mse.endOfStream()
327
- } else {
328
- loadData(0, range[1] + 1)
329
- waiterTimer = setTimeout(function () {
330
- let buffered = player.buffered; let start
331
- for (let i = 0, len = buffered.length; i < len; i++) {
332
- start = buffered.start(i)
333
- if (start >= player.currentTime) {
334
- player.currentTime = start
335
- break
336
- }
337
- }
338
- }, 1500)
526
+ });
527
+ player._requestTimer.tickEvery(player._tickInSeconds);//200ms
528
+ this._hasStartProgress = true;
529
+ }
530
+
531
+ unloadVideo() {
532
+ let player = this;
533
+ try {
534
+ if (player.video && player.video.src) {
535
+ player.video.removeAttribute('src'); // empty source
536
+ player.video.load();
339
537
  }
538
+ } catch (error) {
539
+ // console.log('unloadVideo error', error)
340
540
  }
341
- player.on('waiting', waitingFunc)
541
+ }
342
542
 
343
- let endedFunc = function () {
344
- player.off('waiting', waitingFunc)
345
- // player.off('timeupdate', timeupdateFunc)
346
- clearInterval(player.mp4ProgressTimer)
543
+ _addPendingPromise(p){
544
+ this._pendingPromises.push(p);
545
+ }
546
+
547
+ _removePendingPromise(p){
548
+ let idx = this._pendingPromises.indexOf(p);
549
+ if(idx > -1){
550
+ this._pendingPromises.splice(idx, 1);
347
551
  }
348
- player.on('ended', endedFunc)
552
+ }
349
553
 
350
- let destroyFunc = function () {
351
- Task.clear()
352
- if (player.timer) {
353
- clearTimeout(player.timer)
354
- }
554
+ onMediaExpired(){
555
+ this._stopProgress();
556
+ this.emit(CUSTOM_EVENTS.MEDIA_EXPIRED);
557
+ }
558
+
559
+ cancelPendingPromises(){
560
+ if(this._pendingPromises.length > 0){
561
+ this._pendingPromises.forEach(promise => {
562
+ promise.reject(DESTROYED)
563
+ })
355
564
  }
356
- player.once('destroy', destroyFunc)
565
+ this._pendingPromises = [];
566
+ }
357
567
 
358
- player._replay = function () {
359
- Task.clear()
360
- player.mp4.bufferCache.clear()
361
- init(player.mp4.url).then((result) => {
362
- let mp4 = result[0]; let mse = result[1]
363
- player._start(mse.url)
364
- player.mp4 = mp4
365
- player.mse = mse
366
- player.currentTime = 0
367
- player.play()
368
- player.once('canplay', () => {
369
- player.on('waiting', waitingFunc)
370
- // player.on('timeupdate', timeupdateFunc)
371
- player.mp4ProgressTimer = setInterval(timeupdateFunc, player.config.mp4ProgressTimer || 300)
372
- })
373
- }, err => {
374
- errorHandle(player, err)
568
+ enableAutoBuffer(start){
569
+ if(start){
570
+ if(!this._allInitPromise){
571
+ return;
572
+ }
573
+ this._allInitPromise.then(()=>{
574
+ this._startProgress();
375
575
  })
576
+ }else{
577
+ this._stopProgress();
578
+ }
579
+ }
580
+
581
+ destroy(){
582
+ if(this.mp4){
583
+ this.mp4.destroy();
584
+ }
585
+ if(this.mse){
586
+ this.mse.destroy();
376
587
  }
588
+ if(this.video) {
589
+ this.video.removeEventListener(CUSTOM_EVENTS.BUFFERED_RESET, this._onBufferedResetFunc);
590
+ }
591
+ super.destroy();
592
+ }
593
+
594
+ emitInitFail(reason){
595
+ this.emit(CUSTOM_EVENTS.INIT_FAIL, reason);
596
+ }
597
+
598
+ emitParseError(){
599
+ this.emit(CUSTOM_EVENTS.PARSE_ERROR);
600
+ }
601
+
602
+ /***
603
+ * @return Promise
604
+ */
605
+ get ready(){
606
+ return this._allInitPromise;
377
607
  }
378
608
  }
609
+ Mp4Player.uniqueId = 1;
610
+ Mp4Player.isSupported = isSupported;
611
+ Mp4Player.isSupportedWithXgmse = isSupportedWithXgmse;
612
+ Mp4Player.isMediaSourceSupported = isMediaSourceSupported;
613
+ Mp4Player.CUSTOM_EVENTS = CUSTOM_EVENTS;
379
614
 
380
- Player.install('mp4player', mp4player)
615
+ export default Mp4Player;