imagescript 3.2.1 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -10
- package/THIRD_PARTY_NOTICES.md +298 -2
- package/dist/animation.d.ts +25 -8
- package/dist/animation.js +44 -13
- package/dist/codecs/av1/cdef.js +197 -0
- package/dist/codecs/av1/data.js +141 -0
- package/dist/codecs/av1/decode.js +1769 -0
- package/dist/codecs/av1/filmgrain.js +219 -0
- package/dist/codecs/av1/frame.js +114 -0
- package/dist/codecs/av1/ipred.js +491 -0
- package/dist/codecs/av1/itx.js +950 -0
- package/dist/codecs/av1/loopfilter.js +149 -0
- package/dist/codecs/av1/msac.js +161 -0
- package/dist/codecs/av1/obu.js +516 -0
- package/dist/codecs/av1/postfilter.js +28 -0
- package/dist/codecs/av1/restoration.js +193 -0
- package/dist/codecs/av1/tables.js +160 -0
- package/dist/codecs/avif.js +581 -0
- package/dist/codecs/bmp.js +317 -0
- package/dist/codecs/crc.js +5 -0
- package/dist/codecs/gif.js +10 -35
- package/dist/codecs/hdr.d.ts +25 -0
- package/dist/codecs/hdr.js +201 -0
- package/dist/codecs/ico.js +48 -0
- package/dist/codecs/jpeg.js +11 -28
- package/dist/codecs/jxl/bits.js +126 -0
- package/dist/codecs/jxl/blend.js +117 -0
- package/dist/codecs/jxl/color.js +116 -0
- package/dist/codecs/jxl/dct.js +404 -0
- package/dist/codecs/jxl/entropy.js +556 -0
- package/dist/codecs/jxl/features.js +325 -0
- package/dist/codecs/jxl/filters.js +119 -0
- package/dist/codecs/jxl/frame-header.js +195 -0
- package/dist/codecs/jxl/frame.js +319 -0
- package/dist/codecs/jxl/headers.js +249 -0
- package/dist/codecs/jxl/idct.js +484 -0
- package/dist/codecs/jxl/modular.js +688 -0
- package/dist/codecs/jxl/quant.js +219 -0
- package/dist/codecs/jxl/upsample.js +52 -0
- package/dist/codecs/jxl/vardct.js +472 -0
- package/dist/codecs/jxl.js +89 -0
- package/dist/codecs/netpbm.js +239 -0
- package/dist/codecs/png.js +22 -10
- package/dist/codecs/qoi.js +150 -0
- package/dist/codecs/tga.js +3 -1
- package/dist/codecs/tiff.js +7 -2
- package/dist/codecs/vp8-enc-dsp.js +932 -0
- package/dist/codecs/vp8-enc-tables.js +78 -0
- package/dist/codecs/vp8-enc.js +1930 -0
- package/dist/codecs/vp8.js +3 -1
- package/dist/codecs/vp8l.js +126 -58
- package/dist/codecs/webp.js +47 -11
- package/dist/codecs/zlib.js +81 -69
- package/dist/frame.d.ts +1 -0
- package/dist/frame.js +4 -2
- package/dist/gif.d.ts +1 -0
- package/dist/gif.js +2 -2
- package/dist/image-type.d.ts +15 -1
- package/dist/image-type.js +45 -2
- package/dist/image.d.ts +89 -13
- package/dist/image.js +266 -113
- package/dist/index.d.ts +3 -2
- package/dist/index.js +4 -4
- package/dist/render/bidi.js +350 -0
- package/dist/render/buffer.js +362 -0
- package/dist/render/color.js +164 -0
- package/dist/render/colr.js +523 -0
- package/dist/render/font.js +173 -241
- package/dist/render/hinting.js +38 -22
- package/dist/render/layout.js +1553 -0
- package/dist/render/linebreak.js +210 -0
- package/dist/render/segment.js +106 -0
- package/dist/render/shape.js +984 -0
- package/dist/render/shapers/arabic.js +284 -0
- package/dist/render/shapers/hangul.js +142 -0
- package/dist/render/shapers/hebrew.js +49 -0
- package/dist/render/shapers/index.js +52 -0
- package/dist/render/shapers/indic.js +579 -0
- package/dist/render/shapers/khmer.js +104 -0
- package/dist/render/shapers/machine.js +129 -0
- package/dist/render/shapers/myanmar.js +121 -0
- package/dist/render/shapers/syllabic.js +100 -0
- package/dist/render/shapers/thai.js +125 -0
- package/dist/render/shapers/use.js +235 -0
- package/dist/render/svg.js +102 -23
- package/dist/render/text.js +373 -103
- package/dist/render/unicode-data.js +63 -0
- package/dist/render/unicode.js +50 -0
- package/dist/text-layout.d.ts +4 -1
- package/dist/text-layout.js +2 -2
- package/dist/util/alpha.js +43 -0
- package/dist/util/blur.js +20 -33
- package/dist/util/bytes.js +40 -0
- package/dist/util/limits.js +34 -0
- package/dist/util/options.js +7 -0
- package/dist/util/resample.js +126 -7
- package/dist/util/rotate.js +43 -0
- package/dist/version.js +1 -1
- package/licenses/HarfBuzz.txt +42 -0
- package/licenses/Unicode-3.0.txt +39 -0
- package/package.json +25 -2
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* AV1 open bitstream units: the sequence header, the frame headers of intra frames and the tile groups, ported from
|
|
3
|
+
* dav1d (src/obu.c, src/getbits.c). Copyright (c) 2018-2019, VideoLAN and dav1d authors, BSD-2-Clause License (see
|
|
4
|
+
* THIRD_PARTY_NOTICES.md)
|
|
5
|
+
*/
|
|
6
|
+
export class BitReader {
|
|
7
|
+
data;
|
|
8
|
+
end;
|
|
9
|
+
pos;
|
|
10
|
+
constructor(data, start, end) {
|
|
11
|
+
this.data = data;
|
|
12
|
+
this.end = end;
|
|
13
|
+
this.pos = start * 8;
|
|
14
|
+
}
|
|
15
|
+
bit() {
|
|
16
|
+
if (this.pos >= this.end * 8)
|
|
17
|
+
throw new Error('AV1: truncated header');
|
|
18
|
+
const v = this.data[this.pos >> 3] >> (7 - (this.pos & 7)) & 1;
|
|
19
|
+
this.pos++;
|
|
20
|
+
return v;
|
|
21
|
+
}
|
|
22
|
+
bits(n) {
|
|
23
|
+
let v = 0;
|
|
24
|
+
for (let i = 0; i < n; i++)
|
|
25
|
+
v = v * 2 + this.bit();
|
|
26
|
+
return v;
|
|
27
|
+
}
|
|
28
|
+
sbits(n) {
|
|
29
|
+
const v = this.bits(n + 1);
|
|
30
|
+
return v >= 2 ** n ? v - 2 ** (n + 1) : v;
|
|
31
|
+
}
|
|
32
|
+
uvlc() {
|
|
33
|
+
let zeros = 0;
|
|
34
|
+
while (!this.bit())
|
|
35
|
+
if (++zeros >= 32)
|
|
36
|
+
return 0xffffffff;
|
|
37
|
+
return 2 ** zeros - 1 + this.bits(zeros);
|
|
38
|
+
}
|
|
39
|
+
uniform(max) {
|
|
40
|
+
let l = 0;
|
|
41
|
+
while (2 ** l <= max)
|
|
42
|
+
l++;
|
|
43
|
+
const m = 2 ** l - max;
|
|
44
|
+
const v = this.bits(l - 1);
|
|
45
|
+
return v < m ? v : (v << 1) - m + this.bit();
|
|
46
|
+
}
|
|
47
|
+
leb128() {
|
|
48
|
+
let v = 0;
|
|
49
|
+
for (let i = 0; i < 8; i++) {
|
|
50
|
+
const b = this.bits(8);
|
|
51
|
+
v += (b & 0x7f) * 2 ** (i * 7);
|
|
52
|
+
if (!(b & 0x80))
|
|
53
|
+
return v;
|
|
54
|
+
}
|
|
55
|
+
throw new Error('AV1: invalid leb128');
|
|
56
|
+
}
|
|
57
|
+
align() {
|
|
58
|
+
this.pos = this.pos + 7 & ~7;
|
|
59
|
+
}
|
|
60
|
+
get byte() {
|
|
61
|
+
return this.pos + 7 >> 3;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const ADAPTIVE = 2;
|
|
65
|
+
export function parseSequenceHeader(r) {
|
|
66
|
+
const profile = r.bits(3);
|
|
67
|
+
if (profile > 2)
|
|
68
|
+
throw new Error(`AV1: unsupported profile ${profile}`);
|
|
69
|
+
r.bit();
|
|
70
|
+
const reducedStillPicture = !!r.bit();
|
|
71
|
+
const operatingPoints = [];
|
|
72
|
+
let decoderModelInfo = false, equalPictureInterval = false, bufferDelayLength = 0, bufferRemovalDelayLength = 0, framePresentationDelayLength = 0;
|
|
73
|
+
if (reducedStillPicture) {
|
|
74
|
+
r.bits(5);
|
|
75
|
+
operatingPoints.push({ idc: 0, decoderModel: false });
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
if (r.bit()) {
|
|
79
|
+
r.bits(32);
|
|
80
|
+
r.bits(32);
|
|
81
|
+
equalPictureInterval = !!r.bit();
|
|
82
|
+
if (equalPictureInterval)
|
|
83
|
+
r.uvlc();
|
|
84
|
+
decoderModelInfo = !!r.bit();
|
|
85
|
+
if (decoderModelInfo) {
|
|
86
|
+
bufferDelayLength = r.bits(5) + 1;
|
|
87
|
+
r.bits(32);
|
|
88
|
+
bufferRemovalDelayLength = r.bits(5) + 1;
|
|
89
|
+
framePresentationDelayLength = r.bits(5) + 1;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const displayModelInfo = !!r.bit();
|
|
93
|
+
const count = r.bits(5) + 1;
|
|
94
|
+
for (let i = 0; i < count; i++) {
|
|
95
|
+
const idc = r.bits(12);
|
|
96
|
+
const level = r.bits(5);
|
|
97
|
+
if (level >> 2 > 1)
|
|
98
|
+
r.bit();
|
|
99
|
+
let decoderModel = false;
|
|
100
|
+
if (decoderModelInfo && (decoderModel = !!r.bit())) {
|
|
101
|
+
r.bits(bufferDelayLength);
|
|
102
|
+
r.bits(bufferDelayLength);
|
|
103
|
+
r.bit();
|
|
104
|
+
}
|
|
105
|
+
if (displayModelInfo && r.bit())
|
|
106
|
+
r.bits(4);
|
|
107
|
+
operatingPoints.push({ idc, decoderModel });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const widthBits = r.bits(4) + 1, heightBits = r.bits(4) + 1;
|
|
111
|
+
const maxWidth = r.bits(widthBits) + 1, maxHeight = r.bits(heightBits) + 1;
|
|
112
|
+
let frameIdBits = 0, deltaFrameIdBits = 0;
|
|
113
|
+
if (!reducedStillPicture && r.bit()) {
|
|
114
|
+
deltaFrameIdBits = r.bits(4) + 2;
|
|
115
|
+
frameIdBits = r.bits(3) + deltaFrameIdBits + 1;
|
|
116
|
+
}
|
|
117
|
+
const sb128 = !!r.bit(), filterIntra = !!r.bit(), intraEdgeFilter = !!r.bit();
|
|
118
|
+
let screenContentTools = ADAPTIVE, forceIntegerMv = ADAPTIVE, orderHintBits = 0;
|
|
119
|
+
if (!reducedStillPicture) {
|
|
120
|
+
r.bit();
|
|
121
|
+
r.bit();
|
|
122
|
+
r.bit();
|
|
123
|
+
r.bit();
|
|
124
|
+
const orderHint = r.bit();
|
|
125
|
+
if (orderHint) {
|
|
126
|
+
r.bit();
|
|
127
|
+
r.bit();
|
|
128
|
+
}
|
|
129
|
+
screenContentTools = r.bit() ? ADAPTIVE : r.bit();
|
|
130
|
+
forceIntegerMv = screenContentTools ? (r.bit() ? ADAPTIVE : r.bit()) : ADAPTIVE;
|
|
131
|
+
if (orderHint)
|
|
132
|
+
orderHintBits = r.bits(3) + 1;
|
|
133
|
+
}
|
|
134
|
+
const superres = !!r.bit(), cdef = !!r.bit(), restoration = !!r.bit();
|
|
135
|
+
let bitDepth = 8;
|
|
136
|
+
if (r.bit())
|
|
137
|
+
bitDepth = profile === 2 && r.bit() ? 12 : 10;
|
|
138
|
+
const monochrome = profile !== 1 && !!r.bit();
|
|
139
|
+
let colorPrimaries = 2, transferCharacteristics = 2, matrixCoefficients = 2;
|
|
140
|
+
if (r.bit()) {
|
|
141
|
+
colorPrimaries = r.bits(8);
|
|
142
|
+
transferCharacteristics = r.bits(8);
|
|
143
|
+
matrixCoefficients = r.bits(8);
|
|
144
|
+
}
|
|
145
|
+
let fullRange, ssx = 1, ssy = 1;
|
|
146
|
+
if (monochrome)
|
|
147
|
+
fullRange = !!r.bit();
|
|
148
|
+
else if (colorPrimaries === 1 && transferCharacteristics === 13 && matrixCoefficients === 0) {
|
|
149
|
+
fullRange = true;
|
|
150
|
+
ssx = ssy = 0;
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
fullRange = !!r.bit();
|
|
154
|
+
if (profile === 1)
|
|
155
|
+
ssx = ssy = 0;
|
|
156
|
+
else if (profile === 2) {
|
|
157
|
+
if (bitDepth === 12) {
|
|
158
|
+
ssx = r.bit();
|
|
159
|
+
ssy = ssx ? r.bit() : 0;
|
|
160
|
+
}
|
|
161
|
+
else
|
|
162
|
+
ssy = 0;
|
|
163
|
+
}
|
|
164
|
+
if (ssx && ssy)
|
|
165
|
+
r.bits(2);
|
|
166
|
+
}
|
|
167
|
+
const separateUvDeltaQ = !monochrome && !!r.bit();
|
|
168
|
+
const filmGrain = !!r.bit();
|
|
169
|
+
return {
|
|
170
|
+
profile, reducedStillPicture, maxWidth, maxHeight, widthBits, heightBits, frameIdBits, deltaFrameIdBits,
|
|
171
|
+
decoderModelInfo, equalPictureInterval, bufferRemovalDelayLength, framePresentationDelayLength, operatingPoints,
|
|
172
|
+
sb128, filterIntra, intraEdgeFilter, screenContentTools, forceIntegerMv, orderHintBits, superres, cdef,
|
|
173
|
+
restoration, bitDepth, monochrome, colorPrimaries, transferCharacteristics, matrixCoefficients, fullRange,
|
|
174
|
+
ssx, ssy, separateUvDeltaQ, filmGrain
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
export const FRAME_KEY = 0, FRAME_INTRA_ONLY = 2;
|
|
178
|
+
export class InterFrameError extends Error {
|
|
179
|
+
}
|
|
180
|
+
export const RESTORATION_NONE = 0, RESTORATION_SWITCHABLE = 1, RESTORATION_WIENER = 2, RESTORATION_SGRPROJ = 3;
|
|
181
|
+
const tileLog2 = (size, target) => {
|
|
182
|
+
let k = 0;
|
|
183
|
+
while (size << k < target)
|
|
184
|
+
k++;
|
|
185
|
+
return k;
|
|
186
|
+
};
|
|
187
|
+
export function parseFrameHeader(r, seq, temporalId, spatialId) {
|
|
188
|
+
const reduced = seq.reducedStillPicture;
|
|
189
|
+
const showExistingFrame = !reduced && !!r.bit();
|
|
190
|
+
const header = { showExistingFrame };
|
|
191
|
+
if (showExistingFrame) {
|
|
192
|
+
header.existingFrameIdx = r.bits(3);
|
|
193
|
+
if (seq.decoderModelInfo && !seq.equalPictureInterval)
|
|
194
|
+
r.bits(seq.framePresentationDelayLength);
|
|
195
|
+
if (seq.frameIdBits)
|
|
196
|
+
r.bits(seq.frameIdBits);
|
|
197
|
+
return header;
|
|
198
|
+
}
|
|
199
|
+
const frameType = reduced ? FRAME_KEY : r.bits(2);
|
|
200
|
+
if (frameType !== FRAME_KEY && frameType !== FRAME_INTRA_ONLY)
|
|
201
|
+
throw new InterFrameError('AV1: inter frames are not supported');
|
|
202
|
+
const showFrame = reduced || !!r.bit();
|
|
203
|
+
let showable = false;
|
|
204
|
+
if (showFrame) {
|
|
205
|
+
if (seq.decoderModelInfo && !seq.equalPictureInterval)
|
|
206
|
+
r.bits(seq.framePresentationDelayLength);
|
|
207
|
+
}
|
|
208
|
+
else
|
|
209
|
+
showable = !!r.bit();
|
|
210
|
+
const errorResilient = frameType === FRAME_KEY && showFrame || reduced || !!r.bit();
|
|
211
|
+
const disableCdfUpdate = !!r.bit();
|
|
212
|
+
const allowScreenContentTools = !!(seq.screenContentTools === ADAPTIVE ? r.bit() : seq.screenContentTools);
|
|
213
|
+
if (allowScreenContentTools && seq.forceIntegerMv === ADAPTIVE)
|
|
214
|
+
r.bit();
|
|
215
|
+
if (seq.frameIdBits)
|
|
216
|
+
r.bits(seq.frameIdBits);
|
|
217
|
+
const frameSizeOverride = !reduced && !!r.bit();
|
|
218
|
+
if (seq.orderHintBits)
|
|
219
|
+
r.bits(seq.orderHintBits);
|
|
220
|
+
if (seq.decoderModelInfo && r.bit()) {
|
|
221
|
+
for (const op of seq.operatingPoints) {
|
|
222
|
+
if (!op.decoderModel)
|
|
223
|
+
continue;
|
|
224
|
+
const inTemporal = op.idc >> temporalId & 1, inSpatial = op.idc >> spatialId + 8 & 1;
|
|
225
|
+
if (!op.idc || inTemporal && inSpatial)
|
|
226
|
+
r.bits(seq.bufferRemovalDelayLength);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const refreshFrameFlags = frameType === FRAME_KEY && showFrame ? 0xff : r.bits(8);
|
|
230
|
+
if (refreshFrameFlags !== 0xff && errorResilient && seq.orderHintBits)
|
|
231
|
+
for (let i = 0; i < 8; i++)
|
|
232
|
+
r.bits(seq.orderHintBits);
|
|
233
|
+
let upscaledWidth = seq.maxWidth, height = seq.maxHeight;
|
|
234
|
+
if (frameSizeOverride) {
|
|
235
|
+
upscaledWidth = r.bits(seq.widthBits) + 1;
|
|
236
|
+
height = r.bits(seq.heightBits) + 1;
|
|
237
|
+
}
|
|
238
|
+
let superresDenominator = 8, width = upscaledWidth;
|
|
239
|
+
if (seq.superres && r.bit()) {
|
|
240
|
+
superresDenominator = 9 + r.bits(3);
|
|
241
|
+
width = Math.max(Math.floor((upscaledWidth * 8 + (superresDenominator >> 1)) / superresDenominator), Math.min(16, upscaledWidth));
|
|
242
|
+
}
|
|
243
|
+
if (r.bit()) {
|
|
244
|
+
r.bits(16);
|
|
245
|
+
r.bits(16);
|
|
246
|
+
}
|
|
247
|
+
const allowIntrabc = allowScreenContentTools && superresDenominator === 8 && !!r.bit();
|
|
248
|
+
if (!reduced && !disableCdfUpdate)
|
|
249
|
+
r.bit();
|
|
250
|
+
const uniform = r.bit();
|
|
251
|
+
const sbLog2 = seq.sb128 ? 7 : 6;
|
|
252
|
+
const sbw = width + (1 << sbLog2) - 1 >> sbLog2, sbh = height + (1 << sbLog2) - 1 >> sbLog2;
|
|
253
|
+
const maxTileWidthSb = 4096 >> sbLog2;
|
|
254
|
+
let maxTileAreaSb = 4096 * 2304 >> 2 * sbLog2;
|
|
255
|
+
const minLog2Cols = tileLog2(maxTileWidthSb, sbw);
|
|
256
|
+
const maxLog2Cols = tileLog2(1, Math.min(sbw, 64)), maxLog2Rows = tileLog2(1, Math.min(sbh, 64));
|
|
257
|
+
const minLog2Tiles = Math.max(tileLog2(maxTileAreaSb, sbw * sbh), minLog2Cols);
|
|
258
|
+
const colStarts = [], rowStarts = [];
|
|
259
|
+
let log2Cols, log2Rows;
|
|
260
|
+
if (uniform) {
|
|
261
|
+
for (log2Cols = minLog2Cols; log2Cols < maxLog2Cols && r.bit(); log2Cols++)
|
|
262
|
+
;
|
|
263
|
+
const tileW = 1 + (sbw - 1 >> log2Cols);
|
|
264
|
+
for (let x = 0; x < sbw; x += tileW)
|
|
265
|
+
colStarts.push(x);
|
|
266
|
+
const minLog2Rows = Math.max(minLog2Tiles - log2Cols, 0);
|
|
267
|
+
for (log2Rows = minLog2Rows; log2Rows < maxLog2Rows && r.bit(); log2Rows++)
|
|
268
|
+
;
|
|
269
|
+
const tileH = 1 + (sbh - 1 >> log2Rows);
|
|
270
|
+
for (let y = 0; y < sbh; y += tileH)
|
|
271
|
+
rowStarts.push(y);
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
let widest = 0;
|
|
275
|
+
for (let x = 0; x < sbw && colStarts.length < 64;) {
|
|
276
|
+
const size = Math.min(sbw - x, maxTileWidthSb);
|
|
277
|
+
const w = size > 1 ? 1 + r.uniform(size) : 1;
|
|
278
|
+
colStarts.push(x);
|
|
279
|
+
x += w;
|
|
280
|
+
widest = Math.max(widest, w);
|
|
281
|
+
}
|
|
282
|
+
log2Cols = tileLog2(1, colStarts.length);
|
|
283
|
+
maxTileAreaSb = sbw * sbh;
|
|
284
|
+
if (minLog2Tiles)
|
|
285
|
+
maxTileAreaSb >>= minLog2Tiles + 1;
|
|
286
|
+
const maxTileHeightSb = Math.max(Math.floor(maxTileAreaSb / widest), 1);
|
|
287
|
+
for (let y = 0; y < sbh && rowStarts.length < 64;) {
|
|
288
|
+
const size = Math.min(sbh - y, maxTileHeightSb);
|
|
289
|
+
const h = size > 1 ? 1 + r.uniform(size) : 1;
|
|
290
|
+
rowStarts.push(y);
|
|
291
|
+
y += h;
|
|
292
|
+
}
|
|
293
|
+
log2Rows = tileLog2(1, rowStarts.length);
|
|
294
|
+
}
|
|
295
|
+
const cols = colStarts.length, rows = rowStarts.length;
|
|
296
|
+
colStarts.push(sbw);
|
|
297
|
+
rowStarts.push(sbh);
|
|
298
|
+
let contextUpdateId = 0, sizeBytes = 0;
|
|
299
|
+
if (log2Cols || log2Rows) {
|
|
300
|
+
contextUpdateId = r.bits(log2Cols + log2Rows);
|
|
301
|
+
if (contextUpdateId >= cols * rows)
|
|
302
|
+
throw new Error('AV1: invalid tile info');
|
|
303
|
+
sizeBytes = r.bits(2) + 1;
|
|
304
|
+
}
|
|
305
|
+
const delta = () => r.bit() ? r.sbits(6) : 0;
|
|
306
|
+
const yac = r.bits(8), ydcDelta = delta();
|
|
307
|
+
let udcDelta = 0, uacDelta = 0, vdcDelta = 0, vacDelta = 0;
|
|
308
|
+
if (!seq.monochrome) {
|
|
309
|
+
const diffUv = seq.separateUvDeltaQ && !!r.bit();
|
|
310
|
+
udcDelta = delta();
|
|
311
|
+
uacDelta = delta();
|
|
312
|
+
if (diffUv) {
|
|
313
|
+
vdcDelta = delta();
|
|
314
|
+
vacDelta = delta();
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
vdcDelta = udcDelta;
|
|
318
|
+
vacDelta = uacDelta;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
const qm = !!r.bit();
|
|
322
|
+
let qmY = 15, qmU = 15, qmV = 15;
|
|
323
|
+
if (qm) {
|
|
324
|
+
qmY = r.bits(4);
|
|
325
|
+
qmU = r.bits(4);
|
|
326
|
+
qmV = seq.separateUvDeltaQ ? r.bits(4) : qmU;
|
|
327
|
+
}
|
|
328
|
+
const segmentData = [];
|
|
329
|
+
const enabled = !!r.bit();
|
|
330
|
+
let preskip = false, lastActiveSegId = -1;
|
|
331
|
+
for (let i = 0; i < 8; i++) {
|
|
332
|
+
const seg = { deltaQ: 0, deltaLf: [0, 0, 0, 0], ref: -1, skip: false, globalMv: false };
|
|
333
|
+
if (enabled) {
|
|
334
|
+
if (r.bit()) {
|
|
335
|
+
seg.deltaQ = r.sbits(8);
|
|
336
|
+
lastActiveSegId = i;
|
|
337
|
+
}
|
|
338
|
+
for (let k = 0; k < 4; k++)
|
|
339
|
+
if (r.bit()) {
|
|
340
|
+
seg.deltaLf[k] = r.sbits(6);
|
|
341
|
+
lastActiveSegId = i;
|
|
342
|
+
}
|
|
343
|
+
if (r.bit()) {
|
|
344
|
+
seg.ref = r.bits(3);
|
|
345
|
+
lastActiveSegId = i;
|
|
346
|
+
preskip = true;
|
|
347
|
+
}
|
|
348
|
+
if ((seg.skip = !!r.bit())) {
|
|
349
|
+
lastActiveSegId = i;
|
|
350
|
+
preskip = true;
|
|
351
|
+
}
|
|
352
|
+
if ((seg.globalMv = !!r.bit())) {
|
|
353
|
+
lastActiveSegId = i;
|
|
354
|
+
preskip = true;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
segmentData.push(seg);
|
|
358
|
+
}
|
|
359
|
+
const deltaQPresent = yac ? !!r.bit() : false;
|
|
360
|
+
const deltaQResLog2 = deltaQPresent ? r.bits(2) : 0;
|
|
361
|
+
const deltaLfPresent = deltaQPresent && !allowIntrabc && !!r.bit();
|
|
362
|
+
const deltaLfResLog2 = deltaLfPresent ? r.bits(2) : 0;
|
|
363
|
+
const deltaLfMulti = deltaLfPresent && !!r.bit();
|
|
364
|
+
const deltaLossless = !ydcDelta && !udcDelta && !uacDelta && !vdcDelta && !vacDelta;
|
|
365
|
+
const qidx = [], lossless = [];
|
|
366
|
+
let allLossless = true;
|
|
367
|
+
for (let i = 0; i < 8; i++) {
|
|
368
|
+
qidx.push(enabled ? Math.min(255, Math.max(0, yac + segmentData[i].deltaQ)) : yac);
|
|
369
|
+
lossless.push(!qidx[i] && deltaLossless);
|
|
370
|
+
allLossless &&= lossless[i];
|
|
371
|
+
}
|
|
372
|
+
const loopFilter = { levelY: [0, 0], levelU: 0, levelV: 0, sharpness: 0, modeRefDeltaEnabled: true, refDeltas: [1, 0, 0, 0, -1, 0, -1, -1], modeDeltas: [0, 0] };
|
|
373
|
+
if (!allLossless && !allowIntrabc) {
|
|
374
|
+
loopFilter.levelY = [r.bits(6), r.bits(6)];
|
|
375
|
+
if (!seq.monochrome && (loopFilter.levelY[0] || loopFilter.levelY[1])) {
|
|
376
|
+
loopFilter.levelU = r.bits(6);
|
|
377
|
+
loopFilter.levelV = r.bits(6);
|
|
378
|
+
}
|
|
379
|
+
loopFilter.sharpness = r.bits(3);
|
|
380
|
+
loopFilter.modeRefDeltaEnabled = !!r.bit();
|
|
381
|
+
if (loopFilter.modeRefDeltaEnabled && r.bit()) {
|
|
382
|
+
for (let i = 0; i < 8; i++)
|
|
383
|
+
if (r.bit())
|
|
384
|
+
loopFilter.refDeltas[i] = r.sbits(6);
|
|
385
|
+
for (let i = 0; i < 2; i++)
|
|
386
|
+
if (r.bit())
|
|
387
|
+
loopFilter.modeDeltas[i] = r.sbits(6);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
const cdef = { damping: 3, bits: 0, yStrengths: [0], uvStrengths: [0] };
|
|
391
|
+
if (!allLossless && seq.cdef && !allowIntrabc) {
|
|
392
|
+
cdef.damping = r.bits(2) + 3;
|
|
393
|
+
cdef.bits = r.bits(2);
|
|
394
|
+
cdef.yStrengths = [];
|
|
395
|
+
cdef.uvStrengths = [];
|
|
396
|
+
for (let i = 0; i < 1 << cdef.bits; i++) {
|
|
397
|
+
cdef.yStrengths.push(r.bits(6));
|
|
398
|
+
cdef.uvStrengths.push(seq.monochrome ? 0 : r.bits(6));
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
const restoration = { types: [RESTORATION_NONE, RESTORATION_NONE, RESTORATION_NONE], unitSizeLog2: [8, 8] };
|
|
402
|
+
if ((!allLossless || superresDenominator !== 8) && seq.restoration && !allowIntrabc) {
|
|
403
|
+
restoration.types[0] = r.bits(2);
|
|
404
|
+
if (!seq.monochrome) {
|
|
405
|
+
restoration.types[1] = r.bits(2);
|
|
406
|
+
restoration.types[2] = r.bits(2);
|
|
407
|
+
}
|
|
408
|
+
if (restoration.types.some(t => t)) {
|
|
409
|
+
let size = 6 + (seq.sb128 ? 1 : 0);
|
|
410
|
+
if (r.bit()) {
|
|
411
|
+
size++;
|
|
412
|
+
if (!seq.sb128)
|
|
413
|
+
size += r.bit();
|
|
414
|
+
}
|
|
415
|
+
restoration.unitSizeLog2 = [size, size];
|
|
416
|
+
if ((restoration.types[1] || restoration.types[2]) && seq.ssx && seq.ssy)
|
|
417
|
+
restoration.unitSizeLog2[1] -= r.bit();
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
const txMode = allLossless ? 0 : r.bit() ? 2 : 1;
|
|
421
|
+
const reducedTxSet = !!r.bit();
|
|
422
|
+
let filmGrain = null;
|
|
423
|
+
if (seq.filmGrain && (showFrame || showable) && r.bit()) {
|
|
424
|
+
const seed = r.bits(16);
|
|
425
|
+
const yPoints = [];
|
|
426
|
+
const numY = r.bits(4);
|
|
427
|
+
if (numY > 14)
|
|
428
|
+
throw new Error('AV1: invalid film grain');
|
|
429
|
+
for (let i = 0; i < numY; i++) {
|
|
430
|
+
yPoints.push([r.bits(8), r.bits(8)]);
|
|
431
|
+
if (i && yPoints[i - 1][0] >= yPoints[i][0])
|
|
432
|
+
throw new Error('AV1: invalid film grain');
|
|
433
|
+
}
|
|
434
|
+
const chromaScalingFromLuma = !seq.monochrome && !!r.bit();
|
|
435
|
+
const uvPoints = [[], []];
|
|
436
|
+
if (!seq.monochrome && !chromaScalingFromLuma && !(seq.ssx && seq.ssy && !numY)) {
|
|
437
|
+
for (let pl = 0; pl < 2; pl++) {
|
|
438
|
+
const n = r.bits(4);
|
|
439
|
+
if (n > 10)
|
|
440
|
+
throw new Error('AV1: invalid film grain');
|
|
441
|
+
for (let i = 0; i < n; i++) {
|
|
442
|
+
uvPoints[pl].push([r.bits(8), r.bits(8)]);
|
|
443
|
+
if (i && uvPoints[pl][i - 1][0] >= uvPoints[pl][i][0])
|
|
444
|
+
throw new Error('AV1: invalid film grain');
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
if (seq.ssx && seq.ssy && !uvPoints[0].length !== !uvPoints[1].length)
|
|
449
|
+
throw new Error('AV1: invalid film grain');
|
|
450
|
+
const scalingShift = r.bits(2) + 8;
|
|
451
|
+
const arCoeffLag = r.bits(2);
|
|
452
|
+
const numPos = 2 * arCoeffLag * (arCoeffLag + 1);
|
|
453
|
+
const arCoeffsY = [];
|
|
454
|
+
for (let i = 0; i < numPos; i++)
|
|
455
|
+
arCoeffsY.push(numY ? r.bits(8) - 128 : 0);
|
|
456
|
+
const arCoeffsUv = [[], []];
|
|
457
|
+
for (let pl = 0; pl < 2; pl++) {
|
|
458
|
+
if (uvPoints[pl].length || chromaScalingFromLuma) {
|
|
459
|
+
const n = numPos + (numY ? 1 : 0);
|
|
460
|
+
for (let i = 0; i < n; i++)
|
|
461
|
+
arCoeffsUv[pl].push(r.bits(8) - 128);
|
|
462
|
+
if (!numY)
|
|
463
|
+
arCoeffsUv[pl].push(0);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
const arCoeffShift = r.bits(2) + 6;
|
|
467
|
+
const grainScaleShift = r.bits(2);
|
|
468
|
+
const uvMult = [0, 0], uvLumaMult = [0, 0], uvOffset = [0, 0];
|
|
469
|
+
for (let pl = 0; pl < 2; pl++) {
|
|
470
|
+
if (uvPoints[pl].length) {
|
|
471
|
+
uvMult[pl] = r.bits(8) - 128;
|
|
472
|
+
uvLumaMult[pl] = r.bits(8) - 128;
|
|
473
|
+
uvOffset[pl] = r.bits(9) - 256;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
const overlap = !!r.bit(), clipToRestrictedRange = !!r.bit();
|
|
477
|
+
filmGrain = {
|
|
478
|
+
seed, yPoints, chromaScalingFromLuma, uvPoints, scalingShift, arCoeffLag, arCoeffsY, arCoeffsUv, arCoeffShift,
|
|
479
|
+
grainScaleShift, uvMult, uvLumaMult, uvOffset, overlap, clipToRestrictedRange
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
return Object.assign(header, {
|
|
483
|
+
existingFrameIdx: 0, frameType, showFrame, refreshFrameFlags, disableCdfUpdate, allowScreenContentTools, allowIntrabc,
|
|
484
|
+
width, upscaledWidth, height, superresDenominator,
|
|
485
|
+
tiles: { cols, rows, log2Cols, log2Rows, colStarts, rowStarts, contextUpdateId, sizeBytes },
|
|
486
|
+
quant: { yac, ydcDelta, udcDelta, uacDelta, vdcDelta, vacDelta, qm, qmY, qmU, qmV },
|
|
487
|
+
segmentation: { enabled, updateMap: enabled, data: segmentData, preskip, lastActiveSegId, qidx, lossless },
|
|
488
|
+
allLossless,
|
|
489
|
+
deltaQ: { present: deltaQPresent, resLog2: deltaQResLog2 },
|
|
490
|
+
deltaLf: { present: deltaLfPresent, resLog2: deltaLfResLog2, multi: deltaLfMulti },
|
|
491
|
+
loopFilter, cdef, restoration, txMode, reducedTxSet, filmGrain
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
export const OBU_SEQUENCE_HEADER = 1, OBU_TEMPORAL_DELIMITER = 2, OBU_FRAME_HEADER = 3, OBU_TILE_GROUP = 4, OBU_METADATA = 5, OBU_FRAME = 6, OBU_REDUNDANT_FRAME_HEADER = 7, OBU_PADDING = 15;
|
|
495
|
+
export function* obus(data, start = 0, end = data.length) {
|
|
496
|
+
let o = start;
|
|
497
|
+
while (o < end) {
|
|
498
|
+
const r = new BitReader(data, o, end);
|
|
499
|
+
r.bit();
|
|
500
|
+
const type = r.bits(4);
|
|
501
|
+
const extension = r.bit(), hasSize = r.bit();
|
|
502
|
+
r.bit();
|
|
503
|
+
let temporalId = 0, spatialId = 0;
|
|
504
|
+
if (extension) {
|
|
505
|
+
temporalId = r.bits(3);
|
|
506
|
+
spatialId = r.bits(2);
|
|
507
|
+
r.bits(3);
|
|
508
|
+
}
|
|
509
|
+
const size = hasSize ? r.leb128() : end - r.byte;
|
|
510
|
+
const payload = r.byte;
|
|
511
|
+
if (payload + size > end)
|
|
512
|
+
throw new Error('AV1: truncated OBU');
|
|
513
|
+
yield { type, temporalId, spatialId, start: payload, end: payload + size };
|
|
514
|
+
o = payload + size;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* The post filters of AV1 frames: deblocking, CDEF, superres upscaling and loop restoration, in the order
|
|
3
|
+
* of the AV1 specification. Copyright (c) 2018-2021, VideoLAN and dav1d authors, BSD-2-Clause License (see
|
|
4
|
+
* THIRD_PARTY_NOTICES.md)
|
|
5
|
+
*/
|
|
6
|
+
import { deblock } from "./loopfilter.js";
|
|
7
|
+
import { cdef, cdefActive } from "./cdef.js";
|
|
8
|
+
import { superres, loopRestoration } from "./restoration.js";
|
|
9
|
+
import { RESTORATION_NONE } from "./obu.js";
|
|
10
|
+
export function postFilter(f) {
|
|
11
|
+
deblock(f);
|
|
12
|
+
const usesLr = f.hdr.restoration.types.some(t => t !== RESTORATION_NONE);
|
|
13
|
+
const doCdef = cdefActive(f);
|
|
14
|
+
let pre = doCdef || usesLr ? f.planes.map(p => p.slice()) : f.planes;
|
|
15
|
+
if (doCdef)
|
|
16
|
+
cdef(f, pre);
|
|
17
|
+
if (f.hdr.upscaledWidth !== f.width) {
|
|
18
|
+
const up = superres(f, f.planes);
|
|
19
|
+
pre = usesLr ? superres(f, pre).planes : up.planes;
|
|
20
|
+
f.planes = up.planes;
|
|
21
|
+
f.strides = up.strides;
|
|
22
|
+
}
|
|
23
|
+
if (usesLr) {
|
|
24
|
+
const out = f.planes.map(p => p.slice());
|
|
25
|
+
loopRestoration(f, pre, f.planes, out, f.strides);
|
|
26
|
+
f.planes = out;
|
|
27
|
+
}
|
|
28
|
+
}
|