codec-helpers.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import { padStart, toHexString, toBinaryString } from './byte-helpers.js'; // https://aomediacodec.github.io/av1-isobmff/#av1codecconfigurationbox-syntax
  2. // https://developer.mozilla.org/en-US/docs/Web/Media/Formats/codecs_parameter#AV1
  3. export var getAv1Codec = function getAv1Codec(bytes) {
  4. var codec = '';
  5. var profile = bytes[1] >>> 3;
  6. var level = bytes[1] & 0x1F;
  7. var tier = bytes[2] >>> 7;
  8. var highBitDepth = (bytes[2] & 0x40) >> 6;
  9. var twelveBit = (bytes[2] & 0x20) >> 5;
  10. var monochrome = (bytes[2] & 0x10) >> 4;
  11. var chromaSubsamplingX = (bytes[2] & 0x08) >> 3;
  12. var chromaSubsamplingY = (bytes[2] & 0x04) >> 2;
  13. var chromaSamplePosition = bytes[2] & 0x03;
  14. codec += profile + "." + padStart(level, 2, '0');
  15. if (tier === 0) {
  16. codec += 'M';
  17. } else if (tier === 1) {
  18. codec += 'H';
  19. }
  20. var bitDepth;
  21. if (profile === 2 && highBitDepth) {
  22. bitDepth = twelveBit ? 12 : 10;
  23. } else {
  24. bitDepth = highBitDepth ? 10 : 8;
  25. }
  26. codec += "." + padStart(bitDepth, 2, '0'); // TODO: can we parse color range??
  27. codec += "." + monochrome;
  28. codec += "." + chromaSubsamplingX + chromaSubsamplingY + chromaSamplePosition;
  29. return codec;
  30. };
  31. export var getAvcCodec = function getAvcCodec(bytes) {
  32. var profileId = toHexString(bytes[1]);
  33. var constraintFlags = toHexString(bytes[2] & 0xFC);
  34. var levelId = toHexString(bytes[3]);
  35. return "" + profileId + constraintFlags + levelId;
  36. };
  37. export var getHvcCodec = function getHvcCodec(bytes) {
  38. var codec = '';
  39. var profileSpace = bytes[1] >> 6;
  40. var profileId = bytes[1] & 0x1F;
  41. var tierFlag = (bytes[1] & 0x20) >> 5;
  42. var profileCompat = bytes.subarray(2, 6);
  43. var constraintIds = bytes.subarray(6, 12);
  44. var levelId = bytes[12];
  45. if (profileSpace === 1) {
  46. codec += 'A';
  47. } else if (profileSpace === 2) {
  48. codec += 'B';
  49. } else if (profileSpace === 3) {
  50. codec += 'C';
  51. }
  52. codec += profileId + "."; // ffmpeg does this in big endian
  53. var profileCompatVal = parseInt(toBinaryString(profileCompat).split('').reverse().join(''), 2); // apple does this in little endian...
  54. if (profileCompatVal > 255) {
  55. profileCompatVal = parseInt(toBinaryString(profileCompat), 2);
  56. }
  57. codec += profileCompatVal.toString(16) + ".";
  58. if (tierFlag === 0) {
  59. codec += 'L';
  60. } else {
  61. codec += 'H';
  62. }
  63. codec += levelId;
  64. var constraints = '';
  65. for (var i = 0; i < constraintIds.length; i++) {
  66. var v = constraintIds[i];
  67. if (v) {
  68. if (constraints) {
  69. constraints += '.';
  70. }
  71. constraints += v.toString(16);
  72. }
  73. }
  74. if (constraints) {
  75. codec += "." + constraints;
  76. }
  77. return codec;
  78. };