adts.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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 Stream = require('../utils/stream.js');
  9. var ONE_SECOND_IN_TS = require('../utils/clock').ONE_SECOND_IN_TS;
  10. var AdtsStream;
  11. var
  12. ADTS_SAMPLING_FREQUENCIES = [
  13. 96000,
  14. 88200,
  15. 64000,
  16. 48000,
  17. 44100,
  18. 32000,
  19. 24000,
  20. 22050,
  21. 16000,
  22. 12000,
  23. 11025,
  24. 8000,
  25. 7350
  26. ];
  27. /*
  28. * Accepts a ElementaryStream and emits data events with parsed
  29. * AAC Audio Frames of the individual packets. Input audio in ADTS
  30. * format is unpacked and re-emitted as AAC frames.
  31. *
  32. * @see http://wiki.multimedia.cx/index.php?title=ADTS
  33. * @see http://wiki.multimedia.cx/?title=Understanding_AAC
  34. */
  35. AdtsStream = function(handlePartialSegments) {
  36. var
  37. buffer,
  38. frameNum = 0;
  39. AdtsStream.prototype.init.call(this);
  40. this.skipWarn_ = function(start, end) {
  41. this.trigger('log', {
  42. level: 'warn',
  43. message: `adts skiping bytes ${start} to ${end} in frame ${frameNum} outside syncword`
  44. });
  45. };
  46. this.push = function(packet) {
  47. var
  48. i = 0,
  49. frameLength,
  50. protectionSkipBytes,
  51. frameEnd,
  52. oldBuffer,
  53. sampleCount,
  54. adtsFrameDuration;
  55. if (!handlePartialSegments) {
  56. frameNum = 0;
  57. }
  58. if (packet.type !== 'audio') {
  59. // ignore non-audio data
  60. return;
  61. }
  62. // Prepend any data in the buffer to the input data so that we can parse
  63. // aac frames the cross a PES packet boundary
  64. if (buffer && buffer.length) {
  65. oldBuffer = buffer;
  66. buffer = new Uint8Array(oldBuffer.byteLength + packet.data.byteLength);
  67. buffer.set(oldBuffer);
  68. buffer.set(packet.data, oldBuffer.byteLength);
  69. } else {
  70. buffer = packet.data;
  71. }
  72. // unpack any ADTS frames which have been fully received
  73. // for details on the ADTS header, see http://wiki.multimedia.cx/index.php?title=ADTS
  74. var skip;
  75. // We use i + 7 here because we want to be able to parse the entire header.
  76. // If we don't have enough bytes to do that, then we definitely won't have a full frame.
  77. while ((i + 7) < buffer.length) {
  78. // Look for the start of an ADTS header..
  79. if ((buffer[i] !== 0xFF) || (buffer[i + 1] & 0xF6) !== 0xF0) {
  80. if (typeof skip !== 'number') {
  81. skip = i;
  82. }
  83. // If a valid header was not found, jump one forward and attempt to
  84. // find a valid ADTS header starting at the next byte
  85. i++;
  86. continue;
  87. }
  88. if (typeof skip === 'number') {
  89. this.skipWarn_(skip, i);
  90. skip = null;
  91. }
  92. // The protection skip bit tells us if we have 2 bytes of CRC data at the
  93. // end of the ADTS header
  94. protectionSkipBytes = (~buffer[i + 1] & 0x01) * 2;
  95. // Frame length is a 13 bit integer starting 16 bits from the
  96. // end of the sync sequence
  97. // NOTE: frame length includes the size of the header
  98. frameLength = ((buffer[i + 3] & 0x03) << 11) |
  99. (buffer[i + 4] << 3) |
  100. ((buffer[i + 5] & 0xe0) >> 5);
  101. sampleCount = ((buffer[i + 6] & 0x03) + 1) * 1024;
  102. adtsFrameDuration = (sampleCount * ONE_SECOND_IN_TS) /
  103. ADTS_SAMPLING_FREQUENCIES[(buffer[i + 2] & 0x3c) >>> 2];
  104. // If we don't have enough data to actually finish this ADTS frame,
  105. // then we have to wait for more data
  106. if ((buffer.byteLength - i) < frameLength) {
  107. break;
  108. }
  109. // Otherwise, deliver the complete AAC frame
  110. this.trigger('data', {
  111. pts: packet.pts + (frameNum * adtsFrameDuration),
  112. dts: packet.dts + (frameNum * adtsFrameDuration),
  113. sampleCount: sampleCount,
  114. audioobjecttype: ((buffer[i + 2] >>> 6) & 0x03) + 1,
  115. channelcount: ((buffer[i + 2] & 1) << 2) |
  116. ((buffer[i + 3] & 0xc0) >>> 6),
  117. samplerate: ADTS_SAMPLING_FREQUENCIES[(buffer[i + 2] & 0x3c) >>> 2],
  118. samplingfrequencyindex: (buffer[i + 2] & 0x3c) >>> 2,
  119. // assume ISO/IEC 14496-12 AudioSampleEntry default of 16
  120. samplesize: 16,
  121. // data is the frame without it's header
  122. data: buffer.subarray(i + 7 + protectionSkipBytes, i + frameLength)
  123. });
  124. frameNum++;
  125. i += frameLength;
  126. }
  127. if (typeof skip === 'number') {
  128. this.skipWarn_(skip, i);
  129. skip = null;
  130. }
  131. // remove processed bytes from the buffer.
  132. buffer = buffer.subarray(i);
  133. };
  134. this.flush = function() {
  135. frameNum = 0;
  136. this.trigger('done');
  137. };
  138. this.reset = function() {
  139. buffer = void 0;
  140. this.trigger('reset');
  141. };
  142. this.endTimeline = function() {
  143. buffer = void 0;
  144. this.trigger('endedtimeline');
  145. };
  146. };
  147. AdtsStream.prototype = new Stream();
  148. module.exports = AdtsStream;