buffer.js 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. JSMpeg.BitBuffer = (function(){ "use strict";
  2. var BitBuffer = function(bufferOrLength, mode) {
  3. if (typeof(bufferOrLength) === 'object') {
  4. this.bytes = (bufferOrLength instanceof Uint8Array)
  5. ? bufferOrLength
  6. : new Uint8Array(bufferOrLength);
  7. this.byteLength = this.bytes.length;
  8. }
  9. else {
  10. this.bytes = new Uint8Array(bufferOrLength || 1024*1024);
  11. this.byteLength = 0;
  12. }
  13. this.mode = mode || BitBuffer.MODE.EXPAND;
  14. this.index = 0;
  15. };
  16. BitBuffer.prototype.resize = function(size) {
  17. var newBytes = new Uint8Array(size);
  18. if (this.byteLength !== 0) {
  19. this.byteLength = Math.min(this.byteLength, size);
  20. newBytes.set(this.bytes, 0, this.byteLength);
  21. }
  22. this.bytes = newBytes;
  23. this.index = Math.min(this.index, this.byteLength << 3);
  24. };
  25. BitBuffer.prototype.evict = function(sizeNeeded) {
  26. var bytePos = this.index >> 3,
  27. available = this.bytes.length - this.byteLength;
  28. // If the current index is the write position, we can simply reset both
  29. // to 0. Also reset (and throw away yet unread data) if we won't be able
  30. // to fit the new data in even after a normal eviction.
  31. if (
  32. this.index === this.byteLength << 3 ||
  33. sizeNeeded > available + bytePos // emergency evac
  34. ) {
  35. this.byteLength = 0;
  36. this.index = 0;
  37. return;
  38. }
  39. else if (bytePos === 0) {
  40. // Nothing read yet - we can't evict anything
  41. return;
  42. }
  43. // Some browsers don't support copyWithin() yet - we may have to do
  44. // it manually using set and a subarray
  45. if (this.bytes.copyWithin) {
  46. this.bytes.copyWithin(0, bytePos, this.byteLength);
  47. }
  48. else {
  49. this.bytes.set(this.bytes.subarray(bytePos, this.byteLength));
  50. }
  51. this.byteLength = this.byteLength - bytePos;
  52. this.index -= bytePos << 3;
  53. return;
  54. };
  55. BitBuffer.prototype.write = function(buffers) {
  56. var isArrayOfBuffers = (typeof(buffers[0]) === 'object'),
  57. totalLength = 0,
  58. available = this.bytes.length - this.byteLength;
  59. // Calculate total byte length
  60. if (isArrayOfBuffers) {
  61. var totalLength = 0;
  62. for (var i = 0; i < buffers.length; i++) {
  63. totalLength += buffers[i].byteLength;
  64. }
  65. }
  66. else {
  67. totalLength = buffers.byteLength;
  68. }
  69. // Do we need to resize or evict?
  70. if (totalLength > available) {
  71. if (this.mode === BitBuffer.MODE.EXPAND) {
  72. var newSize = Math.max(
  73. this.bytes.length * 2,
  74. totalLength - available
  75. );
  76. this.resize(newSize)
  77. }
  78. else {
  79. this.evict(totalLength);
  80. }
  81. }
  82. if (isArrayOfBuffers) {
  83. for (var i = 0; i < buffers.length; i++) {
  84. this.appendSingleBuffer(buffers[i]);
  85. }
  86. }
  87. else {
  88. this.appendSingleBuffer(buffers);
  89. }
  90. };
  91. BitBuffer.prototype.appendSingleBuffer = function(buffer) {
  92. buffer = buffer instanceof Uint8Array
  93. ? buffer
  94. : new Uint8Array(buffer);
  95. this.bytes.set(buffer, this.byteLength);
  96. this.byteLength += buffer.length;
  97. };
  98. BitBuffer.prototype.findNextStartCode = function() {
  99. for (var i = (this.index+7 >> 3); i < this.byteLength; i++) {
  100. if(
  101. this.bytes[i] == 0x00 &&
  102. this.bytes[i+1] == 0x00 &&
  103. this.bytes[i+2] == 0x01
  104. ) {
  105. this.index = (i+4) << 3;
  106. return this.bytes[i+3];
  107. }
  108. }
  109. this.index = (this.byteLength << 3);
  110. return -1;
  111. };
  112. BitBuffer.prototype.findStartCode = function(code) {
  113. var current = 0;
  114. while (true) {
  115. current = this.findNextStartCode();
  116. if (current === code || current === -1) {
  117. return current;
  118. }
  119. }
  120. return -1;
  121. };
  122. BitBuffer.prototype.nextBytesAreStartCode = function() {
  123. var i = (this.index+7 >> 3);
  124. return (
  125. i >= this.byteLength || (
  126. this.bytes[i] == 0x00 &&
  127. this.bytes[i+1] == 0x00 &&
  128. this.bytes[i+2] == 0x01
  129. )
  130. );
  131. };
  132. BitBuffer.prototype.peek = function(count) {
  133. var offset = this.index;
  134. var value = 0;
  135. while (count) {
  136. var currentByte = this.bytes[offset >> 3],
  137. remaining = 8 - (offset & 7), // remaining bits in byte
  138. read = remaining < count ? remaining : count, // bits in this run
  139. shift = remaining - read,
  140. mask = (0xff >> (8-read));
  141. value = (value << read) | ((currentByte & (mask << shift)) >> shift);
  142. offset += read;
  143. count -= read;
  144. }
  145. return value;
  146. }
  147. BitBuffer.prototype.read = function(count) {
  148. var value = this.peek(count);
  149. this.index += count;
  150. return value;
  151. };
  152. BitBuffer.prototype.skip = function(count) {
  153. return (this.index += count);
  154. };
  155. BitBuffer.prototype.rewind = function(count) {
  156. this.index = Math.max(this.index - count, 0);
  157. };
  158. BitBuffer.prototype.has = function(count) {
  159. return ((this.byteLength << 3) - this.index) >= count;
  160. };
  161. BitBuffer.MODE = {
  162. EVICT: 1,
  163. EXPAND: 2
  164. };
  165. return BitBuffer;
  166. })();