UNPKG

@framekit/webm-writer-esm

Version:
200 lines (181 loc) • 5.53 kB
/* eslint no-fallthrough: "off" */ /** * A tool for presenting an ArrayBuffer as a stream for writing some simple data types. * * By Nicholas Sherlock * */ /* * Create an ArrayBuffer of the given length and present it as a writable stream with methods * for writing data in different formats. */ export function ArrayBufferDataStream(length) { this.data = new Uint8Array(length); this.pos = 0; } ArrayBufferDataStream.prototype.seek = function (toOffset) { this.pos = toOffset; }; ArrayBufferDataStream.prototype.writeBytes = function (arr) { for (let i = 0; i < arr.length; i++) { this.data[this.pos++] = arr[i]; } }; ArrayBufferDataStream.prototype.writeByte = function (b) { this.data[this.pos++] = b; }; //Synonym: ArrayBufferDataStream.prototype.writeU8 = ArrayBufferDataStream.prototype.writeByte; ArrayBufferDataStream.prototype.writeU16BE = function (u) { this.data[this.pos++] = u >> 8; this.data[this.pos++] = u; }; ArrayBufferDataStream.prototype.writeDoubleBE = function (d) { let bytes = new Uint8Array(new Float64Array([d]).buffer); for (let i = bytes.length - 1; i >= 0; i--) { this.writeByte(bytes[i]); } }; ArrayBufferDataStream.prototype.writeFloatBE = function (d) { let bytes = new Uint8Array(new Float32Array([d]).buffer); for (let i = bytes.length - 1; i >= 0; i--) { this.writeByte(bytes[i]); } }; /** * Write an ASCII string to the stream */ ArrayBufferDataStream.prototype.writeString = function (s) { for (let i = 0; i < s.length; i++) { this.data[this.pos++] = s.charCodeAt(i); } }; /** * Write the given 32-bit integer to the stream as an EBML variable-length integer using the given byte width * (use measureEBMLVarInt). * * No error checking is performed to ensure that the supplied width is correct for the integer. * * @param i Integer to be written * @param width Number of bytes to write to the stream */ ArrayBufferDataStream.prototype.writeEBMLVarIntWidth = function (i, width) { switch (width) { case 1: this.writeU8((1 << 7) | i); break; case 2: this.writeU8((1 << 6) | (i >> 8)); this.writeU8(i); break; case 3: this.writeU8((1 << 5) | (i >> 16)); this.writeU8(i >> 8); this.writeU8(i); break; case 4: this.writeU8((1 << 4) | (i >> 24)); this.writeU8(i >> 16); this.writeU8(i >> 8); this.writeU8(i); break; case 5: /* * JavaScript converts its doubles to 32-bit integers for bitwise operations, so we need to do a * division by 2^32 instead of a right-shift of 32 to retain those top 3 bits */ this.writeU8((1 << 3) | ((i / 4294967296) & 0x7)); this.writeU8(i >> 24); this.writeU8(i >> 16); this.writeU8(i >> 8); this.writeU8(i); break; default: throw new Error('Bad EBML VINT size ' + width); } }; /** * Return the number of bytes needed to encode the given integer as an EBML VINT. */ ArrayBufferDataStream.prototype.measureEBMLVarInt = function (val) { if (val < (1 << 7) - 1) { /* Top bit is set, leaving 7 bits to hold the integer, but we can't store 127 because * "all bits set to one" is a reserved value. Same thing for the other cases below: */ return 1; } else if (val < (1 << 14) - 1) { return 2; } else if (val < (1 << 21) - 1) { return 3; } else if (val < (1 << 28) - 1) { return 4; } else if (val < 34359738367) { // 2 ^ 35 - 1 (can address 32GB) return 5; } else { throw new Error('EBML VINT size not supported ' + val); } }; ArrayBufferDataStream.prototype.writeEBMLVarInt = function (i) { this.writeEBMLVarIntWidth(i, this.measureEBMLVarInt(i)); }; /** * Write the given unsigned 32-bit integer to the stream in big-endian order using the given byte width. * No error checking is performed to ensure that the supplied width is correct for the integer. * * Omit the width parameter to have it determined automatically for you. * * @param u Unsigned integer to be written * @param width Number of bytes to write to the stream */ ArrayBufferDataStream.prototype.writeUnsignedIntBE = function (u, width) { if (width === undefined) { width = this.measureUnsignedInt(u); } // Each case falls through: switch (width) { case 5: this.writeU8(Math.floor(u / 4294967296)); // Need to use division to access >32 bits of floating point var case 4: this.writeU8(u >> 24); case 3: this.writeU8(u >> 16); case 2: this.writeU8(u >> 8); case 1: this.writeU8(u); break; default: throw new Error('Bad UINT size ' + width); } }; /** * Return the number of bytes needed to hold the non-zero bits of the given unsigned integer. */ ArrayBufferDataStream.prototype.measureUnsignedInt = function (val) { // Force to 32-bit unsigned integer if (val < 1 << 8) { return 1; } else if (val < 1 << 16) { return 2; } else if (val < 1 << 24) { return 3; } else if (val < 4294967296) { return 4; } else { return 5; } }; /** * Return a view on the portion of the buffer from the beginning to the current seek position as a Uint8Array. */ ArrayBufferDataStream.prototype.getAsDataArray = function () { if (this.pos < this.data.byteLength) { return this.data.subarray(0, this.pos); } else if (this.pos == this.data.byteLength) { return this.data; } else { throw new Error('ArrayBufferDataStream\'s pos lies beyond end of buffer'); } };