Source: lib/transmuxer/ec3.js

  1. /*! @license
  2. * Shaka Player
  3. * Copyright 2016 Google LLC
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. goog.provide('shaka.transmuxer.Ec3');
  7. goog.require('shaka.util.ExpGolomb');
  8. /**
  9. * EC3 utils
  10. */
  11. shaka.transmuxer.Ec3 = class {
  12. /**
  13. * @param {!Uint8Array} data
  14. * @param {!number} offset
  15. * @return {?{
  16. * sampleRate: number,
  17. * channelCount: number,
  18. * audioConfig: !Uint8Array,
  19. * frameLength: number,
  20. * }}
  21. */
  22. static parseFrame(data, offset) {
  23. if (offset + 8 > data.length) {
  24. // not enough bytes left
  25. return null;
  26. }
  27. if (!shaka.transmuxer.Ec3.probe(data, offset)) {
  28. return null;
  29. }
  30. const gb = new shaka.util.ExpGolomb(data.subarray(offset + 2));
  31. // Skip stream_type
  32. gb.skipBits(2);
  33. // Skip sub_stream_id
  34. gb.skipBits(3);
  35. const frameLength = (gb.readBits(11) + 1) << 1;
  36. let samplingRateCode = gb.readBits(2);
  37. let sampleRate = null;
  38. let numBlocksCode = null;
  39. if (samplingRateCode == 0x03) {
  40. samplingRateCode = gb.readBits(2);
  41. sampleRate = [24000, 22060, 16000][samplingRateCode];
  42. numBlocksCode = 3;
  43. } else {
  44. sampleRate = [48000, 44100, 32000][samplingRateCode];
  45. numBlocksCode = gb.readBits(2);
  46. }
  47. const channelMode = gb.readBits(3);
  48. const lowFrequencyEffectsChannelOn = gb.readBits(1);
  49. const bitStreamIdentification = gb.readBits(5);
  50. if (offset + frameLength > data.byteLength) {
  51. return null;
  52. }
  53. const channelsMap = [2, 1, 2, 3, 3, 4, 4, 5];
  54. const numBlocksMap = [1, 2, 3, 6];
  55. const numBlocks = numBlocksMap[numBlocksCode];
  56. const dataRateSub =
  57. Math.floor((frameLength * sampleRate) / (numBlocks * 16));
  58. const config = new Uint8Array([
  59. ((dataRateSub & 0x1FE0) >> 5),
  60. ((dataRateSub & 0x001F) << 3), // num_ind_sub = zero
  61. (sampleRate << 6) | (bitStreamIdentification << 1) | (0 << 0),
  62. (0 << 7) | (0 << 4) |
  63. (channelMode << 1) | (lowFrequencyEffectsChannelOn << 0),
  64. (0 << 5) | (0 << 1) | (0 << 0),
  65. ]);
  66. return {
  67. sampleRate,
  68. channelCount: channelsMap[channelMode] + lowFrequencyEffectsChannelOn,
  69. audioConfig: config,
  70. frameLength,
  71. };
  72. }
  73. /**
  74. * @param {!Uint8Array} data
  75. * @param {!number} offset
  76. * @return {boolean}
  77. */
  78. static probe(data, offset) {
  79. // search 16-bit 0x0B77 sync word
  80. const syncWord = (data[offset] << 8) | (data[offset + 1] << 0);
  81. if (syncWord === 0x0B77) {
  82. return true;
  83. } else {
  84. return false;
  85. }
  86. }
  87. };
  88. /**
  89. * @const {number}
  90. */
  91. shaka.transmuxer.Ec3.EC3_SAMPLES_PER_FRAME = 1536;