@@ -15,6 +15,7 @@ namespace Gfx::JPEG2000 {
15
15
16
16
struct BitplaneDecodingOptions {
17
17
bool reset_context_probabilities_each_pass { false };
18
+ bool uses_vertically_causal_context { false };
18
19
};
19
20
20
21
inline ErrorOr<void > decode_code_block (Span2D<i16 > result, SubBand sub_band, int number_of_coding_passes, ReadonlyBytes data, int M_b, int p, BitplaneDecodingOptions options = {})
@@ -87,6 +88,14 @@ inline ErrorOr<void> decode_code_block(Span2D<i16> result, SubBand sub_band, int
87
88
auto strip_value = significance_and_sign[strip_offset + x];
88
89
return (strip_value & (1 << strip_y)) != 0 ;
89
90
};
91
+ auto is_significant_with_y_horizon = [&](int x, int y, int y_horizon) {
92
+ if (options.uses_vertically_causal_context && y >= y_horizon) {
93
+ // D.7 Vertically causal context formation
94
+ // "any coefficient from the next code-block scan is considered to be insignificant"
95
+ return false ;
96
+ }
97
+ return is_significant (x, y);
98
+ };
90
99
auto sign_is_negative = [&](int x, int y) {
91
100
auto strip_index = y / 4 ;
92
101
auto strip_y = y % 4 ;
@@ -120,11 +129,11 @@ inline ErrorOr<void> decode_code_block(Span2D<i16> result, SubBand sub_band, int
120
129
121
130
// Helper functions, mostly for computing arithmetic decoder contexts in various situations.
122
131
123
- auto compute_context_ll_lh = [&](int x, int y) -> unsigned {
132
+ auto compute_context_ll_lh = [&](int x, int y, int y_horizon ) -> unsigned {
124
133
// Table D.1 – Contexts for the significance propagation and cleanup coding passes
125
134
u8 sum_h = is_significant (x - 1 , y) + is_significant (x + 1 , y);
126
- u8 sum_v = is_significant (x, y - 1 ) + is_significant (x, y + 1 );
127
- u8 sum_d = is_significant (x - 1 , y - 1 ) + is_significant (x - 1 , y + 1 ) + is_significant (x + 1 , y - 1 ) + is_significant (x + 1 , y + 1 );
135
+ u8 sum_v = is_significant (x, y - 1 ) + is_significant_with_y_horizon (x, y + 1 , y_horizon );
136
+ u8 sum_d = is_significant (x - 1 , y - 1 ) + is_significant_with_y_horizon (x - 1 , y + 1 , y_horizon ) + is_significant (x + 1 , y - 1 ) + is_significant_with_y_horizon (x + 1 , y + 1 , y_horizon );
128
137
129
138
if (sum_h == 2 )
130
139
return 8 ;
@@ -150,11 +159,11 @@ inline ErrorOr<void> decode_code_block(Span2D<i16> result, SubBand sub_band, int
150
159
};
151
160
152
161
// Like compute_context_ll_lh but with sum_h and sum_v swapped
153
- auto compute_context_hl = [&](int x, int y) -> unsigned {
162
+ auto compute_context_hl = [&](int x, int y, int y_horizon ) -> unsigned {
154
163
// Table D.1 – Contexts for the significance propagation and cleanup coding passes
155
164
u8 sum_h = is_significant (x - 1 , y) + is_significant (x + 1 , y);
156
- u8 sum_v = is_significant (x, y - 1 ) + is_significant (x, y + 1 );
157
- u8 sum_d = is_significant (x - 1 , y - 1 ) + is_significant (x - 1 , y + 1 ) + is_significant (x + 1 , y - 1 ) + is_significant (x + 1 , y + 1 );
165
+ u8 sum_v = is_significant (x, y - 1 ) + is_significant_with_y_horizon (x, y + 1 , y_horizon );
166
+ u8 sum_d = is_significant (x - 1 , y - 1 ) + is_significant_with_y_horizon (x - 1 , y + 1 , y_horizon ) + is_significant (x + 1 , y - 1 ) + is_significant_with_y_horizon (x + 1 , y + 1 , y_horizon );
158
167
159
168
if (sum_v == 2 )
160
169
return 8 ;
@@ -179,12 +188,12 @@ inline ErrorOr<void> decode_code_block(Span2D<i16> result, SubBand sub_band, int
179
188
return 0 ;
180
189
};
181
190
182
- auto compute_context_hh = [&](int x, int y) -> unsigned {
191
+ auto compute_context_hh = [&](int x, int y, int y_horizon ) -> unsigned {
183
192
// Table D.1 – Contexts for the significance propagation and cleanup coding passes
184
193
u8 sum_h = is_significant (x - 1 , y) + is_significant (x + 1 , y);
185
- u8 sum_v = is_significant (x, y - 1 ) + is_significant (x, y + 1 );
194
+ u8 sum_v = is_significant (x, y - 1 ) + is_significant_with_y_horizon (x, y + 1 , y_horizon );
186
195
u8 sum_h_v = sum_h + sum_v;
187
- u8 sum_d = is_significant (x - 1 , y - 1 ) + is_significant (x - 1 , y + 1 ) + is_significant (x + 1 , y - 1 ) + is_significant (x + 1 , y + 1 );
196
+ u8 sum_d = is_significant (x - 1 , y - 1 ) + is_significant_with_y_horizon (x - 1 , y + 1 , y_horizon ) + is_significant (x + 1 , y - 1 ) + is_significant_with_y_horizon (x + 1 , y + 1 , y_horizon );
188
197
189
198
if (sum_d >= 3 )
190
199
return 8 ;
@@ -211,24 +220,24 @@ inline ErrorOr<void> decode_code_block(Span2D<i16> result, SubBand sub_band, int
211
220
return 0 ;
212
221
};
213
222
214
- auto compute_context = [&](int x, int y) -> unsigned {
223
+ auto compute_context = [&](int x, int y, int y_horizon ) -> unsigned {
215
224
switch (sub_band) {
216
225
case SubBand::HorizontalLowpassVerticalLowpass:
217
226
case SubBand::HorizontalLowpassVerticalHighpass:
218
- return compute_context_ll_lh (x, y);
227
+ return compute_context_ll_lh (x, y, y_horizon );
219
228
case SubBand::HorizontalHighpassVerticalLowpass:
220
- return compute_context_hl (x, y);
229
+ return compute_context_hl (x, y, y_horizon );
221
230
case SubBand::HorizontalHighpassVerticalHighpass:
222
- return compute_context_hh (x, y);
231
+ return compute_context_hh (x, y, y_horizon );
223
232
}
224
233
VERIFY_NOT_REACHED ();
225
234
};
226
235
227
- auto v_or_h_contribution = [&](IntPoint p, IntPoint d0, IntPoint d1) -> i8 {
236
+ auto v_or_h_contribution = [&](IntPoint p, IntPoint d0, IntPoint d1, int y_horizon ) -> i8 {
228
237
auto p0 = p + d0;
229
238
auto p1 = p + d1;
230
239
// Table D.2 – Contributions of the vertical (and the horizontal) neighbours to the sign context
231
- if (is_significant (p1.x (), p1.y ())) {
240
+ if (is_significant_with_y_horizon (p1.x (), p1.y (), y_horizon )) {
232
241
if (!sign_is_negative (p1.x (), p1.y ())) {
233
242
if (is_significant (p0.x (), p0.y ()))
234
243
return !sign_is_negative (p0.x (), p0.y ()) ? 1 : 0 ;
@@ -243,13 +252,13 @@ inline ErrorOr<void> decode_code_block(Span2D<i16> result, SubBand sub_band, int
243
252
return 0 ;
244
253
};
245
254
246
- auto read_sign_bit = [&](int x, int y) {
255
+ auto read_sign_bit = [&](int x, int y, int y_horizon ) {
247
256
// C2, Decode sign bit of current coefficient
248
257
// Sign bit
249
258
// D.3.2 Sign bit decoding
250
259
// Table D.2 – Contributions of the vertical (and the horizontal) neighbours to the sign context
251
- i8 v_contribution = v_or_h_contribution ({ x, y }, { 0 , -1 }, { 0 , 1 });
252
- i8 h_contribution = v_or_h_contribution ({ x, y }, { -1 , 0 }, { 1 , 0 });
260
+ i8 v_contribution = v_or_h_contribution ({ x, y }, { 0 , -1 }, { 0 , 1 }, y_horizon );
261
+ i8 h_contribution = v_or_h_contribution ({ x, y }, { -1 , 0 }, { 1 , 0 }, y_horizon );
253
262
// Table D.3 – Sign contexts from the vertical and horizontal contributions
254
263
u8 context_label = 9 ;
255
264
if (h_contribution == 0 )
@@ -282,7 +291,7 @@ inline ErrorOr<void> decode_code_block(Span2D<i16> result, SubBand sub_band, int
282
291
// D1, Is the current coefficient significant?
283
292
if (!is_significant (x, y + coefficient_index)) {
284
293
// D2, Is the context bin zero? (see Table D.1)
285
- u8 context = compute_context (x, y + coefficient_index);
294
+ u8 context = compute_context (x, y + coefficient_index, y + 4 );
286
295
if (context != 0 ) {
287
296
// C1, Decode significance bit of current coefficient (See D.3.1)
288
297
bool is_newly_significant = arithmetic_decoder.get_next_bit (all_other_contexts[context]);
@@ -295,7 +304,7 @@ inline ErrorOr<void> decode_code_block(Span2D<i16> result, SubBand sub_band, int
295
304
296
305
// D3, Did the current coefficient just become significant?
297
306
if (is_newly_significant) {
298
- bool sign_bit = read_sign_bit (x, y + coefficient_index);
307
+ bool sign_bit = read_sign_bit (x, y + coefficient_index, y + 4 );
299
308
set_sign (x, y + coefficient_index, sign_bit);
300
309
}
301
310
}
@@ -327,8 +336,8 @@ inline ErrorOr<void> decode_code_block(Span2D<i16> result, SubBand sub_band, int
327
336
u8 context;
328
337
if (became_significant_at_bitplane[(y + coefficient_index) * w + x] == current_bitplane - 1 ) {
329
338
u8 sum_h = is_significant (x - 1 , y + coefficient_index) + is_significant (x + 1 , y + coefficient_index);
330
- u8 sum_v = is_significant (x, y + coefficient_index - 1 ) + is_significant (x, y + coefficient_index + 1 );
331
- u8 sum_d = is_significant (x - 1 , y + coefficient_index - 1 ) + is_significant (x - 1 , y + coefficient_index + 1 ) + is_significant (x + 1 , y + coefficient_index - 1 ) + is_significant (x + 1 , y + coefficient_index + 1 );
339
+ u8 sum_v = is_significant (x, y + coefficient_index - 1 ) + is_significant_with_y_horizon (x, y + coefficient_index + 1 , y + 4 );
340
+ u8 sum_d = is_significant (x - 1 , y + coefficient_index - 1 ) + is_significant_with_y_horizon (x - 1 , y + coefficient_index + 1 , y + 4 ) + is_significant (x + 1 , y + coefficient_index - 1 ) + is_significant_with_y_horizon (x + 1 , y + coefficient_index + 1 , y + 4 );
332
341
context = (sum_h + sum_v + sum_d) >= 1 ? 15 : 14 ;
333
342
} else {
334
343
context = 16 ;
@@ -355,7 +364,7 @@ inline ErrorOr<void> decode_code_block(Span2D<i16> result, SubBand sub_band, int
355
364
Array<u8 , 4 > contexts {};
356
365
int num_undecoded = 0 ;
357
366
for (int i = 0 ; i < 4 ; ++i) {
358
- contexts[i] = compute_context (x, y + i);
367
+ contexts[i] = compute_context (x, y + i, y + 4 );
359
368
if (!is_significant (x, y + i))
360
369
++num_undecoded; // FIXME: This is probably redundant since this would imply a context being non-0.
361
370
}
@@ -386,7 +395,7 @@ inline ErrorOr<void> decode_code_block(Span2D<i16> result, SubBand sub_band, int
386
395
++coefficient_index;
387
396
388
397
// C1, Decode significance bit of current coefficient (See D.3.1)
389
- u8 context = compute_context (x, y + coefficient_index); // PERF: could use `contexts` cache (needs invalidation then).
398
+ u8 context = compute_context (x, y + coefficient_index, y + 4 ); // PERF: could use `contexts` cache (needs invalidation then).
390
399
bool is_newly_significant = arithmetic_decoder.get_next_bit (all_other_contexts[context]);
391
400
is_current_coefficient_significant = is_newly_significant;
392
401
set_significant (x, y + coefficient_index, is_newly_significant);
@@ -399,7 +408,7 @@ inline ErrorOr<void> decode_code_block(Span2D<i16> result, SubBand sub_band, int
399
408
400
409
// D3, Did the current coefficient just become significant?
401
410
if (is_current_coefficient_significant) {
402
- bool sign_bit = read_sign_bit (x, y + coefficient_index);
411
+ bool sign_bit = read_sign_bit (x, y + coefficient_index, y + 4 );
403
412
set_sign (x, y + coefficient_index, sign_bit);
404
413
}
405
414
@@ -422,7 +431,7 @@ inline ErrorOr<void> decode_code_block(Span2D<i16> result, SubBand sub_band, int
422
431
bool has_already_been_coded = pass > 0 && was_coded_in_pass[(y + coefficient_index) * w + x] == pass - 2 ;
423
432
if (!is_significant_or_coded && !has_already_been_coded) {
424
433
// C1, Decode significance bit of current coefficient
425
- u8 context = compute_context (x, y + coefficient_index); // PERF: could use `contexts` cache (needs invalidation then).
434
+ u8 context = compute_context (x, y + coefficient_index, y + 4 ); // PERF: could use `contexts` cache (needs invalidation then).
426
435
bool is_newly_significant = arithmetic_decoder.get_next_bit (all_other_contexts[context]);
427
436
set_significant (x, y + coefficient_index, is_newly_significant);
428
437
if (is_newly_significant) {
@@ -432,7 +441,7 @@ inline ErrorOr<void> decode_code_block(Span2D<i16> result, SubBand sub_band, int
432
441
433
442
// D3, Did the current coefficient just become significant?
434
443
if (is_newly_significant) {
435
- bool sign_bit = read_sign_bit (x, y + coefficient_index);
444
+ bool sign_bit = read_sign_bit (x, y + coefficient_index, y + 4 );
436
445
set_sign (x, y + coefficient_index, sign_bit);
437
446
}
438
447
}
0 commit comments