flv-inspector.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  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 tagTypes = {
  9. 0x08: 'audio',
  10. 0x09: 'video',
  11. 0x12: 'metadata'
  12. },
  13. hex = function hex(val) {
  14. return '0x' + ('00' + val.toString(16)).slice(-2).toUpperCase();
  15. },
  16. hexStringList = function hexStringList(data) {
  17. var arr = [],
  18. i;
  19. while (data.byteLength > 0) {
  20. i = 0;
  21. arr.push(hex(data[i++]));
  22. data = data.subarray(i);
  23. }
  24. return arr.join(' ');
  25. },
  26. parseAVCTag = function parseAVCTag(tag, obj) {
  27. var avcPacketTypes = ['AVC Sequence Header', 'AVC NALU', 'AVC End-of-Sequence'],
  28. compositionTime = tag[1] & parseInt('01111111', 2) << 16 | tag[2] << 8 | tag[3];
  29. obj = obj || {};
  30. obj.avcPacketType = avcPacketTypes[tag[0]];
  31. obj.CompositionTime = tag[1] & parseInt('10000000', 2) ? -compositionTime : compositionTime;
  32. if (tag[0] === 1) {
  33. obj.nalUnitTypeRaw = hexStringList(tag.subarray(4, 100));
  34. } else {
  35. obj.data = hexStringList(tag.subarray(4));
  36. }
  37. return obj;
  38. },
  39. parseVideoTag = function parseVideoTag(tag, obj) {
  40. var frameTypes = ['Unknown', 'Keyframe (for AVC, a seekable frame)', 'Inter frame (for AVC, a nonseekable frame)', 'Disposable inter frame (H.263 only)', 'Generated keyframe (reserved for server use only)', 'Video info/command frame'],
  41. codecID = tag[0] & parseInt('00001111', 2);
  42. obj = obj || {};
  43. obj.frameType = frameTypes[(tag[0] & parseInt('11110000', 2)) >>> 4];
  44. obj.codecID = codecID;
  45. if (codecID === 7) {
  46. return parseAVCTag(tag.subarray(1), obj);
  47. }
  48. return obj;
  49. },
  50. parseAACTag = function parseAACTag(tag, obj) {
  51. var packetTypes = ['AAC Sequence Header', 'AAC Raw'];
  52. obj = obj || {};
  53. obj.aacPacketType = packetTypes[tag[0]];
  54. obj.data = hexStringList(tag.subarray(1));
  55. return obj;
  56. },
  57. parseAudioTag = function parseAudioTag(tag, obj) {
  58. var formatTable = ['Linear PCM, platform endian', 'ADPCM', 'MP3', 'Linear PCM, little endian', 'Nellymoser 16-kHz mono', 'Nellymoser 8-kHz mono', 'Nellymoser', 'G.711 A-law logarithmic PCM', 'G.711 mu-law logarithmic PCM', 'reserved', 'AAC', 'Speex', 'MP3 8-Khz', 'Device-specific sound'],
  59. samplingRateTable = ['5.5-kHz', '11-kHz', '22-kHz', '44-kHz'],
  60. soundFormat = (tag[0] & parseInt('11110000', 2)) >>> 4;
  61. obj = obj || {};
  62. obj.soundFormat = formatTable[soundFormat];
  63. obj.soundRate = samplingRateTable[(tag[0] & parseInt('00001100', 2)) >>> 2];
  64. obj.soundSize = (tag[0] & parseInt('00000010', 2)) >>> 1 ? '16-bit' : '8-bit';
  65. obj.soundType = tag[0] & parseInt('00000001', 2) ? 'Stereo' : 'Mono';
  66. if (soundFormat === 10) {
  67. return parseAACTag(tag.subarray(1), obj);
  68. }
  69. return obj;
  70. },
  71. parseGenericTag = function parseGenericTag(tag) {
  72. return {
  73. tagType: tagTypes[tag[0]],
  74. dataSize: tag[1] << 16 | tag[2] << 8 | tag[3],
  75. timestamp: tag[7] << 24 | tag[4] << 16 | tag[5] << 8 | tag[6],
  76. streamID: tag[8] << 16 | tag[9] << 8 | tag[10]
  77. };
  78. },
  79. inspectFlvTag = function inspectFlvTag(tag) {
  80. var header = parseGenericTag(tag);
  81. switch (tag[0]) {
  82. case 0x08:
  83. parseAudioTag(tag.subarray(11), header);
  84. break;
  85. case 0x09:
  86. parseVideoTag(tag.subarray(11), header);
  87. break;
  88. case 0x12:
  89. }
  90. return header;
  91. },
  92. inspectFlv = function inspectFlv(bytes) {
  93. var i = 9,
  94. // header
  95. dataSize,
  96. parsedResults = [],
  97. tag; // traverse the tags
  98. i += 4; // skip previous tag size
  99. while (i < bytes.byteLength) {
  100. dataSize = bytes[i + 1] << 16;
  101. dataSize |= bytes[i + 2] << 8;
  102. dataSize |= bytes[i + 3];
  103. dataSize += 11;
  104. tag = bytes.subarray(i, i + dataSize);
  105. parsedResults.push(inspectFlvTag(tag));
  106. i += dataSize + 4;
  107. }
  108. return parsedResults;
  109. },
  110. textifyFlv = function textifyFlv(flvTagArray) {
  111. return JSON.stringify(flvTagArray, null, 2);
  112. };
  113. module.exports = {
  114. inspectTag: inspectFlvTag,
  115. inspect: inspectFlv,
  116. textify: textifyFlv
  117. };