@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,142 @@
1
+ /*
2
+ * Copyright (C) 2023 zheng qian. 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 Log from '../utils/logger';
20
+
21
+ class LoadingController {
22
+
23
+ private readonly TAG: string = 'LoadingController';
24
+
25
+ private _config: any = null;
26
+ private _media_element: HTMLMediaElement = null;
27
+ private _on_pause_transmuxer: () => void = null;
28
+ private _on_resume_transmuxer: () => void = null;
29
+
30
+ private _paused: boolean = false;
31
+
32
+ private e?: any = null;
33
+
34
+ public constructor(
35
+ config: any,
36
+ media_element: HTMLMediaElement,
37
+ on_pause_transmuxer: () => void,
38
+ on_resume_transmuxer: () => void
39
+ ) {
40
+ this._config = config;
41
+ this._media_element = media_element;
42
+ this._on_pause_transmuxer = on_pause_transmuxer;
43
+ this._on_resume_transmuxer = on_resume_transmuxer;
44
+
45
+ this.e = {
46
+ onMediaTimeUpdate: this._onMediaTimeUpdate.bind(this),
47
+ };
48
+ }
49
+
50
+ public destroy(): void {
51
+ this._media_element.removeEventListener('timeupdate', this.e.onMediaTimeUpdate);
52
+ this.e = null;
53
+ this._media_element = null;
54
+ this._config = null;
55
+ this._on_pause_transmuxer = null;
56
+ this._on_resume_transmuxer = null;
57
+ }
58
+
59
+ // buffered_position: in seconds
60
+ public notifyBufferedPositionChanged(buffered_position?: number): void {
61
+ if (this._config.isLive || !this._config.lazyLoad) {
62
+ return;
63
+ }
64
+
65
+ if (buffered_position == undefined) {
66
+ this._suspendTransmuxerIfNeeded();
67
+ } else {
68
+ this._suspendTransmuxerIfBufferedPositionExceeded(buffered_position);
69
+ }
70
+ }
71
+
72
+ private _onMediaTimeUpdate(e: Event): void {
73
+ if (this._paused) {
74
+ this._resumeTransmuxerIfNeeded();
75
+ }
76
+ }
77
+
78
+ private _suspendTransmuxerIfNeeded() {
79
+ const buffered: TimeRanges = this._media_element.buffered;
80
+ const current_time: number = this._media_element.currentTime;
81
+ let current_range_end = 0;
82
+
83
+ for (let i = 0; i < buffered.length; i++) {
84
+ const start = buffered.start(i);
85
+ const end = buffered.end(i);
86
+ if (start <= current_time && current_time < end) {
87
+ current_range_end = end;
88
+ break;
89
+ }
90
+ }
91
+ if (current_range_end > 0) {
92
+ this._suspendTransmuxerIfBufferedPositionExceeded(current_range_end);
93
+ }
94
+ }
95
+
96
+ private _suspendTransmuxerIfBufferedPositionExceeded(buffered_end: number): void {
97
+ const current_time = this._media_element.currentTime;
98
+ if (buffered_end >= current_time + this._config.lazyLoadMaxDuration && !this._paused) {
99
+ Log.v(this.TAG, 'Maximum buffering duration exceeded, suspend transmuxing task');
100
+ this.suspendTransmuxer();
101
+ this._media_element.addEventListener('timeupdate', this.e.onMediaTimeUpdate);
102
+ }
103
+ }
104
+
105
+ public suspendTransmuxer(): void {
106
+ this._paused = true;
107
+ this._on_pause_transmuxer();
108
+ }
109
+
110
+ private _resumeTransmuxerIfNeeded(): void {
111
+ const buffered: TimeRanges = this._media_element.buffered;
112
+ const current_time: number = this._media_element.currentTime;
113
+
114
+ const recover_duration = this._config.lazyLoadRecoverDuration;
115
+ let should_resume = false;
116
+
117
+ for (let i = 0; i < buffered.length; i++) {
118
+ const from = buffered.start(i);
119
+ const to = buffered.end(i);
120
+ if (current_time >= from && current_time < to) {
121
+ if (current_time >= to - recover_duration) {
122
+ should_resume = true;
123
+ }
124
+ break;
125
+ }
126
+ }
127
+
128
+ if (should_resume) {
129
+ Log.v(this.TAG, 'Continue loading from paused position');
130
+ this.resumeTransmuxer();
131
+ this._media_element.removeEventListener('timeupdate', this.e.onMediaTimeUpdate);
132
+ }
133
+ }
134
+
135
+ public resumeTransmuxer(): void {
136
+ this._paused = false;
137
+ this._on_resume_transmuxer();
138
+ }
139
+
140
+ }
141
+
142
+ export default LoadingController;
@@ -0,0 +1,150 @@
1
+ /*
2
+ * Copyright (C) 2023 zheng qian. 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 Log from '../utils/logger';
20
+ import MediaInfo from '../core/media-info';
21
+ import PlayerEngine from './player-engine';
22
+ import PlayerEngineMainThread from './player-engine-main-thread';
23
+ import PlayerEngineDedicatedThread from './player-engine-dedicated-thread';
24
+ import {InvalidArgumentException} from '../utils/exception';
25
+
26
+ class MSEPlayer {
27
+
28
+ private readonly TAG: string = 'MSEPlayer';
29
+
30
+ private _type: string = 'MSEPlayer';
31
+
32
+ private _media_element: HTMLMediaElement = null;
33
+ private _player_engine: PlayerEngine = null;
34
+
35
+ public constructor(mediaDataSource: any, config?: any) {
36
+ const typeLowerCase: string = mediaDataSource.type.toLowerCase();
37
+ if (typeLowerCase !== 'mse'
38
+ && typeLowerCase !== 'mpegts'
39
+ && typeLowerCase !== 'm2ts'
40
+ && typeLowerCase !== 'flv') {
41
+ throw new InvalidArgumentException('MSEPlayer requires an mpegts/m2ts/flv MediaDataSource input!');
42
+ }
43
+
44
+ if (config && config.enableWorkerForMSE && PlayerEngineDedicatedThread.isSupported()) {
45
+ try {
46
+ this._player_engine = new PlayerEngineDedicatedThread(mediaDataSource, config);
47
+ } catch (error) {
48
+ Log.e(this.TAG,
49
+ 'Error while initializing PlayerEngineDedicatedThread, fallback to PlayerEngineMainThread');
50
+ this._player_engine = new PlayerEngineMainThread(mediaDataSource, config);
51
+ }
52
+ } else {
53
+ this._player_engine = new PlayerEngineMainThread(mediaDataSource, config);
54
+ }
55
+ }
56
+
57
+ public destroy(): void {
58
+ this._player_engine.destroy();
59
+ this._player_engine = null;
60
+ this._media_element = null;
61
+ }
62
+
63
+ public on(event: string, listener: (...args: any[]) => void): void {
64
+ this._player_engine.on(event, listener);
65
+ }
66
+
67
+ public off(event: string, listener: (...args: any[]) => void): void {
68
+ this._player_engine.off(event, listener);
69
+ }
70
+
71
+ public attachMediaElement(mediaElement: HTMLMediaElement): void {
72
+ this._media_element = mediaElement;
73
+ this._player_engine.attachMediaElement(mediaElement);
74
+ }
75
+
76
+ public detachMediaElement(): void {
77
+ this._media_element = null;
78
+ this._player_engine.detachMediaElement();
79
+ }
80
+
81
+ public load(): void {
82
+ this._player_engine.load();
83
+ }
84
+
85
+ public unload(): void {
86
+ this._player_engine.unload();
87
+ }
88
+
89
+ public play(): Promise<void> {
90
+ return this._player_engine.play();
91
+ }
92
+
93
+ public pause(): void {
94
+ this._player_engine.pause();
95
+ }
96
+
97
+ public get type(): string {
98
+ return this._type;
99
+ }
100
+
101
+ public get buffered(): TimeRanges {
102
+ return this._media_element.buffered;
103
+ }
104
+
105
+ public get duration(): number {
106
+ return this._media_element.duration;
107
+ }
108
+
109
+ public get volume(): number {
110
+ return this._media_element.volume;
111
+ }
112
+
113
+ public set volume(value) {
114
+ this._media_element.volume = value;
115
+ }
116
+
117
+ public get muted(): boolean {
118
+ return this._media_element.muted;
119
+ }
120
+
121
+ public set muted(muted) {
122
+ this._media_element.muted = muted;
123
+ }
124
+
125
+ public get currentTime(): number {
126
+ if (this._media_element) {
127
+ return this._media_element.currentTime;
128
+ }
129
+ return 0;
130
+ }
131
+
132
+ public set currentTime(seconds: number) {
133
+ this._player_engine.seek(seconds);
134
+ }
135
+
136
+ public get mediaInfo(): MediaInfo {
137
+ return this._player_engine.mediaInfo;
138
+ }
139
+
140
+ public get statisticsInfo(): any {
141
+ return this._player_engine.statisticsInfo;
142
+ }
143
+
144
+ public switchAudioPid(pid: number): void {
145
+ this._player_engine.switchAudioPid(pid);
146
+ }
147
+
148
+ }
149
+
150
+ export default MSEPlayer;
@@ -0,0 +1,262 @@
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 PlayerEvents from './player-events';
21
+ import {createDefaultConfig} from '../config.js';
22
+ import {InvalidArgumentException, IllegalStateException} from '../utils/exception.js';
23
+
24
+ // Player wrapper for browser's native player (HTMLVideoElement) without MediaSource src.
25
+ class NativePlayer {
26
+
27
+ constructor(mediaDataSource, config) {
28
+ this.TAG = 'NativePlayer';
29
+ this._type = 'NativePlayer';
30
+ this._emitter = new EventEmitter();
31
+
32
+ this._config = createDefaultConfig();
33
+ if (typeof config === 'object') {
34
+ Object.assign(this._config, config);
35
+ }
36
+
37
+ let typeLowerCase = mediaDataSource.type.toLowerCase();
38
+
39
+ if (typeLowerCase === 'mse'
40
+ || typeLowerCase === 'mpegts'
41
+ || typeLowerCase === 'm2ts'
42
+ || typeLowerCase === 'flv') {
43
+ throw new InvalidArgumentException('NativePlayer does\'t support mse/mpegts/m2ts/flv MediaDataSource input!');
44
+ }
45
+ if (mediaDataSource.hasOwnProperty('segments')) {
46
+ throw new InvalidArgumentException(`NativePlayer(${mediaDataSource.type}) doesn't support multipart playback!`);
47
+ }
48
+
49
+ this.e = {
50
+ onvLoadedMetadata: this._onvLoadedMetadata.bind(this)
51
+ };
52
+
53
+ this._pendingSeekTime = null;
54
+ this._statisticsReporter = null;
55
+
56
+ this._mediaDataSource = mediaDataSource;
57
+ this._mediaElement = null;
58
+ }
59
+
60
+ destroy() {
61
+ this._emitter.emit(PlayerEvents.DESTROYING);
62
+ if (this._mediaElement) {
63
+ this.unload();
64
+ this.detachMediaElement();
65
+ }
66
+ this.e = null;
67
+ this._mediaDataSource = null;
68
+ this._emitter.removeAllListeners();
69
+ this._emitter = null;
70
+ }
71
+
72
+ on(event, listener) {
73
+ if (event === PlayerEvents.MEDIA_INFO) {
74
+ if (this._mediaElement != null && this._mediaElement.readyState !== 0) { // HAVE_NOTHING
75
+ Promise.resolve().then(() => {
76
+ this._emitter.emit(PlayerEvents.MEDIA_INFO, this.mediaInfo);
77
+ });
78
+ }
79
+ } else if (event === PlayerEvents.STATISTICS_INFO) {
80
+ if (this._mediaElement != null && this._mediaElement.readyState !== 0) {
81
+ Promise.resolve().then(() => {
82
+ this._emitter.emit(PlayerEvents.STATISTICS_INFO, this.statisticsInfo);
83
+ });
84
+ }
85
+ }
86
+ this._emitter.addListener(event, listener);
87
+ }
88
+
89
+ off(event, listener) {
90
+ this._emitter.removeListener(event, listener);
91
+ }
92
+
93
+ attachMediaElement(mediaElement) {
94
+ this._mediaElement = mediaElement;
95
+ mediaElement.addEventListener('loadedmetadata', this.e.onvLoadedMetadata);
96
+
97
+ if (this._pendingSeekTime != null) {
98
+ try {
99
+ mediaElement.currentTime = this._pendingSeekTime;
100
+ this._pendingSeekTime = null;
101
+ } catch (e) {
102
+ // IE11 may throw InvalidStateError if readyState === 0
103
+ // Defer set currentTime operation after loadedmetadata
104
+ }
105
+ }
106
+ }
107
+
108
+ detachMediaElement() {
109
+ if (this._mediaElement) {
110
+ this._mediaElement.src = '';
111
+ this._mediaElement.removeAttribute('src');
112
+ this._mediaElement.removeEventListener('loadedmetadata', this.e.onvLoadedMetadata);
113
+ this._mediaElement = null;
114
+ }
115
+ if (this._statisticsReporter != null) {
116
+ window.clearInterval(this._statisticsReporter);
117
+ this._statisticsReporter = null;
118
+ }
119
+ }
120
+
121
+ load() {
122
+ if (!this._mediaElement) {
123
+ throw new IllegalStateException('HTMLMediaElement must be attached before load()!');
124
+ }
125
+ this._mediaElement.src = this._mediaDataSource.url;
126
+
127
+ if (this._mediaElement.readyState > 0) {
128
+ this._mediaElement.currentTime = 0;
129
+ }
130
+
131
+ this._mediaElement.preload = 'auto';
132
+ this._mediaElement.load();
133
+ this._statisticsReporter = window.setInterval(
134
+ this._reportStatisticsInfo.bind(this),
135
+ this._config.statisticsInfoReportInterval);
136
+ }
137
+
138
+ unload() {
139
+ if (this._mediaElement) {
140
+ this._mediaElement.src = '';
141
+ this._mediaElement.removeAttribute('src');
142
+ }
143
+ if (this._statisticsReporter != null) {
144
+ window.clearInterval(this._statisticsReporter);
145
+ this._statisticsReporter = null;
146
+ }
147
+ }
148
+
149
+ play() {
150
+ return this._mediaElement.play();
151
+ }
152
+
153
+ pause() {
154
+ this._mediaElement.pause();
155
+ }
156
+
157
+ get type() {
158
+ return this._type;
159
+ }
160
+
161
+ get buffered() {
162
+ return this._mediaElement.buffered;
163
+ }
164
+
165
+ get duration() {
166
+ return this._mediaElement.duration;
167
+ }
168
+
169
+ get volume() {
170
+ return this._mediaElement.volume;
171
+ }
172
+
173
+ set volume(value) {
174
+ this._mediaElement.volume = value;
175
+ }
176
+
177
+ get muted() {
178
+ return this._mediaElement.muted;
179
+ }
180
+
181
+ set muted(muted) {
182
+ this._mediaElement.muted = muted;
183
+ }
184
+
185
+ get currentTime() {
186
+ if (this._mediaElement) {
187
+ return this._mediaElement.currentTime;
188
+ }
189
+ return 0;
190
+ }
191
+
192
+ set currentTime(seconds) {
193
+ if (this._mediaElement) {
194
+ this._mediaElement.currentTime = seconds;
195
+ } else {
196
+ this._pendingSeekTime = seconds;
197
+ }
198
+ }
199
+
200
+ get mediaInfo() {
201
+ let mediaPrefix = (this._mediaElement instanceof HTMLAudioElement) ? 'audio/' : 'video/';
202
+ let info = {
203
+ mimeType: mediaPrefix + this._mediaDataSource.type
204
+ };
205
+ if (this._mediaElement) {
206
+ info.duration = Math.floor(this._mediaElement.duration * 1000);
207
+ if (this._mediaElement instanceof HTMLVideoElement) {
208
+ info.width = this._mediaElement.videoWidth;
209
+ info.height = this._mediaElement.videoHeight;
210
+ }
211
+ }
212
+ return info;
213
+ }
214
+
215
+ get statisticsInfo() {
216
+ let info = {
217
+ playerType: this._type,
218
+ url: this._mediaDataSource.url
219
+ };
220
+
221
+ if (!(this._mediaElement instanceof HTMLVideoElement)) {
222
+ return info;
223
+ }
224
+
225
+ let hasQualityInfo = true;
226
+ let decoded = 0;
227
+ let dropped = 0;
228
+
229
+ if (this._mediaElement.getVideoPlaybackQuality) {
230
+ let quality = this._mediaElement.getVideoPlaybackQuality();
231
+ decoded = quality.totalVideoFrames;
232
+ dropped = quality.droppedVideoFrames;
233
+ } else if (this._mediaElement.webkitDecodedFrameCount != undefined) {
234
+ decoded = this._mediaElement.webkitDecodedFrameCount;
235
+ dropped = this._mediaElement.webkitDroppedFrameCount;
236
+ } else {
237
+ hasQualityInfo = false;
238
+ }
239
+
240
+ if (hasQualityInfo) {
241
+ info.decodedFrames = decoded;
242
+ info.droppedFrames = dropped;
243
+ }
244
+
245
+ return info;
246
+ }
247
+
248
+ _onvLoadedMetadata(e) {
249
+ if (this._pendingSeekTime != null) {
250
+ this._mediaElement.currentTime = this._pendingSeekTime;
251
+ this._pendingSeekTime = null;
252
+ }
253
+ this._emitter.emit(PlayerEvents.MEDIA_INFO, this.mediaInfo);
254
+ }
255
+
256
+ _reportStatisticsInfo() {
257
+ this._emitter.emit(PlayerEvents.STATISTICS_INFO, this.statisticsInfo);
258
+ }
259
+
260
+ }
261
+
262
+ export default NativePlayer;