codec-helpers.js
2.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
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;
};