exp-golomb.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /**
  2. * mux.js
  3. *
  4. * Copyright (c) Brightcove
  5. * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
  6. */
  7. 'use strict';
  8. var ExpGolomb;
  9. /**
  10. * Parser for exponential Golomb codes, a variable-bitwidth number encoding
  11. * scheme used by h264.
  12. */
  13. ExpGolomb = function(workingData) {
  14. var
  15. // the number of bytes left to examine in workingData
  16. workingBytesAvailable = workingData.byteLength,
  17. // the current word being examined
  18. workingWord = 0, // :uint
  19. // the number of bits left to examine in the current word
  20. workingBitsAvailable = 0; // :uint;
  21. // ():uint
  22. this.length = function() {
  23. return (8 * workingBytesAvailable);
  24. };
  25. // ():uint
  26. this.bitsAvailable = function() {
  27. return (8 * workingBytesAvailable) + workingBitsAvailable;
  28. };
  29. // ():void
  30. this.loadWord = function() {
  31. var
  32. position = workingData.byteLength - workingBytesAvailable,
  33. workingBytes = new Uint8Array(4),
  34. availableBytes = Math.min(4, workingBytesAvailable);
  35. if (availableBytes === 0) {
  36. throw new Error('no bytes available');
  37. }
  38. workingBytes.set(workingData.subarray(position,
  39. position + availableBytes));
  40. workingWord = new DataView(workingBytes.buffer).getUint32(0);
  41. // track the amount of workingData that has been processed
  42. workingBitsAvailable = availableBytes * 8;
  43. workingBytesAvailable -= availableBytes;
  44. };
  45. // (count:int):void
  46. this.skipBits = function(count) {
  47. var skipBytes; // :int
  48. if (workingBitsAvailable > count) {
  49. workingWord <<= count;
  50. workingBitsAvailable -= count;
  51. } else {
  52. count -= workingBitsAvailable;
  53. skipBytes = Math.floor(count / 8);
  54. count -= (skipBytes * 8);
  55. workingBytesAvailable -= skipBytes;
  56. this.loadWord();
  57. workingWord <<= count;
  58. workingBitsAvailable -= count;
  59. }
  60. };
  61. // (size:int):uint
  62. this.readBits = function(size) {
  63. var
  64. bits = Math.min(workingBitsAvailable, size), // :uint
  65. valu = workingWord >>> (32 - bits); // :uint
  66. // if size > 31, handle error
  67. workingBitsAvailable -= bits;
  68. if (workingBitsAvailable > 0) {
  69. workingWord <<= bits;
  70. } else if (workingBytesAvailable > 0) {
  71. this.loadWord();
  72. }
  73. bits = size - bits;
  74. if (bits > 0) {
  75. return valu << bits | this.readBits(bits);
  76. }
  77. return valu;
  78. };
  79. // ():uint
  80. this.skipLeadingZeros = function() {
  81. var leadingZeroCount; // :uint
  82. for (leadingZeroCount = 0; leadingZeroCount < workingBitsAvailable; ++leadingZeroCount) {
  83. if ((workingWord & (0x80000000 >>> leadingZeroCount)) !== 0) {
  84. // the first bit of working word is 1
  85. workingWord <<= leadingZeroCount;
  86. workingBitsAvailable -= leadingZeroCount;
  87. return leadingZeroCount;
  88. }
  89. }
  90. // we exhausted workingWord and still have not found a 1
  91. this.loadWord();
  92. return leadingZeroCount + this.skipLeadingZeros();
  93. };
  94. // ():void
  95. this.skipUnsignedExpGolomb = function() {
  96. this.skipBits(1 + this.skipLeadingZeros());
  97. };
  98. // ():void
  99. this.skipExpGolomb = function() {
  100. this.skipBits(1 + this.skipLeadingZeros());
  101. };
  102. // ():uint
  103. this.readUnsignedExpGolomb = function() {
  104. var clz = this.skipLeadingZeros(); // :uint
  105. return this.readBits(clz + 1) - 1;
  106. };
  107. // ():int
  108. this.readExpGolomb = function() {
  109. var valu = this.readUnsignedExpGolomb(); // :int
  110. if (0x01 & valu) {
  111. // the number is odd if the low order bit is set
  112. return (1 + valu) >>> 1; // add 1 to make it even, and divide by 2
  113. }
  114. return -1 * (valu >>> 1); // divide by two then make it negative
  115. };
  116. // Some convenience functions
  117. // :Boolean
  118. this.readBoolean = function() {
  119. return this.readBits(1) === 1;
  120. };
  121. // ():int
  122. this.readUnsignedByte = function() {
  123. return this.readBits(8);
  124. };
  125. this.loadWord();
  126. };
  127. module.exports = ExpGolomb;