1 |
|
2 |
|
3 |
|
4 | import videojs from 'video.js';
|
5 |
|
6 | const noop = function() {};
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 | export default class SourceUpdater {
|
21 | constructor(mediaSource, mimeType) {
|
22 | let createSourceBuffer = () => {
|
23 | this.sourceBuffer_ = mediaSource.addSourceBuffer(mimeType);
|
24 |
|
25 |
|
26 |
|
27 | this.onUpdateendCallback_ = () => {
|
28 | let pendingCallback = this.pendingCallback_;
|
29 |
|
30 | this.pendingCallback_ = null;
|
31 |
|
32 | if (pendingCallback) {
|
33 | pendingCallback();
|
34 | }
|
35 |
|
36 | this.runCallback_();
|
37 | };
|
38 |
|
39 | this.sourceBuffer_.addEventListener('updateend', this.onUpdateendCallback_);
|
40 |
|
41 | this.runCallback_();
|
42 | };
|
43 |
|
44 | this.callbacks_ = [];
|
45 | this.pendingCallback_ = null;
|
46 | this.timestampOffset_ = 0;
|
47 | this.mediaSource = mediaSource;
|
48 | this.processedAppend_ = false;
|
49 |
|
50 | if (mediaSource.readyState === 'closed') {
|
51 | mediaSource.addEventListener('sourceopen', createSourceBuffer);
|
52 | } else {
|
53 | createSourceBuffer();
|
54 | }
|
55 | }
|
56 |
|
57 | |
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 | abort(done) {
|
64 | if (this.processedAppend_) {
|
65 | this.queueCallback_(() => {
|
66 | this.sourceBuffer_.abort();
|
67 | }, done);
|
68 | }
|
69 | }
|
70 |
|
71 | |
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 | appendBuffer(bytes, done) {
|
79 | this.processedAppend_ = true;
|
80 |
|
81 | this.queueCallback_(() => {
|
82 | this.sourceBuffer_.appendBuffer(bytes);
|
83 | }, done);
|
84 | }
|
85 |
|
86 | |
87 |
|
88 |
|
89 |
|
90 |
|
91 | buffered() {
|
92 | if (!this.sourceBuffer_) {
|
93 | return videojs.createTimeRanges();
|
94 | }
|
95 | return this.sourceBuffer_.buffered;
|
96 | }
|
97 |
|
98 | |
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 | remove(start, end) {
|
106 | if (this.processedAppend_) {
|
107 | this.queueCallback_(() => {
|
108 | this.sourceBuffer_.remove(start, end);
|
109 | }, noop);
|
110 | }
|
111 | }
|
112 |
|
113 | |
114 |
|
115 |
|
116 |
|
117 |
|
118 | updating() {
|
119 | return !this.sourceBuffer_ || this.sourceBuffer_.updating || this.pendingCallback_;
|
120 | }
|
121 |
|
122 | |
123 |
|
124 |
|
125 |
|
126 |
|
127 | timestampOffset(offset) {
|
128 | if (typeof offset !== 'undefined') {
|
129 | this.queueCallback_(() => {
|
130 | this.sourceBuffer_.timestampOffset = offset;
|
131 | });
|
132 | this.timestampOffset_ = offset;
|
133 | }
|
134 | return this.timestampOffset_;
|
135 | }
|
136 |
|
137 | |
138 |
|
139 |
|
140 | queueCallback_(callback, done) {
|
141 | this.callbacks_.push([callback.bind(this), done]);
|
142 | this.runCallback_();
|
143 | }
|
144 |
|
145 | |
146 |
|
147 |
|
148 | runCallback_() {
|
149 | let callbacks;
|
150 |
|
151 | if (!this.updating() &&
|
152 | this.callbacks_.length) {
|
153 | callbacks = this.callbacks_.shift();
|
154 | this.pendingCallback_ = callbacks[1];
|
155 | callbacks[0]();
|
156 | }
|
157 | }
|
158 |
|
159 | |
160 |
|
161 |
|
162 | dispose() {
|
163 | this.sourceBuffer_.removeEventListener('updateend', this.onUpdateendCallback_);
|
164 | if (this.sourceBuffer_ && this.mediaSource.readyState === 'open') {
|
165 | this.sourceBuffer_.abort();
|
166 | }
|
167 | }
|
168 | }
|