You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
106 lines
2.6 KiB
106 lines
2.6 KiB
import {padStart, toHexString, toBinaryString} from './byte-helpers.js';
|
|
|
|
// https://aomediacodec.github.io/av1-isobmff/#av1codecconfigurationbox-syntax
|
|
// https://developer.mozilla.org/en-US/docs/Web/Media/Formats/codecs_parameter#AV1
|
|
export const getAv1Codec = function(bytes) {
|
|
let codec = '';
|
|
const profile = bytes[1] >>> 3;
|
|
const level = bytes[1] & 0x1F;
|
|
const tier = bytes[2] >>> 7;
|
|
const highBitDepth = (bytes[2] & 0x40) >> 6;
|
|
const twelveBit = (bytes[2] & 0x20) >> 5;
|
|
const monochrome = (bytes[2] & 0x10) >> 4;
|
|
const chromaSubsamplingX = (bytes[2] & 0x08) >> 3;
|
|
const chromaSubsamplingY = (bytes[2] & 0x04) >> 2;
|
|
const chromaSamplePosition = bytes[2] & 0x03;
|
|
|
|
codec += `${profile}.${padStart(level, 2, '0')}`;
|
|
|
|
if (tier === 0) {
|
|
codec += 'M';
|
|
} else if (tier === 1) {
|
|
codec += 'H';
|
|
}
|
|
|
|
let bitDepth;
|
|
|
|
if (profile === 2 && highBitDepth) {
|
|
bitDepth = twelveBit ? 12 : 10;
|
|
} else {
|
|
bitDepth = highBitDepth ? 10 : 8;
|
|
}
|
|
|
|
codec += `.${padStart(bitDepth, 2, '0')}`;
|
|
|
|
// TODO: can we parse color range??
|
|
codec += `.${monochrome}`;
|
|
codec += `.${chromaSubsamplingX}${chromaSubsamplingY}${chromaSamplePosition}`;
|
|
|
|
return codec;
|
|
};
|
|
|
|
export const getAvcCodec = function(bytes) {
|
|
const profileId = toHexString(bytes[1]);
|
|
const constraintFlags = toHexString(bytes[2] & 0xFC);
|
|
const levelId = toHexString(bytes[3]);
|
|
|
|
return `${profileId}${constraintFlags}${levelId}`;
|
|
};
|
|
|
|
export const getHvcCodec = function(bytes) {
|
|
let codec = '';
|
|
const profileSpace = bytes[1] >> 6;
|
|
const profileId = bytes[1] & 0x1F;
|
|
const tierFlag = (bytes[1] & 0x20) >> 5;
|
|
|
|
const profileCompat = bytes.subarray(2, 6);
|
|
const constraintIds = bytes.subarray(6, 12);
|
|
const levelId = bytes[12];
|
|
|
|
if (profileSpace === 1) {
|
|
codec += 'A';
|
|
} else if (profileSpace === 2) {
|
|
codec += 'B';
|
|
} else if (profileSpace === 3) {
|
|
codec += 'C';
|
|
}
|
|
|
|
codec += `${profileId}.`;
|
|
|
|
// ffmpeg does this in big endian
|
|
let profileCompatVal = parseInt(toBinaryString(profileCompat).split('').reverse().join(''), 2);
|
|
|
|
// apple does this in little endian...
|
|
if (profileCompatVal > 255) {
|
|
profileCompatVal = parseInt(toBinaryString(profileCompat), 2);
|
|
}
|
|
|
|
codec += `${profileCompatVal.toString(16)}.`;
|
|
|
|
if (tierFlag === 0) {
|
|
codec += 'L';
|
|
} else {
|
|
codec += 'H';
|
|
}
|
|
|
|
codec += levelId;
|
|
|
|
let constraints = '';
|
|
|
|
for (let i = 0; i < constraintIds.length; i++) {
|
|
const v = constraintIds[i];
|
|
|
|
if (v) {
|
|
if (constraints) {
|
|
constraints += '.';
|
|
}
|
|
constraints += v.toString(16);
|
|
}
|
|
}
|
|
|
|
if (constraints) {
|
|
codec += `.${constraints}`;
|
|
}
|
|
|
|
return codec;
|
|
};
|
|
|