@alessmicrosystems/mpegts.js 1.8.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 (121) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +158 -0
  3. package/README_ja.md +153 -0
  4. package/README_zh.md +157 -0
  5. package/d.ts/mpegts.d.ts +524 -0
  6. package/d.ts/src/core/mse-events.d.ts +9 -0
  7. package/d.ts/src/core/transmuxing-events.d.ts +24 -0
  8. package/d.ts/src/demux/aac.d.ts +44 -0
  9. package/d.ts/src/demux/ac3.d.ts +70 -0
  10. package/d.ts/src/demux/av1-parser.d.ts +77 -0
  11. package/d.ts/src/demux/av1.d.ts +11 -0
  12. package/d.ts/src/demux/base-demuxer.d.ts +55 -0
  13. package/d.ts/src/demux/h264.d.ts +40 -0
  14. package/d.ts/src/demux/h265.d.ts +65 -0
  15. package/d.ts/src/demux/klv.d.ts +17 -0
  16. package/d.ts/src/demux/mp3.d.ts +6 -0
  17. package/d.ts/src/demux/mpeg4-audio.d.ts +28 -0
  18. package/d.ts/src/demux/pat-pmt-pes.d.ts +106 -0
  19. package/d.ts/src/demux/patpmt.d.ts +40 -0
  20. package/d.ts/src/demux/pes-private-data.d.ts +14 -0
  21. package/d.ts/src/demux/pgs-data.d.ts +9 -0
  22. package/d.ts/src/demux/scte35.d.ts +250 -0
  23. package/d.ts/src/demux/sei.d.ts +8 -0
  24. package/d.ts/src/demux/smpte2038.d.ts +22 -0
  25. package/d.ts/src/demux/ts-demuxer.d.ts +124 -0
  26. package/d.ts/src/player/live-latency-chaser.d.ts +10 -0
  27. package/d.ts/src/player/live-latency-synchronizer.d.ts +10 -0
  28. package/d.ts/src/player/loading-controller.d.ts +19 -0
  29. package/d.ts/src/player/mse-player.d.ts +30 -0
  30. package/d.ts/src/player/player-engine-dedicated-thread-worker.d.ts +2 -0
  31. package/d.ts/src/player/player-engine-dedicated-thread.d.ts +48 -0
  32. package/d.ts/src/player/player-engine-main-thread.d.ts +50 -0
  33. package/d.ts/src/player/player-engine-worker-cmd-def.d.ts +25 -0
  34. package/d.ts/src/player/player-engine-worker-msg-def.d.ts +54 -0
  35. package/d.ts/src/player/player-engine-worker.d.ts +2 -0
  36. package/d.ts/src/player/player-engine.d.ts +16 -0
  37. package/d.ts/src/player/player-events.d.ts +21 -0
  38. package/d.ts/src/player/seeking-handler.d.ts +22 -0
  39. package/d.ts/src/player/startup-stall-jumper.d.ts +14 -0
  40. package/d.ts/src/utils/typedarray-equality.d.ts +2 -0
  41. package/dist/mpegts.js +3 -0
  42. package/dist/mpegts.js.LICENSE.txt +7 -0
  43. package/dist/mpegts.js.map +1 -0
  44. package/package.json +53 -0
  45. package/src/config.js +67 -0
  46. package/src/core/features.js +88 -0
  47. package/src/core/media-info.js +127 -0
  48. package/src/core/media-segment-info.js +230 -0
  49. package/src/core/mse-controller.js +599 -0
  50. package/src/core/mse-events.ts +28 -0
  51. package/src/core/transmuxer.js +346 -0
  52. package/src/core/transmuxing-controller.js +628 -0
  53. package/src/core/transmuxing-events.ts +43 -0
  54. package/src/core/transmuxing-worker.js +286 -0
  55. package/src/demux/aac.ts +397 -0
  56. package/src/demux/ac3.ts +335 -0
  57. package/src/demux/amf-parser.js +243 -0
  58. package/src/demux/av1-parser.ts +629 -0
  59. package/src/demux/av1.ts +103 -0
  60. package/src/demux/base-demuxer.ts +69 -0
  61. package/src/demux/demux-errors.js +26 -0
  62. package/src/demux/exp-golomb.js +116 -0
  63. package/src/demux/flv-demuxer.js +1854 -0
  64. package/src/demux/h264.ts +187 -0
  65. package/src/demux/h265-parser.js +501 -0
  66. package/src/demux/h265.ts +214 -0
  67. package/src/demux/klv.ts +40 -0
  68. package/src/demux/mp3.ts +7 -0
  69. package/src/demux/mpeg4-audio.ts +45 -0
  70. package/src/demux/pat-pmt-pes.ts +132 -0
  71. package/src/demux/pes-private-data.ts +16 -0
  72. package/src/demux/pgs-data.ts +11 -0
  73. package/src/demux/scte35.ts +723 -0
  74. package/src/demux/sei.ts +99 -0
  75. package/src/demux/smpte2038.ts +89 -0
  76. package/src/demux/sps-parser.js +298 -0
  77. package/src/demux/ts-demuxer.ts +2405 -0
  78. package/src/index.js +4 -0
  79. package/src/io/fetch-stream-loader.js +266 -0
  80. package/src/io/io-controller.js +647 -0
  81. package/src/io/loader.js +134 -0
  82. package/src/io/param-seek-handler.js +85 -0
  83. package/src/io/range-seek-handler.js +52 -0
  84. package/src/io/speed-sampler.js +93 -0
  85. package/src/io/websocket-loader.js +151 -0
  86. package/src/io/xhr-moz-chunked-loader.js +211 -0
  87. package/src/io/xhr-msstream-loader.js +307 -0
  88. package/src/io/xhr-range-loader.js +366 -0
  89. package/src/mpegts.js +95 -0
  90. package/src/player/live-latency-chaser.ts +66 -0
  91. package/src/player/live-latency-synchronizer.ts +79 -0
  92. package/src/player/loading-controller.ts +142 -0
  93. package/src/player/mse-player.ts +150 -0
  94. package/src/player/native-player.js +262 -0
  95. package/src/player/player-engine-dedicated-thread.ts +479 -0
  96. package/src/player/player-engine-main-thread.ts +463 -0
  97. package/src/player/player-engine-worker-cmd-def.ts +62 -0
  98. package/src/player/player-engine-worker-msg-def.ts +102 -0
  99. package/src/player/player-engine-worker.ts +370 -0
  100. package/src/player/player-engine.ts +35 -0
  101. package/src/player/player-errors.js +39 -0
  102. package/src/player/player-events.ts +40 -0
  103. package/src/player/seeking-handler.ts +205 -0
  104. package/src/player/startup-stall-jumper.ts +86 -0
  105. package/src/remux/aac-silent.js +56 -0
  106. package/src/remux/mp4-generator.js +866 -0
  107. package/src/remux/mp4-remuxer.js +778 -0
  108. package/src/utils/browser.js +128 -0
  109. package/src/utils/exception.js +73 -0
  110. package/src/utils/logger.js +140 -0
  111. package/src/utils/logging-control.js +165 -0
  112. package/src/utils/polyfill.js +68 -0
  113. package/src/utils/typedarray-equality.ts +69 -0
  114. package/src/utils/utf8-conv.js +84 -0
  115. package/src/utils/webworkify-webpack.js +202 -0
  116. package/tsconfig.json +16 -0
  117. package/tslint.json +1 -0
  118. package/types/index.d.ts +3 -0
  119. package/types/test-flv.ts +8 -0
  120. package/types/tsconfig.json +24 -0
  121. package/webpack.config.js +55 -0
