0eec9a25 by David LaPalomento

Grow flv-tag buffer when needed. Optimize double metadata tags

Check whether the byte buffer is large enough before performing a write and allocate a larger buffer if necessary. Do less byte-by-byte ops when writing metadata double tags since they were a significant portion of parse computation when testing on my laptop.
1 parent 0acf0d03
1 (function(window) { 1 (function(window) {
2 2
3 var hls = window.videojs.hls; 3 var
4 hls = window.videojs.hls,
5
6 // commonly used metadata properties
7 widthBytes = new Uint8Array('width'.length),
8 heightBytes = new Uint8Array('height'.length),
9 videocodecidBytes = new Uint8Array('videocodecid'.length),
10 i;
11
12 // calculating the bytes of common metadata names ahead of time makes the
13 // corresponding writes faster because we don't have to loop over the
14 // characters
15 // re-test with test/perf.html if you're planning on changing this
16 for (i in 'width') {
17 widthBytes[i] = 'width'.charCodeAt(i);
18 }
19 for (i in 'height') {
20 heightBytes[i] = 'height'.charCodeAt(i);
21 }
22 for (i in 'videocodecid') {
23 videocodecidBytes[i] = 'videocodecid'.charCodeAt(i);
24 }
4 25
5 // (type:uint, extraData:Boolean = false) extends ByteArray 26 // (type:uint, extraData:Boolean = false) extends ByteArray
6 hls.FlvTag = function(type, extraData) { 27 hls.FlvTag = function(type, extraData) {
...@@ -54,7 +75,7 @@ hls.FlvTag = function(type, extraData) { ...@@ -54,7 +75,7 @@ hls.FlvTag = function(type, extraData) {
54 // presentation timestamp 75 // presentation timestamp
55 this.pts = 0; 76 this.pts = 0;
56 // decoder timestamp 77 // decoder timestamp
57 this.dts = 0; 78 this.dts = 0;
58 79
59 // ByteArray#writeBytes(bytes:ByteArray, offset:uint = 0, length:uint = 0) 80 // ByteArray#writeBytes(bytes:ByteArray, offset:uint = 0, length:uint = 0)
60 this.writeBytes = function(bytes, offset, length) { 81 this.writeBytes = function(bytes, offset, length) {
...@@ -100,7 +121,7 @@ hls.FlvTag = function(type, extraData) { ...@@ -100,7 +121,7 @@ hls.FlvTag = function(type, extraData) {
100 if (adHoc === 0) { 121 if (adHoc === 0) {
101 return 0; 122 return 0;
102 } 123 }
103 124
104 return this.length - (adHoc + 4); 125 return this.length - (adHoc + 4);
105 }; 126 };
106 127
...@@ -135,7 +156,7 @@ hls.FlvTag = function(type, extraData) { ...@@ -135,7 +156,7 @@ hls.FlvTag = function(type, extraData) {
135 this.position = this.length; 156 this.position = this.length;
136 157
137 if (nalContainer) { 158 if (nalContainer) {
138 // Add the tag to the NAL unit 159 // Add the tag to the NAL unit
139 nalContainer.push(this.bytes.subarray(nalStart, nalStart + nalLength)); 160 nalContainer.push(this.bytes.subarray(nalStart, nalStart + nalLength));
140 } 161 }
141 } 162 }
...@@ -143,23 +164,47 @@ hls.FlvTag = function(type, extraData) { ...@@ -143,23 +164,47 @@ hls.FlvTag = function(type, extraData) {
143 adHoc = 0; 164 adHoc = 0;
144 }; 165 };
145 166
167 /**
168 * Write out a 64-bit floating point valued metadata property. This method is
169 * called frequently during a typical parse and needs to be fast.
170 */
146 // (key:String, val:Number):void 171 // (key:String, val:Number):void
147 this.writeMetaDataDouble = function(key, val) { 172 this.writeMetaDataDouble = function(key, val) {
148 var i; 173 var i;
149 prepareWrite(this, 2); 174 prepareWrite(this, 2 + key.length + 9);
175
176 // write size of property name
150 this.view.setUint16(this.position, key.length); 177 this.view.setUint16(this.position, key.length);
151 this.position += 2; 178 this.position += 2;
152 for (i in key) { 179
153 console.assert(key.charCodeAt(i) < 255); 180 // this next part looks terrible but it improves parser throughput by
154 prepareWrite(this, 1); 181 // 10kB/s in my testing
155 this.bytes[this.position] = key.charCodeAt(i); 182
156 this.position++; 183 // write property name
184 if (key === 'width') {
185 this.bytes.set(widthBytes, this.position);
186 this.position += 5;
187 } else if (key === 'height') {
188 this.bytes.set(heightBytes, this.position);
189 this.position += 6;
190 } else if (key === 'videocodecid') {
191 this.bytes.set(videocodecidBytes, this.position);
192 this.position += 12;
193 } else {
194 for (i in key) {
195 this.bytes[this.position] = key.charCodeAt(i);
196 this.position++;
197 }
157 } 198 }
158 prepareWrite(this, 9); 199
159 this.view.setUint8(this.position, 0x00); 200 // skip null byte
160 this.position++; 201 this.position++;
202
203 // write property value
161 this.view.setFloat64(this.position, val); 204 this.view.setFloat64(this.position, val);
162 this.position += 8; 205 this.position += 8;
206
207 // update flv tag length
163 this.length = Math.max(this.length, this.position); 208 this.length = Math.max(this.length, this.position);
164 ++adHoc; 209 ++adHoc;
165 }; 210 };
...@@ -287,7 +332,7 @@ hls.FlvTag.isKeyFrame = function(tag) { ...@@ -287,7 +332,7 @@ hls.FlvTag.isKeyFrame = function(tag) {
287 if (hls.FlvTag.isAudioFrame(tag)) { 332 if (hls.FlvTag.isAudioFrame(tag)) {
288 return true; 333 return true;
289 } 334 }
290 335
291 if (hls.FlvTag.isMetaData(tag)) { 336 if (hls.FlvTag.isMetaData(tag)) {
292 return true; 337 return true;
293 } 338 }
......