nal-helpers.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import { bytesMatch, toUint8 } from './byte-helpers.js';
  2. export var NAL_TYPE_ONE = toUint8([0x00, 0x00, 0x00, 0x01]);
  3. export var NAL_TYPE_TWO = toUint8([0x00, 0x00, 0x01]);
  4. export var EMULATION_PREVENTION = toUint8([0x00, 0x00, 0x03]);
  5. /**
  6. * Expunge any "Emulation Prevention" bytes from a "Raw Byte
  7. * Sequence Payload"
  8. *
  9. * @param data {Uint8Array} the bytes of a RBSP from a NAL
  10. * unit
  11. * @return {Uint8Array} the RBSP without any Emulation
  12. * Prevention Bytes
  13. */
  14. export var discardEmulationPreventionBytes = function discardEmulationPreventionBytes(bytes) {
  15. var positions = [];
  16. var i = 1; // Find all `Emulation Prevention Bytes`
  17. while (i < bytes.length - 2) {
  18. if (bytesMatch(bytes.subarray(i, i + 3), EMULATION_PREVENTION)) {
  19. positions.push(i + 2);
  20. i++;
  21. }
  22. i++;
  23. } // If no Emulation Prevention Bytes were found just return the original
  24. // array
  25. if (positions.length === 0) {
  26. return bytes;
  27. } // Create a new array to hold the NAL unit data
  28. var newLength = bytes.length - positions.length;
  29. var newData = new Uint8Array(newLength);
  30. var sourceIndex = 0;
  31. for (i = 0; i < newLength; sourceIndex++, i++) {
  32. if (sourceIndex === positions[0]) {
  33. // Skip this byte
  34. sourceIndex++; // Remove this position index
  35. positions.shift();
  36. }
  37. newData[i] = bytes[sourceIndex];
  38. }
  39. return newData;
  40. };
  41. export var findNal = function findNal(bytes, dataType, types, nalLimit) {
  42. if (nalLimit === void 0) {
  43. nalLimit = Infinity;
  44. }
  45. bytes = toUint8(bytes);
  46. types = [].concat(types);
  47. var i = 0;
  48. var nalStart;
  49. var nalsFound = 0; // keep searching until:
  50. // we reach the end of bytes
  51. // we reach the maximum number of nals they want to seach
  52. // NOTE: that we disregard nalLimit when we have found the start
  53. // of the nal we want so that we can find the end of the nal we want.
  54. while (i < bytes.length && (nalsFound < nalLimit || nalStart)) {
  55. var nalOffset = void 0;
  56. if (bytesMatch(bytes.subarray(i), NAL_TYPE_ONE)) {
  57. nalOffset = 4;
  58. } else if (bytesMatch(bytes.subarray(i), NAL_TYPE_TWO)) {
  59. nalOffset = 3;
  60. } // we are unsynced,
  61. // find the next nal unit
  62. if (!nalOffset) {
  63. i++;
  64. continue;
  65. }
  66. nalsFound++;
  67. if (nalStart) {
  68. return discardEmulationPreventionBytes(bytes.subarray(nalStart, i));
  69. }
  70. var nalType = void 0;
  71. if (dataType === 'h264') {
  72. nalType = bytes[i + nalOffset] & 0x1f;
  73. } else if (dataType === 'h265') {
  74. nalType = bytes[i + nalOffset] >> 1 & 0x3f;
  75. }
  76. if (types.indexOf(nalType) !== -1) {
  77. nalStart = i + nalOffset;
  78. } // nal header is 1 length for h264, and 2 for h265
  79. i += nalOffset + (dataType === 'h264' ? 1 : 2);
  80. }
  81. return bytes.subarray(0, 0);
  82. };
  83. export var findH264Nal = function findH264Nal(bytes, type, nalLimit) {
  84. return findNal(bytes, 'h264', type, nalLimit);
  85. };
  86. export var findH265Nal = function findH265Nal(bytes, type, nalLimit) {
  87. return findNal(bytes, 'h265', type, nalLimit);
  88. };