Home Reference Source

src/demux/exp-golomb.js

  1. /**
  2. * Parser for exponential Golomb codes, a variable-bitwidth number encoding scheme used by h264.
  3. */
  4.  
  5. import { logger } from '../utils/logger';
  6.  
  7. class ExpGolomb {
  8. constructor (data) {
  9. this.data = data;
  10. // the number of bytes left to examine in this.data
  11. this.bytesAvailable = data.byteLength;
  12. // the current word being examined
  13. this.word = 0; // :uint
  14. // the number of bits left to examine in the current word
  15. this.bitsAvailable = 0; // :uint
  16. }
  17.  
  18. // ():void
  19. loadWord () {
  20. let
  21. data = this.data,
  22. bytesAvailable = this.bytesAvailable,
  23. position = data.byteLength - bytesAvailable,
  24. workingBytes = new Uint8Array(4),
  25. availableBytes = Math.min(4, bytesAvailable);
  26. if (availableBytes === 0) {
  27. throw new Error('no bytes available');
  28. }
  29.  
  30. workingBytes.set(data.subarray(position, position + availableBytes));
  31. this.word = new DataView(workingBytes.buffer).getUint32(0);
  32. // track the amount of this.data that has been processed
  33. this.bitsAvailable = availableBytes * 8;
  34. this.bytesAvailable -= availableBytes;
  35. }
  36.  
  37. // (count:int):void
  38. skipBits (count) {
  39. let skipBytes; // :int
  40. if (this.bitsAvailable > count) {
  41. this.word <<= count;
  42. this.bitsAvailable -= count;
  43. } else {
  44. count -= this.bitsAvailable;
  45. skipBytes = count >> 3;
  46. count -= (skipBytes >> 3);
  47. this.bytesAvailable -= skipBytes;
  48. this.loadWord();
  49. this.word <<= count;
  50. this.bitsAvailable -= count;
  51. }
  52. }
  53.  
  54. // (size:int):uint
  55. readBits (size) {
  56. let
  57. bits = Math.min(this.bitsAvailable, size), // :uint
  58. valu = this.word >>> (32 - bits); // :uint
  59. if (size > 32) {
  60. logger.error('Cannot read more than 32 bits at a time');
  61. }
  62.  
  63. this.bitsAvailable -= bits;
  64. if (this.bitsAvailable > 0) {
  65. this.word <<= bits;
  66. } else if (this.bytesAvailable > 0) {
  67. this.loadWord();
  68. }
  69.  
  70. bits = size - bits;
  71. if (bits > 0 && this.bitsAvailable) {
  72. return valu << bits | this.readBits(bits);
  73. } else {
  74. return valu;
  75. }
  76. }
  77.  
  78. // ():uint
  79. skipLZ () {
  80. let leadingZeroCount; // :uint
  81. for (leadingZeroCount = 0; leadingZeroCount < this.bitsAvailable; ++leadingZeroCount) {
  82. if ((this.word & (0x80000000 >>> leadingZeroCount)) !== 0) {
  83. // the first bit of working word is 1
  84. this.word <<= leadingZeroCount;
  85. this.bitsAvailable -= leadingZeroCount;
  86. return leadingZeroCount;
  87. }
  88. }
  89. // we exhausted word and still have not found a 1
  90. this.loadWord();
  91. return leadingZeroCount + this.skipLZ();
  92. }
  93.  
  94. // ():void
  95. skipUEG () {
  96. this.skipBits(1 + this.skipLZ());
  97. }
  98.  
  99. // ():void
  100. skipEG () {
  101. this.skipBits(1 + this.skipLZ());
  102. }
  103.  
  104. // ():uint
  105. readUEG () {
  106. let clz = this.skipLZ(); // :uint
  107. return this.readBits(clz + 1) - 1;
  108. }
  109.  
  110. // ():int
  111. readEG () {
  112. let valu = this.readUEG(); // :int
  113. if (0x01 & valu) {
  114. // the number is odd if the low order bit is set
  115. return (1 + valu) >>> 1; // add 1 to make it even, and divide by 2
  116. } else {
  117. return -1 * (valu >>> 1); // divide by two then make it negative
  118. }
  119. }
  120.  
  121. // Some convenience functions
  122. // :Boolean
  123. readBoolean () {
  124. return this.readBits(1) === 1;
  125. }
  126.  
  127. // ():int
  128. readUByte () {
  129. return this.readBits(8);
  130. }
  131.  
  132. // ():int
  133. readUShort () {
  134. return this.readBits(16);
  135. }
  136. // ():int
  137. readUInt () {
  138. return this.readBits(32);
  139. }
  140.  
  141. /**
  142. * Advance the ExpGolomb decoder past a scaling list. The scaling
  143. * list is optionally transmitted as part of a sequence parameter
  144. * set and is not relevant to transmuxing.
  145. * @param count {number} the number of entries in this scaling list
  146. * @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
  147. */
  148. skipScalingList (count) {
  149. let
  150. lastScale = 8,
  151. nextScale = 8,
  152. j,
  153. deltaScale;
  154. for (j = 0; j < count; j++) {
  155. if (nextScale !== 0) {
  156. deltaScale = this.readEG();
  157. nextScale = (lastScale + deltaScale + 256) % 256;
  158. }
  159. lastScale = (nextScale === 0) ? lastScale : nextScale;
  160. }
  161. }
  162.  
  163. /**
  164. * Read a sequence parameter set and return some interesting video
  165. * properties. A sequence parameter set is the H264 metadata that
  166. * describes the properties of upcoming video frames.
  167. * @param data {Uint8Array} the bytes of a sequence parameter set
  168. * @return {object} an object with configuration parsed from the
  169. * sequence parameter set, including the dimensions of the
  170. * associated video frames.
  171. */
  172. readSPS () {
  173. let
  174. frameCropLeftOffset = 0,
  175. frameCropRightOffset = 0,
  176. frameCropTopOffset = 0,
  177. frameCropBottomOffset = 0,
  178. profileIdc, profileCompat, levelIdc,
  179. numRefFramesInPicOrderCntCycle, picWidthInMbsMinus1,
  180. picHeightInMapUnitsMinus1,
  181. frameMbsOnlyFlag,
  182. scalingListCount,
  183. i,
  184. readUByte = this.readUByte.bind(this),
  185. readBits = this.readBits.bind(this),
  186. readUEG = this.readUEG.bind(this),
  187. readBoolean = this.readBoolean.bind(this),
  188. skipBits = this.skipBits.bind(this),
  189. skipEG = this.skipEG.bind(this),
  190. skipUEG = this.skipUEG.bind(this),
  191. skipScalingList = this.skipScalingList.bind(this);
  192.  
  193. readUByte();
  194. profileIdc = readUByte(); // profile_idc
  195. profileCompat = readBits(5); // constraint_set[0-4]_flag, u(5)
  196. skipBits(3); // reserved_zero_3bits u(3),
  197. levelIdc = readUByte(); // level_idc u(8)
  198. skipUEG(); // seq_parameter_set_id
  199. // some profiles have more optional data we don't need
  200. if (profileIdc === 100 ||
  201. profileIdc === 110 ||
  202. profileIdc === 122 ||
  203. profileIdc === 244 ||
  204. profileIdc === 44 ||
  205. profileIdc === 83 ||
  206. profileIdc === 86 ||
  207. profileIdc === 118 ||
  208. profileIdc === 128) {
  209. let chromaFormatIdc = readUEG();
  210. if (chromaFormatIdc === 3) {
  211. skipBits(1);
  212. } // separate_colour_plane_flag
  213.  
  214. skipUEG(); // bit_depth_luma_minus8
  215. skipUEG(); // bit_depth_chroma_minus8
  216. skipBits(1); // qpprime_y_zero_transform_bypass_flag
  217. if (readBoolean()) { // seq_scaling_matrix_present_flag
  218. scalingListCount = (chromaFormatIdc !== 3) ? 8 : 12;
  219. for (i = 0; i < scalingListCount; i++) {
  220. if (readBoolean()) { // seq_scaling_list_present_flag[ i ]
  221. if (i < 6) {
  222. skipScalingList(16);
  223. } else {
  224. skipScalingList(64);
  225. }
  226. }
  227. }
  228. }
  229. }
  230. skipUEG(); // log2_max_frame_num_minus4
  231. let picOrderCntType = readUEG();
  232. if (picOrderCntType === 0) {
  233. readUEG(); // log2_max_pic_order_cnt_lsb_minus4
  234. } else if (picOrderCntType === 1) {
  235. skipBits(1); // delta_pic_order_always_zero_flag
  236. skipEG(); // offset_for_non_ref_pic
  237. skipEG(); // offset_for_top_to_bottom_field
  238. numRefFramesInPicOrderCntCycle = readUEG();
  239. for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
  240. skipEG();
  241. } // offset_for_ref_frame[ i ]
  242. }
  243. skipUEG(); // max_num_ref_frames
  244. skipBits(1); // gaps_in_frame_num_value_allowed_flag
  245. picWidthInMbsMinus1 = readUEG();
  246. picHeightInMapUnitsMinus1 = readUEG();
  247. frameMbsOnlyFlag = readBits(1);
  248. if (frameMbsOnlyFlag === 0) {
  249. skipBits(1);
  250. } // mb_adaptive_frame_field_flag
  251.  
  252. skipBits(1); // direct_8x8_inference_flag
  253. if (readBoolean()) { // frame_cropping_flag
  254. frameCropLeftOffset = readUEG();
  255. frameCropRightOffset = readUEG();
  256. frameCropTopOffset = readUEG();
  257. frameCropBottomOffset = readUEG();
  258. }
  259. let pixelRatio = [1, 1];
  260. if (readBoolean()) {
  261. // vui_parameters_present_flag
  262. if (readBoolean()) {
  263. // aspect_ratio_info_present_flag
  264. const aspectRatioIdc = readUByte();
  265. switch (aspectRatioIdc) {
  266. case 1: pixelRatio = [1, 1]; break;
  267. case 2: pixelRatio = [12, 11]; break;
  268. case 3: pixelRatio = [10, 11]; break;
  269. case 4: pixelRatio = [16, 11]; break;
  270. case 5: pixelRatio = [40, 33]; break;
  271. case 6: pixelRatio = [24, 11]; break;
  272. case 7: pixelRatio = [20, 11]; break;
  273. case 8: pixelRatio = [32, 11]; break;
  274. case 9: pixelRatio = [80, 33]; break;
  275. case 10: pixelRatio = [18, 11]; break;
  276. case 11: pixelRatio = [15, 11]; break;
  277. case 12: pixelRatio = [64, 33]; break;
  278. case 13: pixelRatio = [160, 99]; break;
  279. case 14: pixelRatio = [4, 3]; break;
  280. case 15: pixelRatio = [3, 2]; break;
  281. case 16: pixelRatio = [2, 1]; break;
  282. case 255: {
  283. pixelRatio = [readUByte() << 8 | readUByte(), readUByte() << 8 | readUByte()];
  284. break;
  285. }
  286. }
  287. }
  288. }
  289. return {
  290. width: Math.ceil((((picWidthInMbsMinus1 + 1) * 16) - frameCropLeftOffset * 2 - frameCropRightOffset * 2)),
  291. height: ((2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16) - ((frameMbsOnlyFlag ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset)),
  292. pixelRatio: pixelRatio
  293. };
  294. }
  295.  
  296. readSliceType () {
  297. // skip NALu type
  298. this.readUByte();
  299. // discard first_mb_in_slice
  300. this.readUEG();
  301. // return slice_type
  302. return this.readUEG();
  303. }
  304. }
  305.  
  306. export default ExpGolomb;