/src/libjxl/lib/jxl/dec_frame.cc
Line | Count | Source |
1 | | // Copyright (c) the JPEG XL Project Authors. All rights reserved. |
2 | | // |
3 | | // Use of this source code is governed by a BSD-style |
4 | | // license that can be found in the LICENSE file. |
5 | | |
6 | | #include "lib/jxl/dec_frame.h" |
7 | | |
8 | | #include <jxl/decode.h> |
9 | | #include <jxl/memory_manager.h> |
10 | | #include <jxl/types.h> |
11 | | |
12 | | #include <algorithm> |
13 | | #include <cstddef> |
14 | | #include <cstdint> |
15 | | #include <cstdlib> |
16 | | #include <memory> |
17 | | #include <utility> |
18 | | #include <vector> |
19 | | |
20 | | #include "lib/jxl/ac_context.h" |
21 | | #include "lib/jxl/ac_strategy.h" |
22 | | #include "lib/jxl/base/bits.h" |
23 | | #include "lib/jxl/base/common.h" |
24 | | #include "lib/jxl/base/compiler_specific.h" |
25 | | #include "lib/jxl/base/data_parallel.h" |
26 | | #include "lib/jxl/base/printf_macros.h" |
27 | | #include "lib/jxl/base/rect.h" |
28 | | #include "lib/jxl/base/span.h" |
29 | | #include "lib/jxl/base/status.h" |
30 | | #include "lib/jxl/chroma_from_luma.h" |
31 | | #include "lib/jxl/coeff_order.h" |
32 | | #include "lib/jxl/coeff_order_fwd.h" |
33 | | #include "lib/jxl/common.h" // kMaxNumPasses |
34 | | #include "lib/jxl/compressed_dc.h" |
35 | | #include "lib/jxl/dct_util.h" |
36 | | #include "lib/jxl/dec_ans.h" |
37 | | #include "lib/jxl/dec_bit_reader.h" |
38 | | #include "lib/jxl/dec_cache.h" |
39 | | #include "lib/jxl/dec_group.h" |
40 | | #include "lib/jxl/dec_modular.h" |
41 | | #include "lib/jxl/dec_noise.h" |
42 | | #include "lib/jxl/dec_patch_dictionary.h" |
43 | | #include "lib/jxl/entropy_coder.h" |
44 | | #include "lib/jxl/epf.h" |
45 | | #include "lib/jxl/fields.h" |
46 | | #include "lib/jxl/frame_dimensions.h" |
47 | | #include "lib/jxl/frame_header.h" |
48 | | #include "lib/jxl/image_bundle.h" |
49 | | #include "lib/jxl/image_metadata.h" |
50 | | #include "lib/jxl/image_ops.h" |
51 | | #include "lib/jxl/jpeg/jpeg_data.h" |
52 | | #include "lib/jxl/loop_filter.h" |
53 | | #include "lib/jxl/passes_state.h" |
54 | | #include "lib/jxl/quant_weights.h" |
55 | | #include "lib/jxl/quantizer.h" |
56 | | #include "lib/jxl/render_pipeline/render_pipeline.h" |
57 | | #include "lib/jxl/splines.h" |
58 | | #include "lib/jxl/toc.h" |
59 | | |
60 | | namespace jxl { |
61 | | |
62 | | namespace { |
63 | | Status DecodeGlobalDCInfo(BitReader* reader, bool is_jpeg, |
64 | 6.32k | PassesDecoderState* state, ThreadPool* pool) { |
65 | 6.32k | JXL_RETURN_IF_ERROR(state->shared_storage.quantizer.Decode(reader)); |
66 | | |
67 | 6.32k | JXL_RETURN_IF_ERROR(DecodeBlockCtxMap(state->memory_manager(), reader, |
68 | 6.32k | &state->shared_storage.block_ctx_map)); |
69 | | |
70 | 6.28k | JXL_RETURN_IF_ERROR(state->shared_storage.cmap.DecodeDC(reader)); |
71 | | |
72 | | // Pre-compute info for decoding a group. |
73 | 6.28k | if (is_jpeg) { |
74 | 0 | state->shared_storage.quantizer.ClearDCMul(); // Don't dequant DC |
75 | 0 | } |
76 | | |
77 | 6.28k | state->shared_storage.ac_strategy.FillInvalid(); |
78 | 6.28k | return true; |
79 | 6.28k | } |
80 | | } // namespace |
81 | | |
82 | | Status DecodeFrame(PassesDecoderState* dec_state, ThreadPool* JXL_RESTRICT pool, |
83 | | const uint8_t* next_in, size_t avail_in, |
84 | | FrameHeader* frame_header, ImageBundle* decoded, |
85 | | const CodecMetadata& metadata, |
86 | 911 | bool use_slow_rendering_pipeline) { |
87 | 911 | FrameDecoder frame_decoder(dec_state, metadata, pool, |
88 | 911 | use_slow_rendering_pipeline); |
89 | | |
90 | 911 | BitReader reader(Bytes(next_in, avail_in)); |
91 | 911 | JXL_RETURN_IF_ERROR(frame_decoder.InitFrame(&reader, decoded, |
92 | 911 | /*is_preview=*/false)); |
93 | 911 | JXL_RETURN_IF_ERROR(frame_decoder.InitFrameOutput()); |
94 | 911 | if (frame_header) { |
95 | 0 | *frame_header = frame_decoder.GetFrameHeader(); |
96 | 0 | } |
97 | | |
98 | 911 | JXL_RETURN_IF_ERROR(reader.AllReadsWithinBounds()); |
99 | 911 | size_t header_bytes = reader.TotalBitsConsumed() / kBitsPerByte; |
100 | 911 | JXL_RETURN_IF_ERROR(reader.Close()); |
101 | | |
102 | 911 | size_t processed_bytes = header_bytes; |
103 | 911 | Status close_ok = true; |
104 | 911 | std::vector<std::unique_ptr<BitReader>> section_readers; |
105 | 911 | { |
106 | 911 | std::vector<std::unique_ptr<BitReaderScopedCloser>> section_closers; |
107 | 911 | std::vector<FrameDecoder::SectionInfo> section_info; |
108 | 911 | std::vector<FrameDecoder::SectionStatus> section_status; |
109 | 911 | size_t pos = header_bytes; |
110 | 911 | size_t index = 0; |
111 | 911 | for (auto toc_entry : frame_decoder.Toc()) { |
112 | 911 | JXL_RETURN_IF_ERROR(pos + toc_entry.size <= avail_in); |
113 | 911 | auto br = make_unique<BitReader>(Bytes(next_in + pos, toc_entry.size)); |
114 | 911 | section_info.emplace_back( |
115 | 911 | FrameDecoder::SectionInfo{br.get(), toc_entry.id, index++}); |
116 | 911 | section_closers.emplace_back( |
117 | 911 | make_unique<BitReaderScopedCloser>(*br, close_ok)); |
118 | 911 | section_readers.emplace_back(std::move(br)); |
119 | 911 | pos += toc_entry.size; |
120 | 911 | } |
121 | 911 | section_status.resize(section_info.size()); |
122 | 911 | JXL_RETURN_IF_ERROR(frame_decoder.ProcessSections( |
123 | 911 | section_info.data(), section_info.size(), section_status.data())); |
124 | 1.82k | for (size_t i = 0; i < section_status.size(); i++) { |
125 | 911 | JXL_RETURN_IF_ERROR(section_status[i] == FrameDecoder::kDone); |
126 | 911 | processed_bytes += frame_decoder.Toc()[i].size; |
127 | 911 | } |
128 | 911 | } |
129 | 911 | JXL_RETURN_IF_ERROR(close_ok); |
130 | 911 | JXL_RETURN_IF_ERROR(frame_decoder.FinalizeFrame()); |
131 | 911 | decoded->SetDecodedBytes(processed_bytes); |
132 | 911 | return true; |
133 | 911 | } |
134 | | |
135 | | Status FrameDecoder::InitFrame(BitReader* JXL_RESTRICT br, ImageBundle* decoded, |
136 | 69.1k | bool is_preview) { |
137 | 69.1k | decoded_ = decoded; |
138 | 69.1k | JXL_ENSURE(is_finalized_); |
139 | 69.1k | JxlMemoryManager* memory_manager = decoded_->memory_manager(); |
140 | | |
141 | | // Reset the dequantization matrices to their default values. |
142 | 69.1k | dec_state_->shared_storage.matrices = DequantMatrices(); |
143 | | |
144 | 69.1k | frame_header_.nonserialized_is_preview = is_preview; |
145 | 69.1k | JXL_ENSURE(frame_header_.nonserialized_metadata != nullptr); |
146 | 69.1k | JXL_RETURN_IF_ERROR(ReadFrameHeader(br, &frame_header_)); |
147 | 56.0k | frame_dim_ = frame_header_.ToFrameDimensions(); |
148 | 56.0k | JXL_DEBUG_V(2, "FrameHeader: %s", frame_header_.DebugString().c_str()); |
149 | | |
150 | 56.0k | const size_t num_passes = frame_header_.passes.num_passes; |
151 | 56.0k | const size_t num_groups = frame_dim_.num_groups; |
152 | | |
153 | | // If the previous frame was not a kRegularFrame, `decoded` may have different |
154 | | // dimensions; must reset to avoid errors. |
155 | 56.0k | decoded->RemoveColor(); |
156 | 56.0k | decoded->ClearExtraChannels(); |
157 | | |
158 | 56.0k | decoded->duration = frame_header_.animation_frame.duration; |
159 | | |
160 | 56.0k | if (!frame_header_.nonserialized_is_preview && |
161 | 54.8k | (frame_header_.is_last || frame_header_.animation_frame.duration > 0) && |
162 | 12.1k | (frame_header_.frame_type == kRegularFrame || |
163 | 12.1k | frame_header_.frame_type == kSkipProgressive)) { |
164 | 12.1k | ++dec_state_->visible_frame_index; |
165 | 12.1k | dec_state_->nonvisible_frame_index = 0; |
166 | 43.8k | } else { |
167 | 43.8k | ++dec_state_->nonvisible_frame_index; |
168 | 43.8k | } |
169 | | |
170 | | // Read TOC. |
171 | 56.0k | const size_t toc_entries = |
172 | 56.0k | NumTocEntries(num_groups, frame_dim_.num_dc_groups, num_passes); |
173 | 56.0k | std::vector<uint32_t> sizes; |
174 | 56.0k | std::vector<coeff_order_t> permutation; |
175 | 56.0k | JXL_RETURN_IF_ERROR( |
176 | 56.0k | ReadToc(memory_manager, toc_entries, br, &sizes, &permutation)); |
177 | 47.8k | bool have_permutation = !permutation.empty(); |
178 | 47.8k | toc_.resize(toc_entries); |
179 | 47.8k | section_sizes_sum_ = 0; |
180 | 150k | for (size_t i = 0; i < toc_entries; ++i) { |
181 | 102k | toc_[i].size = sizes[i]; |
182 | 102k | size_t index = have_permutation ? permutation[i] : i; |
183 | 102k | toc_[index].id = i; |
184 | 102k | if (section_sizes_sum_ + toc_[i].size < section_sizes_sum_) { |
185 | 0 | return JXL_FAILURE("group offset overflow"); |
186 | 0 | } |
187 | 102k | section_sizes_sum_ += toc_[i].size; |
188 | 102k | } |
189 | | |
190 | 47.8k | if (JXL_DEBUG_V_LEVEL >= 3) { |
191 | 0 | for (size_t i = 0; i < toc_entries; ++i) { |
192 | 0 | JXL_DEBUG_V(3, "TOC entry %" PRIuS " size %" PRIuS " id %" PRIuS "", i, |
193 | 0 | toc_[i].size, toc_[i].id); |
194 | 0 | } |
195 | 0 | } |
196 | | |
197 | 47.8k | JXL_ENSURE((br->TotalBitsConsumed() % kBitsPerByte) == 0); |
198 | 47.8k | const size_t group_codes_begin = br->TotalBitsConsumed() / kBitsPerByte; |
199 | 47.8k | JXL_ENSURE(!toc_.empty()); |
200 | | |
201 | | // Overflow check. |
202 | 47.8k | if (group_codes_begin + section_sizes_sum_ < group_codes_begin) { |
203 | 0 | return JXL_FAILURE("Invalid group codes"); |
204 | 0 | } |
205 | | |
206 | 47.8k | if (!frame_header_.chroma_subsampling.Is444() && |
207 | 7.22k | !(frame_header_.flags & FrameHeader::kSkipAdaptiveDCSmoothing) && |
208 | 6.88k | frame_header_.encoding == FrameEncoding::kVarDCT) { |
209 | 8 | return JXL_FAILURE( |
210 | 8 | "Non-444 chroma subsampling is not allowed when adaptive DC " |
211 | 8 | "smoothing is enabled"); |
212 | 8 | } |
213 | 47.8k | return true; |
214 | 47.8k | } |
215 | | |
216 | 38.0k | Status FrameDecoder::InitFrameOutput() { |
217 | 38.0k | JXL_RETURN_IF_ERROR( |
218 | 38.0k | InitializePassesSharedState(frame_header_, &dec_state_->shared_storage)); |
219 | 38.0k | JXL_RETURN_IF_ERROR(dec_state_->Init(frame_header_)); |
220 | 38.0k | modular_frame_decoder_.Init(frame_dim_); |
221 | | |
222 | 38.0k | if (decoded_->IsJPEG()) { |
223 | 0 | if (frame_header_.encoding == FrameEncoding::kModular) { |
224 | 0 | return JXL_FAILURE("Cannot output JPEG from Modular"); |
225 | 0 | } |
226 | 0 | jpeg::JPEGData* jpeg_data = decoded_->jpeg_data.get(); |
227 | 0 | size_t num_components = jpeg_data->components.size(); |
228 | 0 | if (num_components != 1 && num_components != 3) { |
229 | 0 | return JXL_FAILURE("Invalid number of components"); |
230 | 0 | } |
231 | 0 | if (frame_header_.nonserialized_metadata->m.xyb_encoded) { |
232 | 0 | return JXL_FAILURE("Cannot decode to JPEG an XYB image"); |
233 | 0 | } |
234 | 0 | auto jpeg_c_map = JpegOrder(ColorTransform::kYCbCr, num_components == 1); |
235 | 0 | decoded_->jpeg_data->width = frame_dim_.xsize; |
236 | 0 | decoded_->jpeg_data->height = frame_dim_.ysize; |
237 | 0 | for (size_t c = 0; c < num_components; c++) { |
238 | 0 | auto& component = jpeg_data->components[jpeg_c_map[c]]; |
239 | 0 | component.width_in_blocks = |
240 | 0 | frame_dim_.xsize_blocks >> frame_header_.chroma_subsampling.HShift(c); |
241 | 0 | component.height_in_blocks = |
242 | 0 | frame_dim_.ysize_blocks >> frame_header_.chroma_subsampling.VShift(c); |
243 | 0 | component.h_samp_factor = |
244 | 0 | 1 << frame_header_.chroma_subsampling.RawHShift(c); |
245 | 0 | component.v_samp_factor = |
246 | 0 | 1 << frame_header_.chroma_subsampling.RawVShift(c); |
247 | 0 | size_t num_blocks = static_cast<size_t>(component.width_in_blocks) * |
248 | 0 | component.height_in_blocks; |
249 | 0 | component.coeffs.resize(num_blocks * jxl::kDCTBlockSize); |
250 | 0 | } |
251 | 0 | } |
252 | | |
253 | | // Clear the state. |
254 | 38.0k | decoded_dc_global_ = false; |
255 | 38.0k | decoded_ac_global_ = false; |
256 | 38.0k | is_finalized_ = false; |
257 | 38.0k | finalized_dc_ = false; |
258 | 38.0k | num_sections_done_ = 0; |
259 | 38.0k | decoded_dc_groups_.clear(); |
260 | 38.0k | decoded_dc_groups_.resize(frame_dim_.num_dc_groups); |
261 | 38.0k | decoded_passes_per_ac_group_.clear(); |
262 | 38.0k | decoded_passes_per_ac_group_.resize(frame_dim_.num_groups, 0); |
263 | 38.0k | processed_section_.clear(); |
264 | 38.0k | processed_section_.resize(toc_.size()); |
265 | 38.0k | allocated_ = false; |
266 | 38.0k | return true; |
267 | 38.0k | } |
268 | | |
269 | 37.6k | Status FrameDecoder::ProcessDCGlobal(BitReader* br) { |
270 | 37.6k | PassesSharedState& shared = dec_state_->shared_storage; |
271 | 37.6k | JxlMemoryManager* memory_manager = shared.memory_manager; |
272 | 37.6k | if (frame_header_.flags & FrameHeader::kPatches) { |
273 | 1.11k | bool uses_extra_channels = false; |
274 | 1.11k | JXL_RETURN_IF_ERROR(shared.image_features.patches.Decode( |
275 | 1.11k | memory_manager, br, frame_dim_.xsize_padded, frame_dim_.ysize_padded, |
276 | 1.11k | shared.metadata->m.num_extra_channels, &uses_extra_channels)); |
277 | 1.05k | if (uses_extra_channels && frame_header_.upsampling != 1) { |
278 | 37 | for (size_t ecups : frame_header_.extra_channel_upsampling) { |
279 | 37 | if (ecups != frame_header_.upsampling) { |
280 | 1 | return JXL_FAILURE( |
281 | 1 | "Cannot use extra channels in patches if color channels are " |
282 | 1 | "subsampled differently from extra channels"); |
283 | 1 | } |
284 | 37 | } |
285 | 20 | } |
286 | 36.4k | } else { |
287 | 36.4k | shared.image_features.patches.Clear(); |
288 | 36.4k | } |
289 | 37.5k | shared.image_features.splines.Clear(); |
290 | 37.5k | if (frame_header_.flags & FrameHeader::kSplines) { |
291 | 2.18k | JXL_RETURN_IF_ERROR(shared.image_features.splines.Decode( |
292 | 2.18k | memory_manager, br, frame_dim_.xsize * frame_dim_.ysize)); |
293 | 2.18k | } |
294 | 37.4k | if (frame_header_.flags & FrameHeader::kNoise) { |
295 | 5.41k | JXL_RETURN_IF_ERROR(DecodeNoise(br, &shared.image_features.noise_params)); |
296 | 5.41k | } |
297 | 37.4k | JXL_RETURN_IF_ERROR(dec_state_->shared_storage.matrices.DecodeDC(br)); |
298 | | |
299 | 37.1k | if (frame_header_.encoding == FrameEncoding::kVarDCT) { |
300 | 6.32k | JXL_RETURN_IF_ERROR( |
301 | 6.32k | jxl::DecodeGlobalDCInfo(br, decoded_->IsJPEG(), dec_state_, pool_)); |
302 | 6.32k | } |
303 | | // Splines' draw cache uses the color correlation map. |
304 | 37.0k | if (frame_header_.flags & FrameHeader::kSplines) { |
305 | 2.04k | JXL_RETURN_IF_ERROR(shared.image_features.splines.InitializeDrawCache( |
306 | 2.04k | frame_dim_.xsize_upsampled, frame_dim_.ysize_upsampled, |
307 | 2.04k | dec_state_->shared->cmap.base())); |
308 | 2.04k | } |
309 | 37.0k | Status dec_status = modular_frame_decoder_.DecodeGlobalInfo( |
310 | 37.0k | br, frame_header_, /*allow_truncated_group=*/false); |
311 | 37.0k | if (dec_status.IsFatalError()) return dec_status; |
312 | 35.3k | if (dec_status) { |
313 | 35.0k | decoded_dc_global_ = true; |
314 | 35.0k | } |
315 | 35.3k | return dec_status; |
316 | 37.0k | } |
317 | | |
318 | 35.4k | Status FrameDecoder::ProcessDCGroup(size_t dc_group_id, BitReader* br) { |
319 | 35.4k | const size_t gx = dc_group_id % frame_dim_.xsize_dc_groups; |
320 | 35.4k | const size_t gy = dc_group_id / frame_dim_.xsize_dc_groups; |
321 | 35.4k | const LoopFilter& lf = frame_header_.loop_filter; |
322 | 35.4k | if (frame_header_.encoding == FrameEncoding::kVarDCT && |
323 | 6.21k | !(frame_header_.flags & FrameHeader::kUseDcFrame)) { |
324 | 6.19k | JXL_RETURN_IF_ERROR(modular_frame_decoder_.DecodeVarDCTDC( |
325 | 6.19k | frame_header_, dc_group_id, br, dec_state_)); |
326 | 6.19k | } |
327 | 34.9k | const Rect mrect(gx * frame_dim_.dc_group_dim, gy * frame_dim_.dc_group_dim, |
328 | 34.9k | frame_dim_.dc_group_dim, frame_dim_.dc_group_dim); |
329 | 34.9k | JXL_RETURN_IF_ERROR(modular_frame_decoder_.DecodeGroup( |
330 | 34.9k | frame_header_, mrect, br, 3, 1000, |
331 | 34.9k | ModularStreamId::ModularDC(dc_group_id), |
332 | 34.9k | /*zerofill=*/false, nullptr, nullptr, |
333 | 34.9k | /*allow_truncated=*/false)); |
334 | 34.9k | if (frame_header_.encoding == FrameEncoding::kVarDCT) { |
335 | 5.76k | JXL_RETURN_IF_ERROR(modular_frame_decoder_.DecodeAcMetadata( |
336 | 5.76k | frame_header_, dc_group_id, br, dec_state_)); |
337 | 29.2k | } else if (lf.epf_iters > 0) { |
338 | 12.0k | FillImage(kInvSigmaNum / lf.epf_sigma_for_modular, &dec_state_->sigma); |
339 | 12.0k | } |
340 | 34.5k | decoded_dc_groups_[dc_group_id] = JXL_TRUE; |
341 | 34.5k | return true; |
342 | 34.9k | } |
343 | | |
344 | 34.1k | Status FrameDecoder::FinalizeDC() { |
345 | | // Do Adaptive DC smoothing if enabled. This *must* happen between all the |
346 | | // ProcessDCGroup and ProcessACGroup. |
347 | 34.1k | JxlMemoryManager* memory_manager = dec_state_->memory_manager(); |
348 | 34.1k | if (frame_header_.encoding == FrameEncoding::kVarDCT && |
349 | 5.37k | !(frame_header_.flags & FrameHeader::kSkipAdaptiveDCSmoothing) && |
350 | 4.75k | !(frame_header_.flags & FrameHeader::kUseDcFrame)) { |
351 | 4.74k | JXL_RETURN_IF_ERROR(AdaptiveDCSmoothing( |
352 | 4.74k | memory_manager, dec_state_->shared->quantizer.MulDC(), |
353 | 4.74k | &dec_state_->shared_storage.dc_storage, pool_)); |
354 | 4.74k | } |
355 | | |
356 | 34.1k | finalized_dc_ = true; |
357 | 34.1k | return true; |
358 | 34.1k | } |
359 | | |
360 | 34.1k | Status FrameDecoder::AllocateOutput() { |
361 | 34.1k | if (allocated_) return true; |
362 | 34.1k | modular_frame_decoder_.MaybeDropFullImage(); |
363 | 34.1k | decoded_->origin = frame_header_.frame_origin; |
364 | 34.1k | JXL_RETURN_IF_ERROR( |
365 | 34.1k | dec_state_->InitForAC(frame_header_.passes.num_passes, nullptr)); |
366 | 34.1k | allocated_ = true; |
367 | 34.1k | return true; |
368 | 34.1k | } |
369 | | |
370 | 34.1k | Status FrameDecoder::ProcessACGlobal(BitReader* br) { |
371 | 34.1k | JXL_ENSURE(finalized_dc_); |
372 | 34.1k | JxlMemoryManager* memory_manager = dec_state_->memory_manager(); |
373 | | |
374 | | // Decode AC group. |
375 | 34.1k | if (frame_header_.encoding == FrameEncoding::kVarDCT) { |
376 | 5.36k | JXL_RETURN_IF_ERROR(dec_state_->shared_storage.matrices.Decode( |
377 | 5.36k | memory_manager, br, &modular_frame_decoder_)); |
378 | 5.17k | JXL_RETURN_IF_ERROR(dec_state_->shared_storage.matrices.EnsureComputed( |
379 | 5.17k | memory_manager, dec_state_->used_acs)); |
380 | | |
381 | 5.14k | size_t num_histo_bits = |
382 | 5.14k | CeilLog2Nonzero(dec_state_->shared->frame_dim.num_groups); |
383 | 5.14k | dec_state_->shared_storage.num_histograms = |
384 | 5.14k | 1 + br->ReadBits(num_histo_bits); |
385 | | |
386 | 5.14k | JXL_DEBUG_V(3, |
387 | 5.14k | "Processing AC global with %d passes and %" PRIuS |
388 | 5.14k | " sets of histograms", |
389 | 5.14k | frame_header_.passes.num_passes, |
390 | 5.14k | dec_state_->shared_storage.num_histograms); |
391 | | |
392 | 5.14k | dec_state_->code.resize(kMaxNumPasses); |
393 | 5.14k | dec_state_->context_map.resize(kMaxNumPasses); |
394 | | // Read coefficient orders and histograms. |
395 | 5.14k | size_t max_num_bits_ac = 0; |
396 | 10.4k | for (size_t i = 0; i < frame_header_.passes.num_passes; i++) { |
397 | 5.34k | uint16_t used_orders = U32Coder::Read(kOrderEnc, br); |
398 | 5.34k | JXL_RETURN_IF_ERROR(DecodeCoeffOrders( |
399 | 5.34k | memory_manager, used_orders, dec_state_->used_acs, |
400 | 5.34k | &dec_state_->shared_storage |
401 | 5.34k | .coeff_orders[i * dec_state_->shared_storage.coeff_order_size], |
402 | 5.34k | br)); |
403 | 5.30k | size_t num_contexts = |
404 | 5.30k | dec_state_->shared->num_histograms * |
405 | 5.30k | dec_state_->shared_storage.block_ctx_map.NumACContexts(); |
406 | 5.30k | JXL_RETURN_IF_ERROR(DecodeHistograms(memory_manager, br, num_contexts, |
407 | 5.30k | &dec_state_->code[i], |
408 | 5.30k | &dec_state_->context_map[i])); |
409 | | // Add extra values to enable the cheat in hot loop of DecodeACVarBlock. |
410 | 5.26k | dec_state_->context_map[i].resize( |
411 | 5.26k | num_contexts + kZeroDensityContextLimit - kZeroDensityContextCount); |
412 | 5.26k | max_num_bits_ac = |
413 | 5.26k | std::max(max_num_bits_ac, dec_state_->code[i].max_num_bits); |
414 | 5.26k | } |
415 | 5.06k | max_num_bits_ac += CeilLog2Nonzero(frame_header_.passes.num_passes); |
416 | | // 16-bit buffer for decoding to JPEG are not implemented. |
417 | | // TODO(veluca): figure out the exact limit - 16 should still work with |
418 | | // 16-bit buffers, but we are excluding it for safety. |
419 | 5.06k | bool use_16_bit = max_num_bits_ac < 16 && !decoded_->IsJPEG(); |
420 | 5.06k | bool store = frame_header_.passes.num_passes > 1; |
421 | 5.06k | size_t xs = store ? kGroupDim * kGroupDim : 0; |
422 | 5.06k | size_t ys = store ? frame_dim_.num_groups : 0; |
423 | 5.06k | if (use_16_bit) { |
424 | 4.26k | JXL_ASSIGN_OR_RETURN(dec_state_->coefficients, |
425 | 4.26k | ACImageT<int16_t>::Make(memory_manager, xs, ys)); |
426 | 4.26k | } else { |
427 | 807 | JXL_ASSIGN_OR_RETURN(dec_state_->coefficients, |
428 | 807 | ACImageT<int32_t>::Make(memory_manager, xs, ys)); |
429 | 807 | } |
430 | 5.06k | if (store) { |
431 | 36 | dec_state_->coefficients->ZeroFill(); |
432 | 36 | } |
433 | 5.06k | } |
434 | | |
435 | | // Set JPEG decoding data. |
436 | 33.8k | if (decoded_->IsJPEG()) { |
437 | 0 | decoded_->color_transform = frame_header_.color_transform; |
438 | 0 | decoded_->chroma_subsampling = frame_header_.chroma_subsampling; |
439 | 0 | const std::vector<QuantEncoding>& qe = |
440 | 0 | dec_state_->shared_storage.matrices.encodings(); |
441 | 0 | if (qe.empty() || qe[0].mode != QuantEncoding::Mode::kQuantModeRAW || |
442 | 0 | std::abs(qe[0].qraw.qtable_den - 1.f / (8 * 255)) > 1e-8f) { |
443 | 0 | return JXL_FAILURE( |
444 | 0 | "Quantization table is not a JPEG quantization table."); |
445 | 0 | } |
446 | 0 | jpeg::JPEGData* jpeg_data = decoded_->jpeg_data.get(); |
447 | 0 | size_t num_components = jpeg_data->components.size(); |
448 | 0 | bool is_gray = (num_components == 1); |
449 | 0 | JXL_ENSURE(frame_header_.color_transform != ColorTransform::kXYB); |
450 | 0 | auto jpeg_c_map = JpegOrder(frame_header_.color_transform, is_gray); |
451 | 0 | size_t qt_set = 0; |
452 | 0 | JXL_ENSURE(num_components <= 3); |
453 | 0 | JXL_ENSURE(qe[0].qraw.qtable->size() == 3 * 8 * 8); |
454 | 0 | int* qtable = qe[0].qraw.qtable->data(); |
455 | 0 | for (size_t c = 0; c < num_components; c++) { |
456 | | // TODO(eustas): why 1-st quant table for gray? |
457 | 0 | size_t quant_c = is_gray ? 1 : c; |
458 | 0 | size_t qpos = jpeg_data->components[jpeg_c_map[c]].quant_idx; |
459 | 0 | JXL_ENSURE(qpos != jpeg_data->quant.size()); |
460 | 0 | qt_set |= 1 << qpos; |
461 | 0 | for (size_t x = 0; x < 8; x++) { |
462 | 0 | for (size_t y = 0; y < 8; y++) { |
463 | 0 | jpeg_data->quant[qpos].values[x * 8 + y] = |
464 | 0 | qtable[quant_c * 64 + y * 8 + x]; |
465 | 0 | } |
466 | 0 | } |
467 | 0 | } |
468 | 0 | for (size_t i = 0; i < jpeg_data->quant.size(); i++) { |
469 | 0 | if (qt_set & (1 << i)) continue; |
470 | 0 | if (i == 0) return JXL_FAILURE("First quant table unused."); |
471 | | // Unused quant table is set to copy of previous quant table |
472 | 0 | for (size_t j = 0; j < 64; j++) { |
473 | 0 | jpeg_data->quant[i].values[j] = jpeg_data->quant[i - 1].values[j]; |
474 | 0 | } |
475 | 0 | } |
476 | 0 | } |
477 | 33.8k | decoded_ac_global_ = true; |
478 | 33.8k | return true; |
479 | 33.8k | } |
480 | | |
481 | | Status FrameDecoder::ProcessACGroup(size_t ac_group_id, PassesReaders& br, |
482 | | size_t num_passes, size_t thread, |
483 | 36.3k | bool force_draw, bool dc_only) { |
484 | 36.3k | size_t group_dim = frame_dim_.group_dim; |
485 | 36.3k | const size_t gx = ac_group_id % frame_dim_.xsize_groups; |
486 | 36.3k | const size_t gy = ac_group_id / frame_dim_.xsize_groups; |
487 | 36.3k | const size_t x = gx * group_dim; |
488 | 36.3k | const size_t y = gy * group_dim; |
489 | 36.3k | JxlMemoryManager* memory_manager = dec_state_->memory_manager(); |
490 | 36.3k | JXL_DEBUG_V(3, |
491 | 36.3k | "Processing AC group %" PRIuS "(%" PRIuS ",%" PRIuS |
492 | 36.3k | ") group_dim: %" PRIuS " decoded passes: %u new passes: %" PRIuS, |
493 | 36.3k | ac_group_id, gx, gy, group_dim, |
494 | 36.3k | decoded_passes_per_ac_group_[ac_group_id], num_passes); |
495 | | |
496 | 36.3k | RenderPipelineInput render_pipeline_input = |
497 | 36.3k | dec_state_->render_pipeline->GetInputBuffers(ac_group_id, thread); |
498 | | |
499 | 36.3k | bool should_run_pipeline = true; |
500 | | |
501 | 36.3k | if (frame_header_.encoding == FrameEncoding::kVarDCT) { |
502 | 5.46k | JXL_RETURN_IF_ERROR(group_dec_caches_[thread].InitOnce( |
503 | 5.46k | memory_manager, frame_header_.passes.num_passes, dec_state_->used_acs)); |
504 | 5.46k | JXL_RETURN_IF_ERROR(DecodeGroup( |
505 | 5.46k | frame_header_, br.data(), num_passes, ac_group_id, dec_state_, |
506 | 5.46k | &group_dec_caches_[thread], thread, render_pipeline_input, |
507 | 5.46k | decoded_->jpeg_data.get(), decoded_passes_per_ac_group_[ac_group_id], |
508 | 5.46k | force_draw, dc_only, &should_run_pipeline)); |
509 | 5.46k | } |
510 | | |
511 | | // don't limit to image dimensions here (is done in DecodeGroup) |
512 | 36.2k | const Rect mrect(x, y, group_dim, group_dim); |
513 | 36.2k | bool modular_ready = false; |
514 | 36.2k | size_t pass0 = decoded_passes_per_ac_group_[ac_group_id]; |
515 | 36.2k | size_t pass1 = |
516 | 36.2k | force_draw ? frame_header_.passes.num_passes : pass0 + num_passes; |
517 | 75.0k | for (size_t i = pass0; i < pass1; ++i) { |
518 | 38.9k | int minShift; |
519 | 38.9k | int maxShift; |
520 | 38.9k | frame_header_.passes.GetDownsamplingBracket(i, minShift, maxShift); |
521 | 38.9k | bool modular_pass_ready = true; |
522 | 38.9k | JXL_DEBUG_V(2, "Decoding modular in group %d pass %d", |
523 | 38.9k | static_cast<int>(ac_group_id), static_cast<int>(i)); |
524 | 38.9k | if (i < pass0 + num_passes) { // i.e. i - pass0 < num_passes |
525 | 38.9k | BitReader* r = br[i - pass0]; |
526 | 38.9k | JXL_ENSURE(r); |
527 | 38.9k | JXL_DEBUG_V(2, "Bit reader position: %" PRIuS " / %" PRIuS, |
528 | 38.9k | r->TotalBitsConsumed(), r->TotalBytes() * kBitsPerByte); |
529 | 38.9k | JXL_RETURN_IF_ERROR(modular_frame_decoder_.DecodeGroup( |
530 | 38.9k | frame_header_, mrect, r, minShift, maxShift, |
531 | 38.9k | ModularStreamId::ModularAC(ac_group_id, i), |
532 | 38.9k | /*zerofill=*/false, dec_state_, &render_pipeline_input, |
533 | 38.9k | /*allow_truncated=*/false, &modular_pass_ready)); |
534 | 38.9k | } else { |
535 | 0 | JXL_RETURN_IF_ERROR(modular_frame_decoder_.DecodeGroup( |
536 | 0 | frame_header_, mrect, nullptr, minShift, maxShift, |
537 | 0 | ModularStreamId::ModularAC(ac_group_id, i), /*zerofill=*/true, |
538 | 0 | dec_state_, &render_pipeline_input, |
539 | 0 | /*allow_truncated=*/false, &modular_pass_ready)); |
540 | 0 | } |
541 | 38.8k | if (modular_pass_ready) modular_ready = true; |
542 | 38.8k | } |
543 | 36.0k | decoded_passes_per_ac_group_[ac_group_id] += num_passes; |
544 | | |
545 | 36.0k | if ((frame_header_.flags & FrameHeader::kNoise) != 0) { |
546 | 6.94k | PrepareNoiseInput(*dec_state_, frame_dim_, frame_header_, ac_group_id, |
547 | 6.94k | thread); |
548 | 6.94k | } |
549 | | |
550 | 36.0k | if (!modular_frame_decoder_.UsesFullImage() && !decoded_->IsJPEG()) { |
551 | 6.32k | if (should_run_pipeline && modular_ready) { |
552 | 5.94k | JXL_RETURN_IF_ERROR(render_pipeline_input.Done()); |
553 | 5.94k | } else if (force_draw) { |
554 | 0 | return JXL_FAILURE("Modular group decoding failed."); |
555 | 0 | } |
556 | 6.32k | } |
557 | 36.0k | return true; |
558 | 36.0k | } |
559 | | |
560 | | void FrameDecoder::MarkSections(const SectionInfo* sections, size_t num, |
561 | 34.0k | const SectionStatus* section_status) { |
562 | 34.0k | num_sections_done_ += num; |
563 | 80.6k | for (size_t i = 0; i < num; i++) { |
564 | 46.6k | if (section_status[i] != SectionStatus::kDone) { |
565 | 992 | processed_section_[sections[i].id] = JXL_FALSE; |
566 | 992 | num_sections_done_--; |
567 | 992 | } |
568 | 46.6k | } |
569 | 34.0k | } |
570 | | |
571 | | Status FrameDecoder::ProcessSections(const SectionInfo* sections, size_t num, |
572 | 39.7k | SectionStatus* section_status) { |
573 | 39.7k | if (num == 0) return true; // Nothing to process |
574 | 37.6k | std::fill(section_status, section_status + num, SectionStatus::kSkipped); |
575 | 37.6k | size_t dc_global_sec = num; |
576 | 37.6k | size_t ac_global_sec = num; |
577 | 37.6k | std::vector<size_t> dc_group_sec(frame_dim_.num_dc_groups, num); |
578 | 37.6k | std::vector<std::vector<size_t>> ac_group_sec( |
579 | 37.6k | frame_dim_.num_groups, |
580 | 37.6k | std::vector<size_t>(frame_header_.passes.num_passes, num)); |
581 | | // This keeps track of the number of ac passes we want to process during this |
582 | | // call of ProcessSections. |
583 | 37.6k | std::vector<size_t> desired_num_ac_passes(frame_dim_.num_groups); |
584 | 37.6k | bool single_section = |
585 | 37.6k | frame_dim_.num_groups == 1 && frame_header_.passes.num_passes == 1; |
586 | 37.6k | if (single_section) { |
587 | 34.9k | JXL_ENSURE(num == 1); |
588 | 34.9k | JXL_ENSURE(sections[0].id == 0); |
589 | 34.9k | if (processed_section_[0] == JXL_FALSE) { |
590 | 34.9k | processed_section_[0] = JXL_TRUE; |
591 | 34.9k | ac_group_sec[0].resize(1); |
592 | 34.9k | dc_global_sec = ac_global_sec = dc_group_sec[0] = ac_group_sec[0][0] = 0; |
593 | 34.9k | desired_num_ac_passes[0] = 1; |
594 | 34.9k | } else { |
595 | 0 | section_status[0] = SectionStatus::kDuplicate; |
596 | 0 | } |
597 | 34.9k | } else { |
598 | 2.73k | size_t ac_global_index = frame_dim_.num_dc_groups + 1; |
599 | 22.3k | for (size_t i = 0; i < num; i++) { |
600 | 19.5k | JXL_ENSURE(sections[i].id < processed_section_.size()); |
601 | 19.5k | if (processed_section_[sections[i].id]) { |
602 | 0 | section_status[i] = SectionStatus::kDuplicate; |
603 | 0 | continue; |
604 | 0 | } |
605 | 19.5k | if (sections[i].id == 0) { |
606 | 2.65k | dc_global_sec = i; |
607 | 16.9k | } else if (sections[i].id < ac_global_index) { |
608 | 3.16k | dc_group_sec[sections[i].id - 1] = i; |
609 | 13.7k | } else if (sections[i].id == ac_global_index) { |
610 | 2.48k | ac_global_sec = i; |
611 | 11.2k | } else { |
612 | 11.2k | size_t ac_idx = sections[i].id - ac_global_index - 1; |
613 | 11.2k | size_t acg = ac_idx % frame_dim_.num_groups; |
614 | 11.2k | size_t acp = ac_idx / frame_dim_.num_groups; |
615 | 11.2k | if (acp >= frame_header_.passes.num_passes) { |
616 | 0 | return JXL_FAILURE("Invalid section ID"); |
617 | 0 | } |
618 | 11.2k | ac_group_sec[acg][acp] = i; |
619 | 11.2k | } |
620 | 19.5k | processed_section_[sections[i].id] = JXL_TRUE; |
621 | 19.5k | } |
622 | | // Count number of new passes per group. |
623 | 29.1k | for (size_t g = 0; g < ac_group_sec.size(); g++) { |
624 | 26.3k | size_t j = 0; |
625 | 37.5k | for (; j + decoded_passes_per_ac_group_[g] < |
626 | 37.5k | frame_header_.passes.num_passes; |
627 | 29.8k | j++) { |
628 | 29.8k | if (ac_group_sec[g][j + decoded_passes_per_ac_group_[g]] == num) { |
629 | 18.7k | break; |
630 | 18.7k | } |
631 | 29.8k | } |
632 | 26.3k | desired_num_ac_passes[g] = j; |
633 | 26.3k | } |
634 | 2.73k | } |
635 | 37.6k | if (dc_global_sec != num) { |
636 | 37.6k | Status dc_global_status = ProcessDCGlobal(sections[dc_global_sec].br); |
637 | 37.6k | if (dc_global_status.IsFatalError()) return dc_global_status; |
638 | 35.4k | if (dc_global_status) { |
639 | 35.0k | section_status[dc_global_sec] = SectionStatus::kDone; |
640 | 35.0k | } else { |
641 | 328 | section_status[dc_global_sec] = SectionStatus::kPartial; |
642 | 328 | } |
643 | 35.4k | } |
644 | | |
645 | 35.4k | if (decoded_dc_global_) { |
646 | 35.0k | const auto process_section = [this, &dc_group_sec, &num, §ions, |
647 | 35.0k | §ion_status](size_t i, |
648 | 35.8k | size_t thread) -> Status { |
649 | 35.8k | if (dc_group_sec[i] != num) { |
650 | 35.4k | JXL_RETURN_IF_ERROR(ProcessDCGroup(i, sections[dc_group_sec[i]].br)); |
651 | 34.5k | section_status[dc_group_sec[i]] = SectionStatus::kDone; |
652 | 34.5k | } |
653 | 35.0k | return true; |
654 | 35.8k | }; |
655 | 35.0k | JXL_RETURN_IF_ERROR(RunOnPool(pool_, 0, dc_group_sec.size(), |
656 | 35.0k | ThreadPool::NoInit, process_section, |
657 | 35.0k | "DecodeDCGroup")); |
658 | 35.0k | } |
659 | | |
660 | 34.6k | if (!HasDcGroupToDecode() && !finalized_dc_) { |
661 | 34.1k | PassesDecoderState::PipelineOptions pipeline_options; |
662 | 34.1k | pipeline_options.use_slow_render_pipeline = use_slow_rendering_pipeline_; |
663 | 34.1k | pipeline_options.coalescing = coalescing_; |
664 | 34.1k | pipeline_options.render_spotcolors = render_spotcolors_; |
665 | 34.1k | pipeline_options.render_noise = true; |
666 | 34.1k | JXL_RETURN_IF_ERROR(dec_state_->PreparePipeline( |
667 | 34.1k | frame_header_, &frame_header_.nonserialized_metadata->m, decoded_, |
668 | 34.1k | pipeline_options)); |
669 | 34.1k | JXL_RETURN_IF_ERROR(FinalizeDC()); |
670 | 34.1k | JXL_RETURN_IF_ERROR(AllocateOutput()); |
671 | 34.1k | if (progressive_detail_ >= JxlProgressiveDetail::kDC) { |
672 | 0 | MarkSections(sections, num, section_status); |
673 | 0 | return true; |
674 | 0 | } |
675 | 34.1k | } |
676 | | |
677 | 34.6k | if (finalized_dc_ && ac_global_sec != num && !decoded_ac_global_) { |
678 | 34.1k | JXL_RETURN_IF_ERROR(ProcessACGlobal(sections[ac_global_sec].br)); |
679 | 33.8k | section_status[ac_global_sec] = SectionStatus::kDone; |
680 | 33.8k | } |
681 | | |
682 | 34.3k | if (progressive_detail_ >= JxlProgressiveDetail::kLastPasses) { |
683 | | // Mark that we only want the next progression pass. |
684 | 0 | size_t target_complete_passes = NextNumPassesToPause(); |
685 | 0 | for (size_t i = 0; i < ac_group_sec.size(); i++) { |
686 | 0 | desired_num_ac_passes[i] = |
687 | 0 | std::min(desired_num_ac_passes[i], |
688 | 0 | target_complete_passes - decoded_passes_per_ac_group_[i]); |
689 | 0 | } |
690 | 0 | } |
691 | | |
692 | 34.3k | if (decoded_ac_global_) { |
693 | | // Mark all the AC groups that we received as not complete yet. |
694 | 73.7k | for (size_t i = 0; i < ac_group_sec.size(); i++) { |
695 | 39.9k | if (desired_num_ac_passes[i] != 0) { |
696 | 36.6k | dec_state_->render_pipeline->ClearDone(i); |
697 | 36.6k | } |
698 | 39.9k | } |
699 | | |
700 | 33.8k | const auto prepare_storage = [this](size_t num_threads) -> Status { |
701 | 33.8k | JXL_RETURN_IF_ERROR( |
702 | 33.8k | PrepareStorage(num_threads, decoded_passes_per_ac_group_.size())); |
703 | 33.8k | return true; |
704 | 33.8k | }; |
705 | 33.8k | const auto process_group = [this, &ac_group_sec, &desired_num_ac_passes, |
706 | 33.8k | &num, §ions, §ion_status]( |
707 | 37.9k | size_t g, size_t thread) -> Status { |
708 | 37.9k | if (desired_num_ac_passes[g] == 0) { |
709 | | // no new AC pass, nothing to do |
710 | 1.51k | return true; |
711 | 1.51k | } |
712 | 36.3k | size_t first_pass = decoded_passes_per_ac_group_[g]; |
713 | 36.3k | PassesReaders readers = {}; |
714 | 75.5k | for (size_t i = 0; i < desired_num_ac_passes[g]; i++) { |
715 | 39.1k | JXL_ENSURE(ac_group_sec[g][first_pass + i] != num); |
716 | 39.1k | readers[i] = sections[ac_group_sec[g][first_pass + i]].br; |
717 | 39.1k | } |
718 | 36.3k | JXL_RETURN_IF_ERROR(ProcessACGroup( |
719 | 36.3k | g, readers, desired_num_ac_passes[g], GetStorageLocation(thread, g), |
720 | 36.3k | /*force_draw=*/false, /*dc_only=*/false)); |
721 | 74.9k | for (size_t i = 0; i < desired_num_ac_passes[g]; i++) { |
722 | 38.8k | section_status[ac_group_sec[g][first_pass + i]] = SectionStatus::kDone; |
723 | 38.8k | } |
724 | 36.0k | return true; |
725 | 36.3k | }; |
726 | 33.8k | JXL_RETURN_IF_ERROR(RunOnPool(pool_, 0, ac_group_sec.size(), |
727 | 33.8k | prepare_storage, process_group, |
728 | 33.8k | "DecodeGroup")); |
729 | 33.8k | } |
730 | | |
731 | 34.0k | MarkSections(sections, num, section_status); |
732 | 34.0k | return true; |
733 | 34.3k | } |
734 | | |
735 | 0 | Status FrameDecoder::Flush() { |
736 | 0 | bool has_blending = frame_header_.blending_info.mode != BlendMode::kReplace || |
737 | 0 | frame_header_.custom_size_or_origin; |
738 | 0 | for (const auto& blending_info_ec : |
739 | 0 | frame_header_.extra_channel_blending_info) { |
740 | 0 | if (blending_info_ec.mode != BlendMode::kReplace) has_blending = true; |
741 | 0 | } |
742 | | // No early Flush() if blending is enabled. |
743 | 0 | if (has_blending && !is_finalized_) { |
744 | 0 | return false; |
745 | 0 | } |
746 | | // No early Flush() - nothing to do - if the frame is a kSkipProgressive |
747 | | // frame. |
748 | 0 | if (frame_header_.frame_type == FrameType::kSkipProgressive && |
749 | 0 | !is_finalized_) { |
750 | 0 | return true; |
751 | 0 | } |
752 | 0 | if (decoded_->IsJPEG()) { |
753 | | // Nothing to do. |
754 | 0 | return true; |
755 | 0 | } |
756 | 0 | JXL_RETURN_IF_ERROR(AllocateOutput()); |
757 | | |
758 | 0 | uint32_t completely_decoded_ac_pass = *std::min_element( |
759 | 0 | decoded_passes_per_ac_group_.begin(), decoded_passes_per_ac_group_.end()); |
760 | 0 | if (completely_decoded_ac_pass < frame_header_.passes.num_passes) { |
761 | | // We don't have all AC yet: force a draw of all the missing areas. |
762 | | // Mark all sections as not complete. |
763 | 0 | for (size_t i = 0; i < decoded_passes_per_ac_group_.size(); i++) { |
764 | 0 | if (decoded_passes_per_ac_group_[i] < frame_header_.passes.num_passes) { |
765 | 0 | dec_state_->render_pipeline->ClearDone(i); |
766 | 0 | } |
767 | 0 | } |
768 | 0 | const auto prepare_storage = [this](const size_t num_threads) -> Status { |
769 | 0 | JXL_RETURN_IF_ERROR( |
770 | 0 | PrepareStorage(num_threads, decoded_passes_per_ac_group_.size())); |
771 | 0 | return true; |
772 | 0 | }; |
773 | 0 | const auto process_group = [this](const uint32_t g, |
774 | 0 | size_t thread) -> Status { |
775 | 0 | if (decoded_passes_per_ac_group_[g] == frame_header_.passes.num_passes) { |
776 | | // This group was drawn already, nothing to do. |
777 | 0 | return true; |
778 | 0 | } |
779 | 0 | PassesReaders readers = {}; |
780 | 0 | JXL_RETURN_IF_ERROR(ProcessACGroup( |
781 | 0 | g, readers, /*num_passes=*/0, GetStorageLocation(thread, g), |
782 | 0 | /*force_draw=*/true, /*dc_only=*/!decoded_ac_global_)); |
783 | 0 | return true; |
784 | 0 | }; |
785 | 0 | JXL_RETURN_IF_ERROR(RunOnPool(pool_, 0, decoded_passes_per_ac_group_.size(), |
786 | 0 | prepare_storage, process_group, |
787 | 0 | "ForceDrawGroup")); |
788 | 0 | } |
789 | | |
790 | | // undo global modular transforms and copy int pixel buffers to float ones |
791 | 0 | JXL_RETURN_IF_ERROR(modular_frame_decoder_.FinalizeDecoding( |
792 | 0 | frame_header_, dec_state_, pool_, is_finalized_)); |
793 | | |
794 | 0 | return true; |
795 | 0 | } |
796 | | |
797 | 46.8k | int FrameDecoder::SavedAs(const FrameHeader& header) { |
798 | 46.8k | if (header.frame_type == FrameType::kDCFrame) { |
799 | | // bits 16, 32, 64, 128 for DC level |
800 | 13.8k | return 16 << (header.dc_level - 1); |
801 | 32.9k | } else if (header.CanBeReferenced()) { |
802 | | // bits 1, 2, 4 and 8 for the references |
803 | 26.3k | return 1 << header.save_as_reference; |
804 | 26.3k | } |
805 | | |
806 | 6.65k | return 0; |
807 | 46.8k | } |
808 | | |
809 | 32.2k | bool FrameDecoder::HasEverything() const { |
810 | 32.2k | if (!decoded_dc_global_) return false; |
811 | 32.2k | if (!decoded_ac_global_) return false; |
812 | 32.2k | if (HasDcGroupToDecode()) return false; |
813 | 33.9k | for (const auto& nb_passes : decoded_passes_per_ac_group_) { |
814 | 33.9k | if (nb_passes < frame_header_.passes.num_passes) return false; |
815 | 33.9k | } |
816 | 32.2k | return true; |
817 | 32.2k | } |
818 | | |
819 | 32.2k | int FrameDecoder::References() const { |
820 | 32.2k | if (is_finalized_) { |
821 | 0 | return 0; |
822 | 0 | } |
823 | 32.2k | if (!HasEverything()) return 0; |
824 | | |
825 | 32.2k | int result = 0; |
826 | | |
827 | | // Blending |
828 | 32.2k | if (frame_header_.frame_type == FrameType::kRegularFrame || |
829 | 18.2k | frame_header_.frame_type == FrameType::kSkipProgressive) { |
830 | 18.2k | bool cropped = frame_header_.custom_size_or_origin; |
831 | 18.2k | if (cropped || frame_header_.blending_info.mode != BlendMode::kReplace) { |
832 | 7.67k | result |= (1 << frame_header_.blending_info.source); |
833 | 7.67k | } |
834 | 18.2k | const auto& extra = frame_header_.extra_channel_blending_info; |
835 | 18.2k | for (const auto& ecbi : extra) { |
836 | 8.65k | if (cropped || ecbi.mode != BlendMode::kReplace) { |
837 | 4.21k | result |= (1 << ecbi.source); |
838 | 4.21k | } |
839 | 8.65k | } |
840 | 18.2k | } |
841 | | |
842 | | // Patches |
843 | 32.2k | if (frame_header_.flags & FrameHeader::kPatches) { |
844 | 834 | result |= dec_state_->shared->image_features.patches.GetReferences(); |
845 | 834 | } |
846 | | |
847 | | // DC Level |
848 | 32.2k | if (frame_header_.flags & FrameHeader::kUseDcFrame) { |
849 | | // Reads from the next dc level |
850 | 100 | int dc_level = frame_header_.dc_level + 1; |
851 | | // bits 16, 32, 64, 128 for DC level |
852 | 100 | result |= (16 << (dc_level - 1)); |
853 | 100 | } |
854 | | |
855 | 32.2k | return result; |
856 | 32.2k | } |
857 | | |
858 | 33.1k | Status FrameDecoder::FinalizeFrame() { |
859 | 33.1k | if (is_finalized_) { |
860 | 0 | return JXL_FAILURE("FinalizeFrame called multiple times"); |
861 | 0 | } |
862 | 33.1k | is_finalized_ = true; |
863 | 33.1k | if (decoded_->IsJPEG()) { |
864 | | // Nothing to do. |
865 | 0 | return true; |
866 | 0 | } |
867 | | |
868 | | // undo global modular transforms and copy int pixel buffers to float ones |
869 | 33.1k | JXL_RETURN_IF_ERROR( |
870 | 33.1k | modular_frame_decoder_.FinalizeDecoding(frame_header_, dec_state_, pool_, |
871 | 33.1k | /*inplace=*/true)); |
872 | | |
873 | 33.1k | if (frame_header_.CanBeReferenced()) { |
874 | 17.8k | auto& info = dec_state_->shared_storage |
875 | 17.8k | .reference_frames[frame_header_.save_as_reference]; |
876 | 17.8k | *info.frame = std::move(dec_state_->frame_storage_for_referencing); |
877 | 17.8k | info.ib_is_in_xyb = frame_header_.save_before_color_transform; |
878 | 17.8k | } |
879 | 33.1k | return true; |
880 | 33.1k | } |
881 | | |
882 | | } // namespace jxl |