imagescript 3.3.0 → 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 +28 -8
- package/THIRD_PARTY_NOTICES.md +167 -2
- package/dist/animation.d.ts +18 -8
- package/dist/animation.js +23 -2
- 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/hdr.d.ts +25 -0
- package/dist/codecs/hdr.js +201 -0
- package/dist/codecs/ico.js +48 -0
- package/dist/codecs/jpeg.js +2 -1
- 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/qoi.js +150 -0
- 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/webp.js +36 -2
- package/dist/image-type.d.ts +15 -1
- package/dist/image-type.js +45 -2
- package/dist/image.d.ts +47 -6
- package/dist/image.js +49 -3
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -2
- package/dist/render/hinting.js +26 -18
- package/dist/render/layout.js +1 -1
- package/dist/render/svg.js +1 -1
- package/dist/render/unicode.js +1 -9
- package/dist/util/bytes.js +9 -0
- package/dist/util/resample.js +4 -2
- package/dist/version.js +1 -1
- package/package.json +25 -2
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* AV1 film grain synthesis, ported from dav1d (src/filmgrain_tmpl.c, src/fg_apply_tmpl.c). Copyright (c) 2018-2021,
|
|
3
|
+
* VideoLAN and dav1d authors, Copyright (c) 2018, Two Orioles, LLC, BSD-2-Clause License (see THIRD_PARTY_NOTICES.md)
|
|
4
|
+
*/
|
|
5
|
+
import { gaussianSequence } from "./tables.js";
|
|
6
|
+
const GRAIN_WIDTH = 82, GRAIN_HEIGHT = 73, SUB_GRAIN_WIDTH = 44, SUB_GRAIN_HEIGHT = 38, BLOCK = 32;
|
|
7
|
+
class Random {
|
|
8
|
+
state;
|
|
9
|
+
constructor(state) {
|
|
10
|
+
this.state = state;
|
|
11
|
+
}
|
|
12
|
+
next(bits) {
|
|
13
|
+
const r = this.state;
|
|
14
|
+
const bit = (r ^ r >> 1 ^ r >> 3 ^ r >> 12) & 1;
|
|
15
|
+
this.state = r >> 1 | bit << 15;
|
|
16
|
+
return this.state >> (16 - bits) & (1 << bits) - 1;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const round2 = (x, shift) => (x + ((1 << shift) >> 1)) >> shift;
|
|
20
|
+
function generateGrainY(g, bitdepth) {
|
|
21
|
+
const gauss = gaussianSequence();
|
|
22
|
+
const buf = new Int16Array(GRAIN_HEIGHT * GRAIN_WIDTH);
|
|
23
|
+
const rnd = new Random(g.seed);
|
|
24
|
+
const shift = 4 - (bitdepth - 8) + g.grainScaleShift;
|
|
25
|
+
const ctr = 128 << (bitdepth - 8), min = -ctr, max = ctr - 1;
|
|
26
|
+
for (let i = 0; i < buf.length; i++)
|
|
27
|
+
buf[i] = round2(gauss[rnd.next(11)], shift);
|
|
28
|
+
const lag = g.arCoeffLag;
|
|
29
|
+
for (let y = 3; y < GRAIN_HEIGHT; y++) {
|
|
30
|
+
for (let x = 3; x < GRAIN_WIDTH - 3; x++) {
|
|
31
|
+
let sum = 0, c = 0;
|
|
32
|
+
outer: for (let dy = -lag; dy <= 0; dy++) {
|
|
33
|
+
for (let dx = -lag; dx <= lag; dx++) {
|
|
34
|
+
if (!dx && !dy)
|
|
35
|
+
break outer;
|
|
36
|
+
sum += g.arCoeffsY[c++] * buf[(y + dy) * GRAIN_WIDTH + x + dx];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const v = buf[y * GRAIN_WIDTH + x] + round2(sum, g.arCoeffShift);
|
|
40
|
+
buf[y * GRAIN_WIDTH + x] = v < min ? min : v > max ? max : v;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return buf;
|
|
44
|
+
}
|
|
45
|
+
function generateGrainUv(g, lumaBuf, uv, subx, suby, bitdepth) {
|
|
46
|
+
const gauss = gaussianSequence();
|
|
47
|
+
const buf = new Int16Array(GRAIN_HEIGHT * GRAIN_WIDTH);
|
|
48
|
+
const rnd = new Random(g.seed ^ (uv ? 0x49d8 : 0xb524));
|
|
49
|
+
const shift = 4 - (bitdepth - 8) + g.grainScaleShift;
|
|
50
|
+
const ctr = 128 << (bitdepth - 8), min = -ctr, max = ctr - 1;
|
|
51
|
+
const w = subx ? SUB_GRAIN_WIDTH : GRAIN_WIDTH, h = suby ? SUB_GRAIN_HEIGHT : GRAIN_HEIGHT;
|
|
52
|
+
for (let y = 0; y < h; y++)
|
|
53
|
+
for (let x = 0; x < w; x++)
|
|
54
|
+
buf[y * GRAIN_WIDTH + x] = round2(gauss[rnd.next(11)], shift);
|
|
55
|
+
const lag = g.arCoeffLag, coeffs = g.arCoeffsUv[uv];
|
|
56
|
+
for (let y = 3; y < h; y++) {
|
|
57
|
+
for (let x = 3; x < w - 3; x++) {
|
|
58
|
+
let sum = 0, c = 0;
|
|
59
|
+
outer: for (let dy = -lag; dy <= 0; dy++) {
|
|
60
|
+
for (let dx = -lag; dx <= lag; dx++) {
|
|
61
|
+
if (!dx && !dy) {
|
|
62
|
+
if (!g.yPoints.length)
|
|
63
|
+
break outer;
|
|
64
|
+
let luma = 0;
|
|
65
|
+
const lx = ((x - 3) << subx) + 3, ly = ((y - 3) << suby) + 3;
|
|
66
|
+
for (let i = 0; i <= suby; i++)
|
|
67
|
+
for (let j = 0; j <= subx; j++)
|
|
68
|
+
luma += lumaBuf[(ly + i) * GRAIN_WIDTH + lx + j];
|
|
69
|
+
sum += round2(luma, subx + suby) * coeffs[c];
|
|
70
|
+
break outer;
|
|
71
|
+
}
|
|
72
|
+
sum += coeffs[c++] * buf[(y + dy) * GRAIN_WIDTH + x + dx];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const v = buf[y * GRAIN_WIDTH + x] + round2(sum, g.arCoeffShift);
|
|
76
|
+
buf[y * GRAIN_WIDTH + x] = v < min ? min : v > max ? max : v;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return buf;
|
|
80
|
+
}
|
|
81
|
+
function generateScaling(bitdepth, points) {
|
|
82
|
+
const shiftX = bitdepth - 8, size = 1 << bitdepth;
|
|
83
|
+
const scaling = new Uint8Array(size);
|
|
84
|
+
const num = points.length;
|
|
85
|
+
if (!num)
|
|
86
|
+
return scaling;
|
|
87
|
+
scaling.fill(points[0][1], 0, points[0][0] << shiftX);
|
|
88
|
+
for (let i = 0; i < num - 1; i++) {
|
|
89
|
+
const [bx, by] = points[i], [ex, ey] = points[i + 1];
|
|
90
|
+
const dx = ex - bx, dy = ey - by;
|
|
91
|
+
const delta = dy * Math.floor((0x10000 + (dx >> 1)) / dx);
|
|
92
|
+
for (let x = 0, d = 0x8000; x < dx; x++) {
|
|
93
|
+
scaling[(bx + x) << shiftX] = by + (d >> 16);
|
|
94
|
+
d += delta;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const n = points[num - 1][0] << shiftX;
|
|
98
|
+
scaling.fill(points[num - 1][1], n, size);
|
|
99
|
+
if (bitdepth > 8) {
|
|
100
|
+
const pad = 1 << shiftX, rnd = pad >> 1;
|
|
101
|
+
for (let i = 0; i < num - 1; i++) {
|
|
102
|
+
const bx = points[i][0] << shiftX, ex = points[i + 1][0] << shiftX;
|
|
103
|
+
for (let x = 0; x < ex - bx; x += pad) {
|
|
104
|
+
const range = scaling[bx + x + pad] - scaling[bx + x];
|
|
105
|
+
for (let k = 1, r = rnd; k < pad; k++) {
|
|
106
|
+
r += range;
|
|
107
|
+
scaling[bx + x + k] = scaling[bx + x] + (r >> shiftX);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return scaling;
|
|
113
|
+
}
|
|
114
|
+
const W = [[[27, 17], [17, 27]], [[23, 22], [0, 0]]];
|
|
115
|
+
function applyStripe(g, dst, src, stride, pw, bh, rowNum, scaling, lut, bitdepth, plane, sx, sy, isId, luma, lumaStride) {
|
|
116
|
+
const rows = 1 + (g.overlap && rowNum > 0 ? 1 : 0);
|
|
117
|
+
const shift8 = bitdepth - 8, ctr = 128 << shift8, gmin = -ctr, gmax = ctr - 1, bdMax = (1 << bitdepth) - 1;
|
|
118
|
+
const minV = g.clipToRestrictedRange ? 16 << shift8 : 0;
|
|
119
|
+
const maxV = g.clipToRestrictedRange ? (plane && !isId ? 240 : 235) << shift8 : bdMax;
|
|
120
|
+
const clip = (v, lo, hi) => v < lo ? lo : v > hi ? hi : v;
|
|
121
|
+
const seeds = [];
|
|
122
|
+
for (let i = 0; i < rows; i++) {
|
|
123
|
+
let s = g.seed;
|
|
124
|
+
s ^= (((rowNum - i) * 37 + 178) & 0xff) << 8;
|
|
125
|
+
s ^= ((rowNum - i) * 173 + 105) & 0xff;
|
|
126
|
+
seeds.push(new Random(s));
|
|
127
|
+
}
|
|
128
|
+
const offsets = [[0, 0], [0, 0]];
|
|
129
|
+
const sample = (bx, by, x, y) => {
|
|
130
|
+
const randval = offsets[bx][by];
|
|
131
|
+
const offx = 3 + (2 >> sx) * (3 + (randval >> 4)), offy = 3 + (2 >> sy) * (3 + (randval & 0xf));
|
|
132
|
+
return lut[(offy + y + (BLOCK >> sy) * by) * GRAIN_WIDTH + offx + x + (BLOCK >> sx) * bx];
|
|
133
|
+
};
|
|
134
|
+
const y0 = rowNum * BLOCK >> sy;
|
|
135
|
+
const uv = plane - 1;
|
|
136
|
+
const add = (bx, x, y, grain) => {
|
|
137
|
+
const o = (y0 + y) * stride + bx + x;
|
|
138
|
+
let val;
|
|
139
|
+
if (!plane)
|
|
140
|
+
val = src[o];
|
|
141
|
+
else {
|
|
142
|
+
const lx = (bx + x) << sx, ly = (y0 + y) << sy;
|
|
143
|
+
let avg = luma[ly * lumaStride + lx];
|
|
144
|
+
if (sx)
|
|
145
|
+
avg = (avg + luma[ly * lumaStride + lx + 1] + 1) >> 1;
|
|
146
|
+
val = avg;
|
|
147
|
+
if (!g.chromaScalingFromLuma) {
|
|
148
|
+
const combined = avg * g.uvLumaMult[uv] + src[o] * g.uvMult[uv];
|
|
149
|
+
val = clip((combined >> 6) + g.uvOffset[uv] * (1 << shift8), 0, bdMax);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const noise = round2(scaling[val] * grain, g.scalingShift);
|
|
153
|
+
dst[o] = clip(src[o] + noise, minV, maxV);
|
|
154
|
+
};
|
|
155
|
+
const blockW = BLOCK >> sx;
|
|
156
|
+
for (let bx = 0; bx < pw; bx += blockW) {
|
|
157
|
+
const bw = Math.min(blockW, pw - bx);
|
|
158
|
+
if (g.overlap && bx)
|
|
159
|
+
for (let i = 0; i < rows; i++)
|
|
160
|
+
offsets[1][i] = offsets[0][i];
|
|
161
|
+
for (let i = 0; i < rows; i++)
|
|
162
|
+
offsets[0][i] = seeds[i].next(8);
|
|
163
|
+
const ystart = g.overlap && rowNum ? Math.min(2 >> sy, bh) : 0;
|
|
164
|
+
const xstart = g.overlap && bx ? Math.min(2 >> sx, bw) : 0;
|
|
165
|
+
const wx = W[sx], wy = W[sy];
|
|
166
|
+
for (let y = ystart; y < bh; y++) {
|
|
167
|
+
for (let x = xstart; x < bw; x++)
|
|
168
|
+
add(bx, x, y, sample(0, 0, x, y));
|
|
169
|
+
for (let x = 0; x < xstart; x++) {
|
|
170
|
+
const grain = clip(round2(sample(1, 0, x, y) * wx[x][0] + sample(0, 0, x, y) * wx[x][1], 5), gmin, gmax);
|
|
171
|
+
add(bx, x, y, grain);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
for (let y = 0; y < ystart; y++) {
|
|
175
|
+
for (let x = xstart; x < bw; x++) {
|
|
176
|
+
const grain = clip(round2(sample(0, 1, x, y) * wy[y][0] + sample(0, 0, x, y) * wy[y][1], 5), gmin, gmax);
|
|
177
|
+
add(bx, x, y, grain);
|
|
178
|
+
}
|
|
179
|
+
for (let x = 0; x < xstart; x++) {
|
|
180
|
+
const top = clip(round2(sample(1, 1, x, y) * wx[x][0] + sample(0, 1, x, y) * wx[x][1], 5), gmin, gmax);
|
|
181
|
+
let grain = clip(round2(sample(1, 0, x, y) * wx[x][0] + sample(0, 0, x, y) * wx[x][1], 5), gmin, gmax);
|
|
182
|
+
grain = clip(round2(top * wy[y][0] + grain * wy[y][1], 5), gmin, gmax);
|
|
183
|
+
add(bx, x, y, grain);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
export function applyFilmGrain(f, g) {
|
|
189
|
+
const bitdepth = f.bitdepth, w = f.hdr.upscaledWidth, h = f.height;
|
|
190
|
+
const sx = f.ssx, sy = f.ssy;
|
|
191
|
+
const lumaLut = generateGrainY(g, bitdepth);
|
|
192
|
+
const out = f.planes.map(p => p.slice());
|
|
193
|
+
const scalingY = g.yPoints.length || g.chromaScalingFromLuma ? generateScaling(bitdepth, g.yPoints) : new Uint8Array(1 << bitdepth);
|
|
194
|
+
const isId = f.seq.matrixCoefficients === 0;
|
|
195
|
+
const rows = Math.ceil(h / BLOCK);
|
|
196
|
+
if (g.yPoints.length) {
|
|
197
|
+
for (let row = 0; row < rows; row++) {
|
|
198
|
+
applyStripe(g, out[0], f.planes[0], f.strides[0], w, Math.min(h - row * BLOCK, BLOCK), row, scalingY, lumaLut, bitdepth, 0, 0, 0, isId, f.planes[0], f.strides[0]);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (f.planes.length === 1 || !g.uvPoints[0].length && !g.uvPoints[1].length && !g.chromaScalingFromLuma)
|
|
202
|
+
return out;
|
|
203
|
+
const luma = f.planes[0], ls = f.strides[0];
|
|
204
|
+
if (w & sx)
|
|
205
|
+
for (let y = 0; y < h; y++)
|
|
206
|
+
luma[y * ls + w] = luma[y * ls + w - 1];
|
|
207
|
+
const cpw = w + sx >> sx;
|
|
208
|
+
for (let pl = 0; pl < 2; pl++) {
|
|
209
|
+
if (!g.chromaScalingFromLuma && !g.uvPoints[pl].length)
|
|
210
|
+
continue;
|
|
211
|
+
const lut = generateGrainUv(g, lumaLut, pl, sx, sy, bitdepth);
|
|
212
|
+
const scaling = g.chromaScalingFromLuma ? scalingY : generateScaling(bitdepth, g.uvPoints[pl]);
|
|
213
|
+
for (let row = 0; row < rows; row++) {
|
|
214
|
+
const bh = Math.min(h - row * BLOCK, BLOCK) + sy >> sy;
|
|
215
|
+
applyStripe(g, out[1 + pl], f.planes[1 + pl], f.strides[1], cpw, bh, row, scaling, lut, bitdepth, 1 + pl, sx, sy, isId, luma, ls);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return out;
|
|
219
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Decodes the first shown frame of an AV1 bitstream (intra frames only), following dav1d's handling of the OBUs
|
|
3
|
+
* (src/obu.c). Copyright (c) 2018-2021, VideoLAN and dav1d authors, BSD-2-Clause License (see THIRD_PARTY_NOTICES.md)
|
|
4
|
+
*/
|
|
5
|
+
import { MAX_PIXELS, checkPixels } from "../../util/limits.js";
|
|
6
|
+
import { BitReader, InterFrameError, parseSequenceHeader, parseFrameHeader, obus, OBU_SEQUENCE_HEADER, OBU_TEMPORAL_DELIMITER, OBU_FRAME_HEADER, OBU_REDUNDANT_FRAME_HEADER, OBU_FRAME, OBU_TILE_GROUP } from "./obu.js";
|
|
7
|
+
import { Frame, TileDecoder, decodeTileGroup } from "./decode.js";
|
|
8
|
+
import { postFilter } from "./postfilter.js";
|
|
9
|
+
import { applyFilmGrain } from "./filmgrain.js";
|
|
10
|
+
export { Frame };
|
|
11
|
+
export function decodeAV1(data, start = 0, end = data.length, { maxPixels = MAX_PIXELS, filmGrain = true, operatingPoint = 0, layer = -1 } = {}) {
|
|
12
|
+
let seq = null;
|
|
13
|
+
let hdr = null;
|
|
14
|
+
let frame = null;
|
|
15
|
+
let decoder = null;
|
|
16
|
+
let tilesDone = 0;
|
|
17
|
+
let opIdc = 0, target = 0;
|
|
18
|
+
let best = null;
|
|
19
|
+
const refs = new Array(8).fill(null);
|
|
20
|
+
for (const obu of obus(data, start, end)) {
|
|
21
|
+
if (obu.type !== OBU_SEQUENCE_HEADER && obu.type !== OBU_TEMPORAL_DELIMITER && opIdc &&
|
|
22
|
+
(!(opIdc >> obu.temporalId & 1) || !(opIdc >> obu.spatialId + 8 & 1)))
|
|
23
|
+
continue;
|
|
24
|
+
if (obu.type === OBU_REDUNDANT_FRAME_HEADER && hdr)
|
|
25
|
+
continue;
|
|
26
|
+
const r = new BitReader(data, obu.start, obu.end);
|
|
27
|
+
switch (obu.type === OBU_REDUNDANT_FRAME_HEADER ? OBU_FRAME_HEADER : obu.type) {
|
|
28
|
+
case OBU_SEQUENCE_HEADER:
|
|
29
|
+
seq = parseSequenceHeader(r);
|
|
30
|
+
opIdc = seq.operatingPoints[Math.min(operatingPoint, seq.operatingPoints.length - 1)].idc;
|
|
31
|
+
target = opIdc >> 8 ? 31 - Math.clz32(opIdc >> 8) : 0;
|
|
32
|
+
if (layer >= 0 && layer < target)
|
|
33
|
+
target = layer;
|
|
34
|
+
break;
|
|
35
|
+
case OBU_FRAME_HEADER:
|
|
36
|
+
case OBU_FRAME: {
|
|
37
|
+
if (!seq)
|
|
38
|
+
throw new Error('AV1: frame before the sequence header');
|
|
39
|
+
try {
|
|
40
|
+
hdr = parseFrameHeader(r, seq, obu.temporalId, obu.spatialId);
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
const lower = best;
|
|
44
|
+
if (!(err instanceof InterFrameError) || !lower)
|
|
45
|
+
throw err;
|
|
46
|
+
lower.incomplete = true;
|
|
47
|
+
return lower;
|
|
48
|
+
}
|
|
49
|
+
if (hdr.showExistingFrame) {
|
|
50
|
+
const shown = refs[hdr.existingFrameIdx];
|
|
51
|
+
if (!shown)
|
|
52
|
+
throw new Error('AV1: shows a frame that doesn\'t exist');
|
|
53
|
+
return output(shown);
|
|
54
|
+
}
|
|
55
|
+
checkPixels(hdr.upscaledWidth, hdr.height, maxPixels);
|
|
56
|
+
frame = new Frame(seq, hdr);
|
|
57
|
+
decoder = new TileDecoder(frame);
|
|
58
|
+
tilesDone = 0;
|
|
59
|
+
if (obu.type !== OBU_FRAME)
|
|
60
|
+
break;
|
|
61
|
+
r.align();
|
|
62
|
+
const shown = tileGroup(r, obu.end, obu.spatialId);
|
|
63
|
+
if (shown)
|
|
64
|
+
return shown;
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
case OBU_TILE_GROUP: {
|
|
68
|
+
if (!hdr || !frame)
|
|
69
|
+
throw new Error('AV1: tile group without a frame header');
|
|
70
|
+
const shown = tileGroup(r, obu.end, obu.spatialId);
|
|
71
|
+
if (shown)
|
|
72
|
+
return shown;
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const lower = best;
|
|
78
|
+
if (lower)
|
|
79
|
+
return lower;
|
|
80
|
+
throw new Error('AV1: no frame');
|
|
81
|
+
function tileGroup(r, end, spatialId) {
|
|
82
|
+
const h = hdr, f = frame;
|
|
83
|
+
const count = h.tiles.cols * h.tiles.rows;
|
|
84
|
+
let first = 0, last = count - 1;
|
|
85
|
+
if (count > 1 && r.bit()) {
|
|
86
|
+
const bits = h.tiles.log2Cols + h.tiles.log2Rows;
|
|
87
|
+
first = r.bits(bits);
|
|
88
|
+
last = r.bits(bits);
|
|
89
|
+
}
|
|
90
|
+
r.align();
|
|
91
|
+
if (first !== tilesDone || last < first || last >= count)
|
|
92
|
+
throw new Error('AV1: invalid tile group');
|
|
93
|
+
decodeTileGroup(decoder, data, r.byte, end, first, last);
|
|
94
|
+
tilesDone = last + 1;
|
|
95
|
+
if (tilesDone < count)
|
|
96
|
+
return null;
|
|
97
|
+
postFilter(f);
|
|
98
|
+
for (let i = 0; i < 8; i++)
|
|
99
|
+
if (h.refreshFrameFlags >> i & 1)
|
|
100
|
+
refs[i] = f;
|
|
101
|
+
if (!h.showFrame)
|
|
102
|
+
return null;
|
|
103
|
+
if (opIdc && spatialId < target) {
|
|
104
|
+
best = output(f);
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
return output(f);
|
|
108
|
+
}
|
|
109
|
+
function output(f) {
|
|
110
|
+
if (filmGrain && f.hdr.filmGrain)
|
|
111
|
+
f.planes = applyFilmGrain(f, f.hdr.filmGrain);
|
|
112
|
+
return f;
|
|
113
|
+
}
|
|
114
|
+
}
|