Grow the internal array if an FLV tag needs more than 16k
Before each write, check that the FLV tag's buffer has enough capacity and grow it if necessary.
Showing
2 changed files
with
47 additions
and
8 deletions
... | @@ -7,7 +7,25 @@ hls.FlvTag = function(type, extraData) { | ... | @@ -7,7 +7,25 @@ hls.FlvTag = function(type, extraData) { |
7 | var | 7 | var |
8 | // Counter if this is a metadata tag, nal start marker if this is a video | 8 | // Counter if this is a metadata tag, nal start marker if this is a video |
9 | // tag. unused if this is an audio tag | 9 | // tag. unused if this is an audio tag |
10 | adHoc = 0; // :uint | 10 | adHoc = 0, // :uint |
11 | |||
12 | // checks whether the FLV tag has enough capacity to accept the proposed | ||
13 | // write and re-allocates the internal buffers if necessary | ||
14 | prepareWrite = function(flv, count) { | ||
15 | var | ||
16 | bytes, | ||
17 | minLength = flv.position + count; | ||
18 | if (minLength < flv.bytes.byteLength) { | ||
19 | // there's enough capacity so do nothing | ||
20 | return; | ||
21 | } | ||
22 | |||
23 | // allocate a new buffer and copy over the data that will not be modified | ||
24 | bytes = new Uint8Array(minLength * 2); | ||
25 | bytes.set(flv.bytes.subarray(0, flv.position), 0); | ||
26 | flv.bytes = bytes; | ||
27 | flv.view = new DataView(flv.bytes.buffer); | ||
28 | }; | ||
11 | 29 | ||
12 | this.keyFrame = false; // :Boolean | 30 | this.keyFrame = false; // :Boolean |
13 | 31 | ||
... | @@ -27,7 +45,6 @@ hls.FlvTag = function(type, extraData) { | ... | @@ -27,7 +45,6 @@ hls.FlvTag = function(type, extraData) { |
27 | throw("Error Unknown TagType"); | 45 | throw("Error Unknown TagType"); |
28 | } | 46 | } |
29 | 47 | ||
30 | // XXX: I have no idea if 16k is enough to buffer arbitrary FLV tags | ||
31 | this.bytes = new Uint8Array(16384); | 48 | this.bytes = new Uint8Array(16384); |
32 | this.view = new DataView(this.bytes.buffer); | 49 | this.view = new DataView(this.bytes.buffer); |
33 | this.bytes[0] = type; | 50 | this.bytes[0] = type; |
... | @@ -41,20 +58,22 @@ hls.FlvTag = function(type, extraData) { | ... | @@ -41,20 +58,22 @@ hls.FlvTag = function(type, extraData) { |
41 | 58 | ||
42 | // ByteArray#writeBytes(bytes:ByteArray, offset:uint = 0, length:uint = 0) | 59 | // ByteArray#writeBytes(bytes:ByteArray, offset:uint = 0, length:uint = 0) |
43 | this.writeBytes = function(bytes, offset, length) { | 60 | this.writeBytes = function(bytes, offset, length) { |
44 | offset = offset || 0; | 61 | var |
62 | start = offset || 0, | ||
63 | end; | ||
45 | length = length || bytes.byteLength; | 64 | length = length || bytes.byteLength; |
65 | end = start + length; | ||
66 | |||
67 | prepareWrite(this, length); | ||
68 | this.bytes.set(bytes.subarray(start, end), this.position); | ||
46 | 69 | ||
47 | try { | ||
48 | this.bytes.set(bytes.subarray(offset, offset + length), this.position); | ||
49 | } catch(e) { | ||
50 | throw e; | ||
51 | } | ||
52 | this.position += length; | 70 | this.position += length; |
53 | this.length = Math.max(this.length, this.position); | 71 | this.length = Math.max(this.length, this.position); |
54 | }; | 72 | }; |
55 | 73 | ||
56 | // ByteArray#writeByte(value:int):void | 74 | // ByteArray#writeByte(value:int):void |
57 | this.writeByte = function(byte) { | 75 | this.writeByte = function(byte) { |
76 | prepareWrite(this, 1); | ||
58 | this.bytes[this.position] = byte; | 77 | this.bytes[this.position] = byte; |
59 | this.position++; | 78 | this.position++; |
60 | this.length = Math.max(this.length, this.position); | 79 | this.length = Math.max(this.length, this.position); |
... | @@ -62,6 +81,7 @@ hls.FlvTag = function(type, extraData) { | ... | @@ -62,6 +81,7 @@ hls.FlvTag = function(type, extraData) { |
62 | 81 | ||
63 | // ByteArray#writeShort(value:int):void | 82 | // ByteArray#writeShort(value:int):void |
64 | this.writeShort = function(short) { | 83 | this.writeShort = function(short) { |
84 | prepareWrite(this, 2); | ||
65 | this.view.setUint16(this.position, short); | 85 | this.view.setUint16(this.position, short); |
66 | this.position += 2; | 86 | this.position += 2; |
67 | this.length = Math.max(this.length, this.position); | 87 | this.length = Math.max(this.length, this.position); |
... | @@ -126,13 +146,16 @@ hls.FlvTag = function(type, extraData) { | ... | @@ -126,13 +146,16 @@ hls.FlvTag = function(type, extraData) { |
126 | // (key:String, val:Number):void | 146 | // (key:String, val:Number):void |
127 | this.writeMetaDataDouble = function(key, val) { | 147 | this.writeMetaDataDouble = function(key, val) { |
128 | var i; | 148 | var i; |
149 | prepareWrite(this, 2); | ||
129 | this.view.setUint16(this.position, key.length); | 150 | this.view.setUint16(this.position, key.length); |
130 | this.position += 2; | 151 | this.position += 2; |
131 | for (i in key) { | 152 | for (i in key) { |
132 | console.assert(key.charCodeAt(i) < 255); | 153 | console.assert(key.charCodeAt(i) < 255); |
154 | prepareWrite(this, 1); | ||
133 | this.bytes[this.position] = key.charCodeAt(i); | 155 | this.bytes[this.position] = key.charCodeAt(i); |
134 | this.position++; | 156 | this.position++; |
135 | } | 157 | } |
158 | prepareWrite(this, 9); | ||
136 | this.view.setUint8(this.position, 0x00); | 159 | this.view.setUint8(this.position, 0x00); |
137 | this.position++; | 160 | this.position++; |
138 | this.view.setFloat64(this.position, val); | 161 | this.view.setFloat64(this.position, val); |
... | @@ -144,13 +167,16 @@ hls.FlvTag = function(type, extraData) { | ... | @@ -144,13 +167,16 @@ hls.FlvTag = function(type, extraData) { |
144 | // (key:String, val:Boolean):void | 167 | // (key:String, val:Boolean):void |
145 | this.writeMetaDataBoolean = function(key, val) { | 168 | this.writeMetaDataBoolean = function(key, val) { |
146 | var i; | 169 | var i; |
170 | prepareWrite(this, 2); | ||
147 | this.view.setUint16(this.position, key.length); | 171 | this.view.setUint16(this.position, key.length); |
148 | this.position += 2; | 172 | this.position += 2; |
149 | for (i in key) { | 173 | for (i in key) { |
150 | console.assert(key.charCodeAt(i) < 255); | 174 | console.assert(key.charCodeAt(i) < 255); |
175 | prepareWrite(this, 1); | ||
151 | this.bytes[this.position] = key.charCodeAt(i); | 176 | this.bytes[this.position] = key.charCodeAt(i); |
152 | this.position++; | 177 | this.position++; |
153 | } | 178 | } |
179 | prepareWrite(this, 2); | ||
154 | this.view.setUint8(this.position, 0x01); | 180 | this.view.setUint8(this.position, 0x01); |
155 | this.position++; | 181 | this.position++; |
156 | this.view.setUint8(this.position, val ? 0x01 : 0x00); | 182 | this.view.setUint8(this.position, val ? 0x01 : 0x00); | ... | ... |
... | @@ -44,4 +44,17 @@ test('writeShort writes a two byte sequence', function() { | ... | @@ -44,4 +44,17 @@ test('writeShort writes a two byte sequence', function() { |
44 | 'the value is written'); | 44 | 'the value is written'); |
45 | }); | 45 | }); |
46 | 46 | ||
47 | test('writeBytes grows the internal byte array dynamically', function() { | ||
48 | var | ||
49 | tag = new FlvTag(FlvTag.VIDEO_TAG), | ||
50 | tooManyBytes = new Uint8Array(tag.bytes.byteLength + 1); | ||
51 | |||
52 | try { | ||
53 | tag.writeBytes(tooManyBytes); | ||
54 | ok(true, 'the buffer grew to fit the data'); | ||
55 | } catch(e) { | ||
56 | ok(!e, 'the buffer should grow'); | ||
57 | } | ||
58 | }); | ||
59 | |||
47 | })(this); | 60 | })(this); | ... | ... |
-
Please register or sign in to post a comment