UNPKG

vox-core

Version:

Runtime de aplicaciones multiplataforma

239 lines (219 loc) 9.97 kB
/* Range Coder. Inspired by rangecod.c from rngcod13.zip from * http://www.compressconsult.com/rangecoder/ * This JavaScript version is: * Copyright (c) 2013 C. Scott Ananian. */ if (typeof define !== 'function') { var define = require('amdefine')(module); } define([],function(){ // Uses 32-bit integer math. Hopefully the JavaScript runtime figures // that out. ;) // see https://github.com/kripken/emscripten/wiki/LLVM-Types-in-JavaScript // for some hints on doing 32-bit unsigned match in JavaScript. // One key is the use of ">>>0" to change a signed result to unsigned. var CODE_BITS = 32; var Top_value = Math.pow(2, CODE_BITS-1); var SHIFT_BITS = (CODE_BITS - 9); var EXTRA_BITS = ((CODE_BITS-2) % 8 + 1); var Bottom_value = (Top_value >>> 8); var MAX_INT = Math.pow(2, CODE_BITS) - 1; /* it is highly recommended that the total frequency count is less */ /* than 1 << 19 to minimize rounding effects. */ /* the total frequency count MUST be less than 1<<23 */ var RangeCoder = function(stream) { this.low = 0; /* low end of interval */ this.range = Top_value; /* length of interval */ this.buffer = 0; /* buffer for input/output */ this.help = 0; /* bytes_to_follow / intermediate value */ this.bytecount = 0; /* counter for output bytes */ this.stream = stream; }; /* Do the normalization before we need a defined state, instead of * after messing it up. This simplifies starting and ending. */ var enc_normalize = function(rc, outputStream) { while (rc.range <= Bottom_value) { /* do we need renormalization? */ if (rc.low < (0xFF << SHIFT_BITS)) {//no carry possible, so output outputStream.writeByte(rc.buffer); for (; rc.help; rc.help--) outputStream.writeByte(0xFF); rc.buffer = (rc.low >>> SHIFT_BITS) & 0xFF; } else if (rc.low & Top_value) { /* carry now, no future carry */ outputStream.writeByte(rc.buffer+1); for (; rc.help; rc.help--) outputStream.writeByte(0x00); rc.buffer = (rc.low >>> SHIFT_BITS) & 0xFF; } else { rc.help++; if (rc.help > MAX_INT) throw new Error("Too many bytes outstanding, "+ "file too large!"); } rc.range = (rc.range << 8) >>> 0;/*ensure result remains positive*/ rc.low = ((rc.low << 8) & (Top_value - 1)) >>> 0; /* unsigned */ rc.bytecount++; } }; /* Start the encoder */ /* c is written as the first byte in the datastream. * one could do w/o, but then you have an additional if per output byte */ RangeCoder.prototype.encodeStart = function(c, initlength) { this.low = 0; this.range = Top_value; this.buffer = c; this.help = 0; this.bytecount = initlength; }; /* Encode a symbol using frequencies */ /* rc is the range coder to be used */ /* sy_f is the interval length (frequency of the symbol) */ /* lt_f is the lower end (frequency sum of < symbols) */ /* tot_f is the total interval length (total frequency sum) */ /* or (faster): tot_f = (code_value)1<<shift */ RangeCoder.prototype.encodeFreq = function(sy_f, lt_f, tot_f) { enc_normalize(this, this.stream); var r = (this.range / tot_f) >>> 0; // note coercion to integer var tmp = r * lt_f; this.low += tmp; if ((lt_f + sy_f) < tot_f) { this.range = r * sy_f; } else { this.range -= tmp; } }; RangeCoder.prototype.encodeShift = function(sy_f, lt_f, shift) { enc_normalize(this, this.stream); var r = this.range >>> shift; var tmp = r * lt_f; this.low += tmp; if ((lt_f + sy_f) >>> shift) { this.range -= tmp; } else { this.range = r * sy_f; } }; /* Encode a bit w/o modelling. */ RangeCoder.prototype.encodeBit = function(b) { this.encodeShift(1, b?1:0, 1); }; /* Encode a byte w/o modelling. */ RangeCoder.prototype.encodeByte = function(b) { this.encodeShift(1, b, 8); }; /* Encode a short w/o modelling. */ RangeCoder.prototype.encodeShort = function(s) { this.encodeShift(1, s, 16); }; /* Finish encoding */ /* returns number of bytes written */ RangeCoder.prototype.encodeFinish = function() { var outputStream = this.stream; enc_normalize(this, outputStream); this.bytecount += 5; var tmp = this.low >>> SHIFT_BITS; if ((this.low & (Bottom_value-1)) >= ((this.bytecount&0xFFFFFF)>>>1)) { tmp++; } if (tmp > 0xFF) { /* we have a carry */ outputStream.writeByte(this.buffer + 1); for (; this.help; this.help--) outputStream.writeByte(0x00); } else { /* no carry */ outputStream.writeByte(this.buffer); for (; this.help; this.help--) outputStream.writeByte(0xFF); } outputStream.writeByte(tmp & 0xFF); // XXX: i'm pretty sure these could be three arbitrary bytes // they are consumed by the decoder at the end outputStream.writeByte((this.bytecount >>> 16) & 0xFF); outputStream.writeByte((this.bytecount >>> 8) & 0xFF); outputStream.writeByte((this.bytecount ) & 0xFF); return this.bytecount; }; /* Start the decoder; you need to provide the *second* byte from the * datastream. (The first byte was provided to startEncoding and is * ignored by the decoder.) */ RangeCoder.prototype.decodeStart = function(skipInitialRead) { var c = skipInitialRead ? 0 : this.stream.readByte(); if (typeof(c) !== 'number' || c < 0) { return c; // EOF } this.buffer = this.stream.readByte(); this.low = this.buffer >>> (8 - EXTRA_BITS); this.range = 1 << EXTRA_BITS; return c; }; var dec_normalize = function(rc, inputStream) { while (rc.range <= Bottom_value) { rc.low = (rc.low << 8) | ((rc.buffer << EXTRA_BITS) & 0xFF); /* rc.low could be negative here; don't fix it quite yet */ rc.buffer = inputStream.readByte(); rc.low |= rc.buffer >>> (8-EXTRA_BITS); rc.low = rc.low >>> 0; /* fix it now */ rc.range = (rc.range << 8) >>> 0; /* ensure stays positive */ } }; /* Calculate cumulative frequency for next symbol. Does NO update!*/ /* rc is the range coder to be used */ /* tot_f is the total frequency */ /* or: totf is (code_value)1<<shift */ /* returns the <= cumulative frequency */ RangeCoder.prototype.decodeCulFreq = function(tot_f) { dec_normalize(this, this.stream); this.help = (this.range / tot_f) >>> 0; // note coercion to integer var tmp = (this.low / this.help) >>> 0; // again return (tmp >= tot_f ? tot_f-1 : tmp); }; RangeCoder.prototype.decodeCulShift = function(shift) { dec_normalize(this, this.stream); this.help = this.range >>> shift; var tmp = (this.low / this.help) >>> 0; // coercion to unsigned // shift is less than 31, so shift below will remain positive return ((tmp>>>shift) ? (1<<shift)-1 : tmp); }; /* Update decoding state */ /* rc is the range coder to be used */ /* sy_f is the interval length (frequency of the symbol) */ /* lt_f is the lower end (frequency sum of < symbols) */ /* tot_f is the total interval length (total frequency sum) */ RangeCoder.prototype.decodeUpdate = function(sy_f, lt_f, tot_f) { var tmp = this.help * lt_f; // should not overflow! this.low -= tmp; if (lt_f + sy_f < tot_f) { this.range = (this.help * sy_f); } else { this.range -= tmp; } }; /* Decode a bit w/o modelling. */ RangeCoder.prototype.decodeBit = function() { var tmp = this.decodeCulShift(1); this.decodeUpdate(1, tmp, 1<<1); return tmp; }; /* decode a byte w/o modelling */ RangeCoder.prototype.decodeByte = function() { var tmp = this.decodeCulShift(8); this.decodeUpdate(1, tmp, 1<<8); return tmp; }; /* decode a short w/o modelling */ RangeCoder.prototype.decodeShort = function() { var tmp = this.decodeCulShift(16); this.decodeUpdate(1, tmp, 1<<16); return tmp; }; /* Finish decoding */ RangeCoder.prototype.decodeFinish = function() { /* normalize to use up all bytes */ dec_normalize(this, this.stream); }; /** Utility functions */ // bitstream interface RangeCoder.prototype.writeBit = RangeCoder.prototype.encodeBit; RangeCoder.prototype.readBit = RangeCoder.prototype.decodeBit; // stream interface RangeCoder.prototype.writeByte = RangeCoder.prototype.encodeByte; RangeCoder.prototype.readByte = RangeCoder.prototype.decodeByte; return RangeCoder; });