@@ -0,0 +1,628 @@
1
+ /*
2
+ * Copyright (C) 2016 Bilibili. All Rights Reserved.
3
+ *
4
+ * @author zheng qian <xqq@xqq.im>
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ import EventEmitter from 'events';
20
+ import Log from '../utils/logger.js';
21
+ import Browser from '../utils/browser.js';
22
+ import MediaInfo from './media-info.js';
23
+ import FLVDemuxer from '../demux/flv-demuxer.js';
24
+ import TSDemuxer from '../demux/ts-demuxer';
25
+ import MP4Remuxer from '../remux/mp4-remuxer.js';
26
+ import DemuxErrors from '../demux/demux-errors.js';
27
+ import IOController from '../io/io-controller.js';
28
+ import TransmuxingEvents from './transmuxing-events';
29
+ import {LoaderStatus, LoaderErrors} from '../io/loader.js';
30
+
31
+ // Transmuxing (IO, Demuxing, Remuxing) controller, with multipart support
32
+ class TransmuxingController {
33
+
34
+ constructor(mediaDataSource, config) {
35
+ this.TAG = 'TransmuxingController';
36
+ this._emitter = new EventEmitter();
37
+
38
+ this._config = config;
39
+
40
+ // treat single part media as multipart media, which has only one segment
41
+ if (!mediaDataSource.segments) {
42
+ mediaDataSource.segments = [{
43
+ duration: mediaDataSource.duration,
44
+ filesize: mediaDataSource.filesize,
45
+ url: mediaDataSource.url
46
+ }];
47
+ }
48
+
49
+ // fill in default IO params if not exists
50
+ if (typeof mediaDataSource.cors !== 'boolean') {
51
+ mediaDataSource.cors = true;
52
+ }
53
+ if (typeof mediaDataSource.withCredentials !== 'boolean') {
54
+ mediaDataSource.withCredentials = false;
55
+ }
56
+
57
+ this._mediaDataSource = mediaDataSource;
58
+ this._currentSegmentIndex = 0;
59
+ let totalDuration = 0;
60
+
61
+ this._mediaDataSource.segments.forEach((segment) => {
62
+ // timestampBase for each segment, and calculate total duration
63
+ segment.timestampBase = totalDuration;
64
+ totalDuration += segment.duration;
65
+ // params needed by IOController
66
+ segment.cors = mediaDataSource.cors;
67
+ segment.withCredentials = mediaDataSource.withCredentials;
68
+ // referrer policy control, if exist
69
+ if (config.referrerPolicy) {
70
+ segment.referrerPolicy = config.referrerPolicy;
71
+ }
72
+ });
73
+
74
+ if (!isNaN(totalDuration) && this._mediaDataSource.duration !== totalDuration) {
75
+ this._mediaDataSource.duration = totalDuration;
76
+ }
77
+
78
+ this._mediaInfo = null;
79
+ this._demuxer = null;
80
+ this._remuxer = null;
81
+ this._ioctl = null;
82
+
83
+ this._pendingSeekTime = null;
84
+ this._pendingResolveSeekPoint = null;
85
+
86
+ this._statisticsReporter = null;
87
+ }
88
+
89
+ destroy() {
90
+ this._mediaInfo = null;
91
+ this._mediaDataSource = null;
92
+
93
+ if (this._statisticsReporter) {
94
+ this._disableStatisticsReporter();
95
+ }
96
+ if (this._ioctl) {
97
+ this._ioctl.destroy();
98
+ this._ioctl = null;
99
+ }
100
+ if (this._demuxer) {
101
+ this._demuxer.destroy();
102
+ this._demuxer = null;
103
+ }
104
+ if (this._remuxer) {
105
+ this._remuxer.destroy();
106
+ this._remuxer = null;
107
+ }
108
+
109
+ this._emitter.removeAllListeners();
110
+ this._emitter = null;
111
+ }
112
+
113
+ on(event, listener) {
114
+ this._emitter.addListener(event, listener);
115
+ }
116
+
117
+ off(event, listener) {
118
+ this._emitter.removeListener(event, listener);
119
+ }
120
+
121
+ start() {
122
+ this._loadSegment(0);
123
+ this._enableStatisticsReporter();
124
+ }
125
+
126
+ _loadSegment(segmentIndex, optionalFrom) {
127
+ this._currentSegmentIndex = segmentIndex;
128
+ let dataSource = this._mediaDataSource.segments[segmentIndex];
129
+
130
+ let ioctl = this._ioctl = new IOController(dataSource, this._config, segmentIndex);
131
+ ioctl.onError = this._onIOException.bind(this);
132
+ ioctl.onSeeked = this._onIOSeeked.bind(this);
133
+ ioctl.onComplete = this._onIOComplete.bind(this);
134
+ ioctl.onRedirect = this._onIORedirect.bind(this);
135
+ ioctl.onRecoveredEarlyEof = this._onIORecoveredEarlyEof.bind(this);
136
+
137
+ if (optionalFrom) {
138
+ this._demuxer.bindDataSource(this._ioctl);
139
+ } else {
140
+ ioctl.onDataArrival = this._onInitChunkArrival.bind(this);
141
+ }
142
+
143
+ ioctl.open(optionalFrom);
144
+ }
145
+
146
+ stop() {
147
+ this._internalAbort();
148
+ this._disableStatisticsReporter();
149
+ }
150
+
151
+ _internalAbort() {
152
+ if (this._ioctl) {
153
+ this._ioctl.destroy();
154
+ this._ioctl = null;
155
+ }
156
+ }
157
+
158
+ pause() { // take a rest
159
+ if (this._ioctl && this._ioctl.isWorking()) {
160
+ this._ioctl.pause();
161
+ this._disableStatisticsReporter();
162
+ }
163
+ }
164
+
165
+ resume() {
166
+ if (this._ioctl && this._ioctl.isPaused()) {
167
+ this._ioctl.resume();
168
+ this._enableStatisticsReporter();
169
+ }
170
+ }
171
+
172
+ switchAudioPid(pid) {
173
+ if (this._demuxer) {
174
+ if (typeof this._demuxer.setPreferredAudioPid === 'function') {
175
+ this._demuxer.setPreferredAudioPid(pid);
176
+ }
177
+ if (typeof this._demuxer.selectAudioPid === 'function') {
178
+ this._demuxer.selectAudioPid(pid);
179
+ }
180
+ }
181
+ }
182
+
183
+ seek(milliseconds) {
184
+ if (this._mediaInfo == null || !this._mediaInfo.isSeekable()) {
185
+ return;
186
+ }
187
+
188
+ let targetSegmentIndex = this._searchSegmentIndexContains(milliseconds);
189
+
190
+ if (targetSegmentIndex === this._currentSegmentIndex) {
191
+ // intra-segment seeking
192
+ let segmentInfo = this._mediaInfo.segments[targetSegmentIndex];
193
+
194
+ if (segmentInfo == undefined) {
195
+ // current segment loading started, but mediainfo hasn't received yet
196
+ // wait for the metadata loaded, then seek to expected position
197
+ this._pendingSeekTime = milliseconds;
198
+ } else {
199
+ let keyframe = segmentInfo.getNearestKeyframe(milliseconds);
200
+ this._remuxer.seek(keyframe.milliseconds);
201
+ this._ioctl.seek(keyframe.fileposition);
202
+ // Will be resolved in _onRemuxerMediaSegmentArrival()
203
+ this._pendingResolveSeekPoint = keyframe.milliseconds;
204
+ }
205
+ } else {
206
+ // cross-segment seeking
207
+ let targetSegmentInfo = this._mediaInfo.segments[targetSegmentIndex];
208
+
209
+ if (targetSegmentInfo == undefined) {
210
+ // target segment hasn't been loaded. We need metadata then seek to expected time
211
+ this._pendingSeekTime = milliseconds;
212
+ this._internalAbort();
213
+ this._remuxer.seek();
214
+ this._remuxer.insertDiscontinuity();
215
+ this._loadSegment(targetSegmentIndex);
216
+ // Here we wait for the metadata loaded, then seek to expected position
217
+ } else {
218
+ // We have target segment's metadata, direct seek to target position
219
+ let keyframe = targetSegmentInfo.getNearestKeyframe(milliseconds);
220
+ this._internalAbort();
221
+ this._remuxer.seek(milliseconds);
222
+ this._remuxer.insertDiscontinuity();
223
+ this._demuxer.resetMediaInfo();
224
+ this._demuxer.timestampBase = this._mediaDataSource.segments[targetSegmentIndex].timestampBase;
225
+ this._loadSegment(targetSegmentIndex, keyframe.fileposition);
226
+ this._pendingResolveSeekPoint = keyframe.milliseconds;
227
+ this._reportSegmentMediaInfo(targetSegmentIndex);
228
+ }
229
+ }
230
+
231
+ this._enableStatisticsReporter();
232
+ }
233
+
234
+ _searchSegmentIndexContains(milliseconds) {
235
+ let segments = this._mediaDataSource.segments;
236
+ let idx = segments.length - 1;
237
+
238
+ for (let i = 0; i < segments.length; i++) {
239
+ if (milliseconds < segments[i].timestampBase) {
240
+ idx = i - 1;
241
+ break;
242
+ }
243
+ }
244
+ return idx;
245
+ }
246
+
247
+ _onInitChunkArrival(data, byteStart) {
248
+ let consumed = 0;
249
+
250
+ if (byteStart > 0) {
251
+ // IOController seeked immediately after opened, byteStart > 0 callback may received
252
+ this._demuxer.bindDataSource(this._ioctl);
253
+ this._demuxer.timestampBase = this._mediaDataSource.segments[this._currentSegmentIndex].timestampBase;
254
+
255
+ consumed = this._demuxer.parseChunks(data, byteStart);
256
+ } else {
257
+ // byteStart == 0, Initial data, probe it first
258
+ let probeData = null;
259
+
260
+ // Try probing input data as FLV first
261
+ probeData = FLVDemuxer.probe(data);
262
+ if (probeData.match) {
263
+ // Hit as FLV
264
+ this._setupFLVDemuxerRemuxer(probeData);
265
+ consumed = this._demuxer.parseChunks(data, byteStart);
266
+ }
267
+
268
+ if (!probeData.match && !probeData.needMoreData) {
269
+ // Non-FLV, try MPEG-TS probe
270
+ probeData = TSDemuxer.probe(data);
271
+ if (probeData.match) {
272
+ // Hit as MPEG-TS
273
+ this._setupTSDemuxerRemuxer(probeData);
274
+ consumed = this._demuxer.parseChunks(data, byteStart);
275
+ }
276
+ }
277
+
278
+ if (!probeData.match && !probeData.needMoreData) {
279
+ // Both probing as FLV / MPEG-TS failed, report error
280
+ probeData = null;
281
+ Log.e(this.TAG, 'Non MPEG-TS/FLV, Unsupported media type!');
282
+ Promise.resolve().then(() => {
283
+ this._internalAbort();
284
+ });
285
+ this._emitter.emit(TransmuxingEvents.DEMUX_ERROR, DemuxErrors.FORMAT_UNSUPPORTED, 'Non MPEG-TS/FLV, Unsupported media type!');
286
+ // Leave consumed as 0
287
+ }
288
+ }
289
+
290
+ return consumed;
291
+ }
292
+
293
+ _setupFLVDemuxerRemuxer(probeData) {
294
+ this._demuxer = new FLVDemuxer(probeData, this._config);
295
+
296
+ if (!this._remuxer) {
297
+ this._remuxer = new MP4Remuxer(this._config);
298
+ }
299
+
300
+ let mds = this._mediaDataSource;
301
+ if (mds.duration != undefined && !isNaN(mds.duration)) {
302
+ this._demuxer.overridedDuration = mds.duration;
303
+ }
304
+ if (typeof mds.hasAudio === 'boolean') {
305
+ this._demuxer.overridedHasAudio = mds.hasAudio;
306
+ }
307
+ if (typeof mds.hasVideo === 'boolean') {
308
+ this._demuxer.overridedHasVideo = mds.hasVideo;
309
+ }
310
+
311
+ this._demuxer.timestampBase = mds.segments[this._currentSegmentIndex].timestampBase;
312
+
313
+ this._demuxer.onError = this._onDemuxException.bind(this);
314
+ this._demuxer.onMediaInfo = this._onMediaInfo.bind(this);
315
+ this._demuxer.onMetaDataArrived = this._onMetaDataArrived.bind(this);
316
+ this._demuxer.onScriptDataArrived = this._onScriptDataArrived.bind(this);
317
+ this._demuxer.onTracksUpdated = this._onTracksUpdated.bind(this);
318
+ this._demuxer.onSeiArrived = this._onSEI.bind(this);
319
+
320
+ this._remuxer.bindDataSource(this._demuxer
321
+ .bindDataSource(this._ioctl
322
+ ));
323
+
324
+ this._remuxer.onInitSegment = this._onRemuxerInitSegmentArrival.bind(this);
325
+ this._remuxer.onMediaSegment = this._onRemuxerMediaSegmentArrival.bind(this);
326
+ }
327
+
328
+ _setupTSDemuxerRemuxer(probeData) {
329
+ let demuxer = this._demuxer = new TSDemuxer(probeData, this._config);
330
+
331
+ if (!this._remuxer) {
332
+ this._remuxer = new MP4Remuxer(this._config);
333
+ }
334
+
335
+ demuxer.onError = this._onDemuxException.bind(this);
336
+ demuxer.onMediaInfo = this._onMediaInfo.bind(this);
337
+ demuxer.onMetaDataArrived = this._onMetaDataArrived.bind(this);
338
+ demuxer.onTimedID3Metadata = this._onTimedID3Metadata.bind(this);
339
+ demuxer.onPGSSubtitleData = this._onPGSSubtitle.bind(this);
340
+ demuxer.onSynchronousKLVMetadata = this._onSynchronousKLVMetadata.bind(this);
341
+ demuxer.onAsynchronousKLVMetadata = this._onAsynchronousKLVMetadata.bind(this);
342
+ demuxer.onSMPTE2038Metadata = this._onSMPTE2038Metadata.bind(this);
343
+ demuxer.onSEI = this._onSEI.bind(this);
344
+ demuxer.onSCTE35Metadata = this._onSCTE35Metadata.bind(this);
345
+ demuxer.onPESPrivateData = this._onPESPrivateData.bind(this);
346
+ demuxer.onPESPrivateDataDescriptor = this._onPESPrivateDataDescriptor.bind(this);
347
+ demuxer.onTracksUpdated = this._onTracksUpdated.bind(this);
348
+ demuxer.onPESPrivateData = this._onPESPrivateData.bind(this);
349
+
350
+ this._remuxer.bindDataSource(this._demuxer);
351
+ this._demuxer.bindDataSource(this._ioctl);
352
+
353
+ this._remuxer.onInitSegment = this._onRemuxerInitSegmentArrival.bind(this);
354
+ this._remuxer.onMediaSegment = this._onRemuxerMediaSegmentArrival.bind(this);
355
+ }
356
+
357
+ _onMediaInfo(mediaInfo) {
358
+ if (this._mediaInfo == null) {
359
+ // Store first segment's mediainfo as global mediaInfo
360
+ this._mediaInfo = Object.assign({}, mediaInfo);
361
+ this._mediaInfo.keyframesIndex = null;
362
+ this._mediaInfo.segments = [];
363
+ this._mediaInfo.segmentCount = this._mediaDataSource.segments.length;
364
+ Object.setPrototypeOf(this._mediaInfo, MediaInfo.prototype);
365
+ }
366
+
367
+ let segmentInfo = Object.assign({}, mediaInfo);
368
+ Object.setPrototypeOf(segmentInfo, MediaInfo.prototype);
369
+ this._mediaInfo.segments[this._currentSegmentIndex] = segmentInfo;
370
+
371
+ // notify mediaInfo update
372
+ this._reportSegmentMediaInfo(this._currentSegmentIndex);
373
+
374
+ if (this._pendingSeekTime != null) {
375
+ Promise.resolve().then(() => {
376
+ let target = this._pendingSeekTime;
377
+ this._pendingSeekTime = null;
378
+ this.seek(target);
379
+ });
380
+ }
381
+ }
382
+
383
+ _onMetaDataArrived(metadata) {
384
+ this._emitter.emit(TransmuxingEvents.METADATA_ARRIVED, metadata);
385
+ }
386
+
387
+ _onScriptDataArrived(data) {
388
+ this._emitter.emit(TransmuxingEvents.SCRIPTDATA_ARRIVED, data);
389
+ }
390
+
391
+ _onTracksUpdated(data) {
392
+ this._emitter.emit(TransmuxingEvents.TRACKS_UPDATED, data);
393
+ }
394
+
395
+ _onTimedID3Metadata(timed_id3_metadata) {
396
+ let timestamp_base = this._remuxer.getTimestampBase();
397
+ if (timestamp_base == undefined) { return; }
398
+
399
+ if (timed_id3_metadata.pts != undefined) {
400
+ timed_id3_metadata.pts -= timestamp_base;
401
+ }
402
+
403
+ if (timed_id3_metadata.dts != undefined) {
404
+ timed_id3_metadata.dts -= timestamp_base;
405
+ }
406
+
407
+ this._emitter.emit(TransmuxingEvents.TIMED_ID3_METADATA_ARRIVED, timed_id3_metadata);
408
+ }
409
+
410
+ _onPGSSubtitle(pgs_data) {
411
+ let timestamp_base = this._remuxer.getTimestampBase();
412
+ if (timestamp_base == undefined) { return; }
413
+
414
+ if (pgs_data.pts != undefined) {
415
+ pgs_data.pts -= timestamp_base;
416
+ }
417
+
418
+ if (pgs_data.dts != undefined) {
419
+ pgs_data.dts -= timestamp_base;
420
+ }
421
+
422
+ this._emitter.emit(TransmuxingEvents.PGS_SUBTITLE_ARRIVED, pgs_data);
423
+ }
424
+
425
+ _onSynchronousKLVMetadata(synchronous_klv_metadata) {
426
+ let timestamp_base = this._remuxer.getTimestampBase();
427
+ if (timestamp_base == undefined) { return; }
428
+
429
+ if (synchronous_klv_metadata.pts != undefined) {
430
+ synchronous_klv_metadata.pts -= timestamp_base;
431
+ }
432
+
433
+ if (synchronous_klv_metadata.dts != undefined) {
434
+ synchronous_klv_metadata.dts -= timestamp_base;
435
+ }
436
+
437
+ this._emitter.emit(TransmuxingEvents.SYNCHRONOUS_KLV_METADATA_ARRIVED, synchronous_klv_metadata);
438
+ }
439
+
440
+ _onAsynchronousKLVMetadata(asynchronous_klv_metadata) {
441
+ this._emitter.emit(TransmuxingEvents.ASYNCHRONOUS_KLV_METADATA_ARRIVED, asynchronous_klv_metadata);
442
+ }
443
+
444
+ _onSMPTE2038Metadata(smpte2038_metadata) {
445
+ let timestamp_base = this._remuxer.getTimestampBase();
446
+ if (timestamp_base == undefined) { return; }
447
+
448
+ if (smpte2038_metadata.pts != undefined) {
449
+ smpte2038_metadata.pts -= timestamp_base;
450
+ }
451
+
452
+ if (smpte2038_metadata.dts != undefined) {
453
+ smpte2038_metadata.dts -= timestamp_base;
454
+ }
455
+
456
+ if (smpte2038_metadata.nearest_pts != undefined) {
457
+ smpte2038_metadata.nearest_pts -= timestamp_base;
458
+ }
459
+
460
+ this._emitter.emit(TransmuxingEvents.SMPTE2038_METADATA_ARRIVED, smpte2038_metadata);
461
+ }
462
+
463
+ _onSEI(sei_data) {
464
+ let timestamp_base = this._remuxer.getTimestampBase();
465
+ if (timestamp_base == undefined) { return; }
466
+
467
+ if (sei_data.pts != undefined) {
468
+ sei_data.pts -= timestamp_base;
469
+ }
470
+
471
+ this._emitter.emit(TransmuxingEvents.SEI_ARRIVED, sei_data);
472
+ }
473
+
474
+ _onSCTE35Metadata(scte35) {
475
+ let timestamp_base = this._remuxer.getTimestampBase();
476
+ if (timestamp_base == undefined) { return; }
477
+
478
+ if (scte35.pts != undefined) {
479
+ scte35.pts -= timestamp_base;
480
+ }
481
+
482
+ if (scte35.nearest_pts != undefined) {
483
+ scte35.nearest_pts -= timestamp_base;
484
+ }
485
+
486
+ this._emitter.emit(TransmuxingEvents.SCTE35_METADATA_ARRIVED, scte35);
487
+ }
488
+
489
+ _onPESPrivateDataDescriptor(descriptor) {
490
+ this._emitter.emit(TransmuxingEvents.PES_PRIVATE_DATA_DESCRIPTOR, descriptor);
491
+ }
492
+
493
+ _onPESPrivateData(private_data) {
494
+ let timestamp_base = this._remuxer.getTimestampBase();
495
+ if (timestamp_base == undefined) { return; }
496
+
497
+ if (private_data.pts != undefined) {
498
+ private_data.pts -= timestamp_base;
499
+ }
500
+
501
+ if (private_data.nearest_pts != undefined) {
502
+ private_data.nearest_pts -= timestamp_base;
503
+ }
504
+
505
+ if (private_data.dts != undefined) {
506
+ private_data.dts -= timestamp_base;
507
+ }
508
+
509
+ this._emitter.emit(TransmuxingEvents.PES_PRIVATE_DATA_ARRIVED, private_data);
510
+ }
511
+
512
+ _onIOSeeked() {
513
+ this._remuxer.insertDiscontinuity();
514
+ }
515
+
516
+ _onIOComplete(extraData) {
517
+ let segmentIndex = extraData;
518
+ let nextSegmentIndex = segmentIndex + 1;
519
+
520
+ if (nextSegmentIndex < this._mediaDataSource.segments.length) {
521
+ this._internalAbort();
522
+ if (this._remuxer) {
523
+ this._remuxer.flushStashedSamples();
524
+ }
525
+ this._loadSegment(nextSegmentIndex);
526
+ } else {
527
+ if (this._remuxer) {
528
+ this._remuxer.flushStashedSamples();
529
+ }
530
+ this._emitter.emit(TransmuxingEvents.LOADING_COMPLETE);
531
+ this._disableStatisticsReporter();
532
+ }
533
+ }
534
+
535
+ _onIORedirect(redirectedURL) {
536
+ let segmentIndex = this._ioctl.extraData;
537
+ this._mediaDataSource.segments[segmentIndex].redirectedURL = redirectedURL;
538
+ }
539
+
540
+ _onIORecoveredEarlyEof() {
541
+ this._emitter.emit(TransmuxingEvents.RECOVERED_EARLY_EOF);
542
+ }
543
+
544
+ _onIOException(type, info) {
545
+ Log.e(this.TAG, `IOException: type = ${type}, code = ${info.code}, msg = ${info.msg}`);
546
+ this._emitter.emit(TransmuxingEvents.IO_ERROR, type, info);
547
+ this._disableStatisticsReporter();
548
+ }
549
+
550
+ _onDemuxException(type, info) {
551
+ Log.e(this.TAG, `DemuxException: type = ${type}, info = ${info}`);
552
+ this._emitter.emit(TransmuxingEvents.DEMUX_ERROR, type, info);
553
+ }
554
+
555
+ _onRemuxerInitSegmentArrival(type, initSegment) {
556
+ this._emitter.emit(TransmuxingEvents.INIT_SEGMENT, type, initSegment);
557
+ }
558
+
559
+ _onRemuxerMediaSegmentArrival(type, mediaSegment) {
560
+ if (this._pendingSeekTime != null) {
561
+ // Media segments after new-segment cross-seeking should be dropped.
562
+ return;
563
+ }
564
+ this._emitter.emit(TransmuxingEvents.MEDIA_SEGMENT, type, mediaSegment);
565
+
566
+ // Resolve pending seekPoint
567
+ if (this._pendingResolveSeekPoint != null && type === 'video') {
568
+ let syncPoints = mediaSegment.info.syncPoints;
569
+ let seekpoint = this._pendingResolveSeekPoint;
570
+ this._pendingResolveSeekPoint = null;
571
+
572
+ // Safari: Pass PTS for recommend_seekpoint
573
+ if (Browser.safari && syncPoints.length > 0 && syncPoints[0].originalDts === seekpoint) {
574
+ seekpoint = syncPoints[0].pts;
575
+ }
576
+ // else: use original DTS (keyframe.milliseconds)
577
+
578
+ this._emitter.emit(TransmuxingEvents.RECOMMEND_SEEKPOINT, seekpoint);
579
+ }
580
+ }
581
+
582
+ _enableStatisticsReporter() {
583
+ if (this._statisticsReporter == null) {
584
+ this._statisticsReporter = self.setInterval(
585
+ this._reportStatisticsInfo.bind(this),
586
+ this._config.statisticsInfoReportInterval);
587
+ }
588
+ }
589
+
590
+ _disableStatisticsReporter() {
591
+ if (this._statisticsReporter) {
592
+ self.clearInterval(this._statisticsReporter);
593
+ this._statisticsReporter = null;
594
+ }
595
+ }
596
+
597
+ _reportSegmentMediaInfo(segmentIndex) {
598
+ let segmentInfo = this._mediaInfo.segments[segmentIndex];
599
+ let exportInfo = Object.assign({}, segmentInfo);
600
+
601
+ exportInfo.duration = this._mediaInfo.duration;
602
+ exportInfo.segmentCount = this._mediaInfo.segmentCount;
603
+ delete exportInfo.segments;
604
+ delete exportInfo.keyframesIndex;
605
+
606
+ this._emitter.emit(TransmuxingEvents.MEDIA_INFO, exportInfo);
607
+ }
608
+
609
+ _reportStatisticsInfo() {
610
+ let info = {};
611
+
612
+ info.url = this._ioctl.currentURL;
613
+ info.hasRedirect = this._ioctl.hasRedirect;
614
+ if (info.hasRedirect) {
615
+ info.redirectedURL = this._ioctl.currentRedirectedURL;
616
+ }
617
+
618
+ info.speed = this._ioctl.currentSpeed;
619
+ info.loaderType = this._ioctl.loaderType;
620
+ info.currentSegmentIndex = this._currentSegmentIndex;
621
+ info.totalSegmentCount = this._mediaDataSource.segments.length;
622
+
623
+ this._emitter.emit(TransmuxingEvents.STATISTICS_INFO, info);
624
+ }
625
+
626
+ }
627
+
628
+ export default TransmuxingController;
@@ -0,0 +1,43 @@
1
+ /*
2
+ * Copyright (C) 2016 Bilibili. All Rights Reserved.
3
+ *
4
+ * @author zheng qian <xqq@xqq.im>
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ enum TransmuxingEvents {
20
+ IO_ERROR = 'io_error',
21
+ DEMUX_ERROR = 'demux_error',
22
+ INIT_SEGMENT = 'init_segment',
23
+ MEDIA_SEGMENT = 'media_segment',
24
+ LOADING_COMPLETE = 'loading_complete',
25
+ RECOVERED_EARLY_EOF = 'recovered_early_eof',
26
+ MEDIA_INFO = 'media_info',
27
+ METADATA_ARRIVED = 'metadata_arrived',
28
+ SCRIPTDATA_ARRIVED = 'scriptdata_arrived',
29
+ TRACKS_UPDATED = 'tracks_updated',
30
+ TIMED_ID3_METADATA_ARRIVED = 'timed_id3_metadata_arrived',
31
+ PGS_SUBTITLE_ARRIVED = 'pgs_subtitle_arrived',
32
+ SYNCHRONOUS_KLV_METADATA_ARRIVED = 'synchronous_klv_metadata_arrived',
33
+ ASYNCHRONOUS_KLV_METADATA_ARRIVED = 'asynchronous_klv_metadata_arrived',
34
+ SMPTE2038_METADATA_ARRIVED = 'smpte2038_metadata_arrived',
35
+ SEI_ARRIVED = 'sei_arrived',
36
+ SCTE35_METADATA_ARRIVED = 'scte35_metadata_arrived',
37
+ PES_PRIVATE_DATA_DESCRIPTOR = 'pes_private_data_descriptor',
38
+ PES_PRIVATE_DATA_ARRIVED = 'pes_private_data_arrived',
39
+ STATISTICS_INFO = 'statistics_info',
40
+ RECOMMEND_SEEKPOINT = 'recommend_seekpoint'
41
+ };
42
+
43
+ export default TransmuxingEvents;