JSFiddle - React, Tailwind, and code Playground
by Jon-Carlos Rivera
HTML
<script>
/**
* Parser for exponential Golomb codes, a variable-bitwidth number encoding
* scheme used by h264.
*/
function ExpGolomb (workingData) {
var
// the number of bytes left to examine in workingData
workingBytesAvailable = workingData.byteLength,
// the current word being examined
workingWord = 0, // :uint
// the number of bits left to examine in the current word
workingBitsAvailable = 0; // :uint;
// ():uint
this.length = function() {
return (8 * workingBytesAvailable);
};
// ():uint
this.bitsAvailable = function() {
return (8 * workingBytesAvailable) + workingBitsAvailable;
};
// ():void
this.loadWord = function() {
var
position = workingData.byteLength - workingBytesAvailable,
workingBytes = new Uint8Array(4),
availableBytes = Math.min(4, workingBytesAvailable);
if (availableBytes === 0) {
throw new Error('no bytes available');
}
workingBytes.set(workingData.subarray(position,
position + availableBytes));
workingWord = new DataView(workingBytes.buffer).getUint32(0);
// track the amount of workingData that has been processed
workingBitsAvailable = availableBytes * 8;
workingBytesAvailable -= availableBytes;
};
// (count:int):void
this.skipBits = function(count) {
var skipBytes; // :int
if (workingBitsAvailable > count) {
workingWord <<= count;
workingBitsAvailable -= count;
} else {
count -= workingBitsAvailable;
skipBytes = Math.floor(count / 8);
count -= (skipBytes * 8);
workingBytesAvailable -= skipBytes;
this.loadWord();
workingWord <<= count;
workingBitsAvailable -= count;
}
};
// (size:int):uint
this.readBits = function(size) {
var
bits = Math.min(workingBitsAvailable, size), // :uint
valu = workingWord >>> (32 - bits); // :uint
// if size > 31, handle error
...
JavaScript
'use strict';
/**
* General ExpGolomb Encoded Structure Parse Functions
*/
let parse = function(parseFns) {
return function (expGolombDecoder, output, index) {
parseFns.forEach((fn) => {
let response = fn(expGolombDecoder, output, index);
expGolombDecoder = response[0];
output = response[1];
});
return [expGolombDecoder, output];
};
};
let read = function (name, format) {
let nameMatch = (/([^\[]*)(\[.*\])?/).exec(name);
let formatMatch = (/(.*)\((.*)\)/i).exec(format);
let property;
let nameArray;
let type;
let size;
if (nameMatch && nameMatch.length > 1) {
property = nameMatch[1];
nameArray = nameMatch[2] !== undefined;
} else {
throw new Error('ExpGolomb Error: Invalid name "' + format + '".');
}
if (formatMatch && formatMatch.length > 2) {
type = formatMatch[1];
size = parseFloat(formatMatch[2]);
if (isNaN(size)) {
size = formatMatch[2];
}
} else {
throw new Error('ExpGolomb Error: Unrecognized format "' + format + '".');
}
return function (expGolombDecoder, output, index) {
let typeTable = {
b: () => expGolombDecoder.readUnsignedByte(),
f: (n) => expGolombDecoder.readBits(n),
i: (n) => expGolombDecoder.readBits(n), // TODO: Fix
se: () => expGolombDecoder.readExpGolomb(),
u: (n) => expGolombDecoder.readBits(n),
ue: () => expGolombDecoder.readUnsignedExpGolomb()
};
let value;
if (typeof size === 'number') {
value = typeTable[type](size);
} else if (size === 'v') {
value = typeTable[type]();
}
if (!nameArray) {
output[property] = value;
} else {
if (!Array.isArray(output[property])) {
output[property] = [];
}
if (index !== undefined) {
output[property][index] = value;
} else {
output[property].push(value);
}
}
return [expGolombDecoder, output];
};
};
let on = function (conditionFn, parseFn) {
return...