154 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			154 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  * mux.js
 | |
|  *
 | |
|  * Copyright (c) Brightcove
 | |
|  * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
 | |
|  */
 | |
| 'use strict';
 | |
| 
 | |
| var ExpGolomb;
 | |
| /**
 | |
|  * Parser for exponential Golomb codes, a variable-bitwidth number encoding
 | |
|  * scheme used by h264.
 | |
|  */
 | |
| 
 | |
| ExpGolomb = 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
 | |
| 
 | |
|     workingBitsAvailable -= bits;
 | |
| 
 | |
|     if (workingBitsAvailable > 0) {
 | |
|       workingWord <<= bits;
 | |
|     } else if (workingBytesAvailable > 0) {
 | |
|       this.loadWord();
 | |
|     }
 | |
| 
 | |
|     bits = size - bits;
 | |
| 
 | |
|     if (bits > 0) {
 | |
|       return valu << bits | this.readBits(bits);
 | |
|     }
 | |
| 
 | |
|     return valu;
 | |
|   }; // ():uint
 | |
| 
 | |
| 
 | |
|   this.skipLeadingZeros = function () {
 | |
|     var leadingZeroCount; // :uint
 | |
| 
 | |
|     for (leadingZeroCount = 0; leadingZeroCount < workingBitsAvailable; ++leadingZeroCount) {
 | |
|       if ((workingWord & 0x80000000 >>> leadingZeroCount) !== 0) {
 | |
|         // the first bit of working word is 1
 | |
|         workingWord <<= leadingZeroCount;
 | |
|         workingBitsAvailable -= leadingZeroCount;
 | |
|         return leadingZeroCount;
 | |
|       }
 | |
|     } // we exhausted workingWord and still have not found a 1
 | |
| 
 | |
| 
 | |
|     this.loadWord();
 | |
|     return leadingZeroCount + this.skipLeadingZeros();
 | |
|   }; // ():void
 | |
| 
 | |
| 
 | |
|   this.skipUnsignedExpGolomb = function () {
 | |
|     this.skipBits(1 + this.skipLeadingZeros());
 | |
|   }; // ():void
 | |
| 
 | |
| 
 | |
|   this.skipExpGolomb = function () {
 | |
|     this.skipBits(1 + this.skipLeadingZeros());
 | |
|   }; // ():uint
 | |
| 
 | |
| 
 | |
|   this.readUnsignedExpGolomb = function () {
 | |
|     var clz = this.skipLeadingZeros(); // :uint
 | |
| 
 | |
|     return this.readBits(clz + 1) - 1;
 | |
|   }; // ():int
 | |
| 
 | |
| 
 | |
|   this.readExpGolomb = function () {
 | |
|     var valu = this.readUnsignedExpGolomb(); // :int
 | |
| 
 | |
|     if (0x01 & valu) {
 | |
|       // the number is odd if the low order bit is set
 | |
|       return 1 + valu >>> 1; // add 1 to make it even, and divide by 2
 | |
|     }
 | |
| 
 | |
|     return -1 * (valu >>> 1); // divide by two then make it negative
 | |
|   }; // Some convenience functions
 | |
|   // :Boolean
 | |
| 
 | |
| 
 | |
|   this.readBoolean = function () {
 | |
|     return this.readBits(1) === 1;
 | |
|   }; // ():int
 | |
| 
 | |
| 
 | |
|   this.readUnsignedByte = function () {
 | |
|     return this.readBits(8);
 | |
|   };
 | |
| 
 | |
|   this.loadWord();
 | |
| };
 | |
| 
 | |
| module.exports = ExpGolomb; | 
