/src/grok/src/lib/core/tile/TileProcessor.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2016-2025 Grok Image Compression Inc. |
3 | | * |
4 | | * This source code is free software: you can redistribute it and/or modify |
5 | | * it under the terms of the GNU Affero General Public License, version 3, |
6 | | * as published by the Free Software Foundation. |
7 | | * |
8 | | * This source code is distributed in the hope that it will be useful, |
9 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | | * GNU Affero General Public License for more details. |
12 | | * |
13 | | * You should have received a copy of the GNU Affero General Public License |
14 | | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
15 | | * |
16 | | * |
17 | | * This source code incorporates work covered by the BSD 2-clause license. |
18 | | * Please see the LICENSE file in the root directory for details. |
19 | | * |
20 | | */ |
21 | | #include "grk_includes.h" |
22 | | namespace grk |
23 | | { |
24 | | TileProcessor::TileProcessor(uint16_t tile_index, CodeStream* codeStream, BufferedStream* stream, |
25 | | bool isCompressor) |
26 | 10.0k | : first_poc_tile_part_(true), tilePartCounter_(0), pino(0), |
27 | 10.0k | headerImage(codeStream->getHeaderImage()), |
28 | 10.0k | current_plugin_tile(codeStream->getCurrentPluginTile()), cp_(codeStream->getCodingParams()), |
29 | 10.0k | packetLengthCache(PLCache()), tile(new Tile(headerImage->numcomps)), scheduler_(nullptr), |
30 | 10.0k | numProcessedPackets(0), numDecompressedPackets(0), tilePartDataLength(0), |
31 | 10.0k | tileIndex_(tile_index), stream_(stream), corrupt_packet_(false), |
32 | 10.0k | newTilePartProgressionPosition(cp_->coding_params_.enc_.newTilePartProgressionPosition), |
33 | 10.0k | tcp_(cp_->tcps + tileIndex_), truncated(false), image_(nullptr), isCompressor_(isCompressor), |
34 | 10.0k | preCalculatedTileLen(0), mct_(new mct(tile, headerImage, tcp_)) |
35 | 10.0k | {} |
36 | | TileProcessor::~TileProcessor() |
37 | 10.0k | { |
38 | 10.0k | release(GRK_TILE_CACHE_NONE); |
39 | 10.0k | delete scheduler_; |
40 | 10.0k | delete mct_; |
41 | 10.0k | } |
42 | | uint64_t TileProcessor::getTilePartDataLength(void) |
43 | 1.35k | { |
44 | 1.35k | return tilePartDataLength; |
45 | 1.35k | } |
46 | | bool TileProcessor::subtractMarkerSegmentLength(uint16_t markerLen) |
47 | 586 | { |
48 | 586 | if(tilePartDataLength == 0) |
49 | 0 | return true; |
50 | | |
51 | 586 | uint32_t segmentLength = (uint32_t)(markerLen + MARKER_LENGTH_BYTES); |
52 | 586 | if(tilePartDataLength > 0 && tilePartDataLength < segmentLength) |
53 | 0 | { |
54 | 0 | Logger::logger_.error("Tile part data length %u smaller than marker segment length %u", |
55 | 0 | tilePartDataLength, markerLen); |
56 | 0 | return false; |
57 | 0 | } |
58 | 586 | tilePartDataLength -= (uint64_t)segmentLength; |
59 | | |
60 | 586 | return true; |
61 | 586 | } |
62 | | bool TileProcessor::setTilePartDataLength(uint16_t tilePart, uint32_t tilePartLength, |
63 | | bool lastTilePartInCodeStream) |
64 | 12.1k | { |
65 | 12.1k | if(!lastTilePartInCodeStream) |
66 | 12.1k | { |
67 | 12.1k | if(tilePartLength < sot_marker_segment_len_minus_tile_data_len) |
68 | 0 | { |
69 | 0 | Logger::logger_.error( |
70 | 0 | "Tile part data length %u is smaller than for marker segment length %u", |
71 | 0 | tilePartDataLength, sot_marker_segment_len_minus_tile_data_len); |
72 | 0 | return false; |
73 | 0 | } |
74 | 12.1k | tilePartDataLength = tilePartLength - sot_marker_segment_len_minus_tile_data_len; |
75 | | // handle some edge cases |
76 | 12.1k | if(tilePartDataLength < 2) |
77 | 0 | { |
78 | 0 | if(tilePartDataLength == 1) |
79 | 0 | { |
80 | 0 | Logger::logger_.warn( |
81 | 0 | "Tile %u: tile part %u data length %u is smaller than minimum size of 2 - " |
82 | 0 | "room for single SOD marker. Ignoring.", |
83 | 0 | getIndex(), tilePart, tilePartDataLength); |
84 | 0 | tilePartDataLength = 0; |
85 | 0 | } |
86 | 0 | else |
87 | 0 | { |
88 | | // some non-compliant images do not add 2 bytes for SOD marker |
89 | | // for an empty tile part |
90 | 0 | tilePartDataLength = 2; |
91 | 0 | } |
92 | 0 | } |
93 | 12.1k | } |
94 | 0 | else |
95 | 0 | { |
96 | 0 | tilePartDataLength = stream_->numBytesLeft(); |
97 | 0 | } |
98 | | |
99 | 12.1k | return true; |
100 | 12.1k | } |
101 | | uint64_t TileProcessor::getNumProcessedPackets(void) |
102 | 1.23M | { |
103 | 1.23M | return numProcessedPackets; |
104 | 1.23M | } |
105 | | void TileProcessor::incNumProcessedPackets(void) |
106 | 1.24M | { |
107 | 1.24M | numProcessedPackets++; |
108 | 1.24M | } |
109 | | void TileProcessor::incNumProcessedPackets(uint64_t numPackets) |
110 | 0 | { |
111 | 0 | numProcessedPackets += numPackets; |
112 | 0 | } |
113 | | uint64_t TileProcessor::getNumDecompressedPackets(void) |
114 | 8.74k | { |
115 | 8.74k | return numDecompressedPackets; |
116 | 8.74k | } |
117 | | void TileProcessor::incNumDecompressedPackets(void) |
118 | 591k | { |
119 | 591k | numDecompressedPackets++; |
120 | 591k | } |
121 | | BufferedStream* TileProcessor::getStream(void) |
122 | 0 | { |
123 | 0 | return stream_; |
124 | 0 | } |
125 | | uint32_t TileProcessor::getPreCalculatedTileLen(void) |
126 | 0 | { |
127 | 0 | return preCalculatedTileLen; |
128 | 0 | } |
129 | | bool TileProcessor::canPreCalculateTileLen(void) |
130 | 0 | { |
131 | 0 | return !cp_->coding_params_.enc_.enableTilePartGeneration_ && |
132 | 0 | (cp_->tcps + tileIndex_)->getNumProgressions() == 1; |
133 | 0 | } |
134 | | uint16_t TileProcessor::getIndex(void) const |
135 | 564k | { |
136 | 564k | return tileIndex_; |
137 | 564k | } |
138 | | void TileProcessor::incrementIndex(void) |
139 | 0 | { |
140 | 0 | tileIndex_++; |
141 | 0 | } |
142 | | Tile* TileProcessor::getTile(void) |
143 | 3.47M | { |
144 | 3.47M | return tile; |
145 | 3.47M | } |
146 | | Scheduler* TileProcessor::getScheduler(void) |
147 | 27.2k | { |
148 | 27.2k | return scheduler_; |
149 | 27.2k | } |
150 | | bool TileProcessor::isCompressor(void) |
151 | 2.08M | { |
152 | 2.08M | return isCompressor_; |
153 | 2.08M | } |
154 | | void TileProcessor::generateImage(GrkImage* src_image, Tile* src_tile) |
155 | 8.64k | { |
156 | 8.64k | if(image_) |
157 | 0 | grk_object_unref(&image_->obj); |
158 | 8.64k | image_ = src_image->duplicate(src_tile); |
159 | 8.64k | } |
160 | | GrkImage* TileProcessor::getImage(void) |
161 | 17.6k | { |
162 | 17.6k | return image_; |
163 | 17.6k | } |
164 | | void TileProcessor::release(uint32_t strategy) |
165 | 18.7k | { |
166 | | // delete image in absence of tile cache strategy |
167 | 18.7k | if(strategy == GRK_TILE_CACHE_NONE) |
168 | 18.7k | { |
169 | 18.7k | if(image_) |
170 | 8.63k | grk_object_unref(&image_->obj); |
171 | 18.7k | image_ = nullptr; |
172 | 18.7k | } |
173 | | |
174 | | // delete tile components |
175 | 18.7k | delete tile; |
176 | 18.7k | tile = nullptr; |
177 | 18.7k | } |
178 | | PacketTracker* TileProcessor::getPacketTracker(void) |
179 | 0 | { |
180 | 0 | return &packetTracker_; |
181 | 0 | } |
182 | | TileCodingParams* TileProcessor::getTileCodingParams(void) |
183 | 3.87M | { |
184 | 3.87M | return cp_->tcps + tileIndex_; |
185 | 3.87M | } |
186 | | uint8_t TileProcessor::getMaxNumDecompressResolutions(void) |
187 | 15.5k | { |
188 | 15.5k | uint8_t rc = 0; |
189 | 15.5k | auto tcp = cp_->tcps + tileIndex_; |
190 | 63.5k | for(uint16_t compno = 0; compno < tile->numcomps_; ++compno) |
191 | 47.9k | { |
192 | 47.9k | auto tccp = tcp->tccps + compno; |
193 | 47.9k | auto numresolutions = tccp->numresolutions; |
194 | 47.9k | uint8_t resToDecomp; |
195 | 47.9k | if(numresolutions < cp_->coding_params_.dec_.reduce_) |
196 | 0 | resToDecomp = 1; |
197 | 47.9k | else |
198 | 47.9k | resToDecomp = (uint8_t)(numresolutions - cp_->coding_params_.dec_.reduce_); |
199 | 47.9k | rc = std::max<uint8_t>(rc, resToDecomp); |
200 | 47.9k | } |
201 | 15.5k | return rc; |
202 | 15.5k | } |
203 | | bool TileProcessor::init(void) |
204 | 9.21k | { |
205 | 9.21k | uint32_t state = grk_plugin_get_debug_state(); |
206 | 9.21k | auto tcp = &(cp_->tcps[tileIndex_]); |
207 | | |
208 | 9.21k | if(tcp->compressedTileData_) |
209 | 9.21k | tcp->compressedTileData_->rewind(); |
210 | | |
211 | | // generate tile bounds from tile grid coordinates |
212 | 9.21k | uint32_t tile_x = tileIndex_ % cp_->t_grid_width; |
213 | 9.21k | uint32_t tile_y = tileIndex_ / cp_->t_grid_width; |
214 | 9.21k | *((grk_rect32*)tile) = cp_->getTileBounds(headerImage, tile_x, tile_y); |
215 | | |
216 | 9.21k | if(tcp->tccps->numresolutions == 0) |
217 | 0 | { |
218 | 0 | Logger::logger_.error("tiles require at least one resolution"); |
219 | 0 | return false; |
220 | 0 | } |
221 | | |
222 | 37.7k | for(uint16_t compno = 0; compno < tile->numcomps_; ++compno) |
223 | 28.5k | { |
224 | 28.5k | auto imageComp = headerImage->comps + compno; |
225 | | /*fprintf(stderr, "compno = %u/%u\n", compno, tile->numcomps);*/ |
226 | 28.5k | if(imageComp->dx == 0 || imageComp->dy == 0) |
227 | 0 | return false; |
228 | 28.5k | auto tilec = tile->comps + compno; |
229 | 28.5k | grk_rect32 unreducedTileComp = grk_rect32( |
230 | 28.5k | ceildiv<uint32_t>(tile->x0, imageComp->dx), ceildiv<uint32_t>(tile->y0, imageComp->dy), |
231 | 28.5k | ceildiv<uint32_t>(tile->x1, imageComp->dx), ceildiv<uint32_t>(tile->y1, imageComp->dy)); |
232 | 28.5k | if(!tilec->init(this, unreducedTileComp, imageComp->prec, tcp->tccps + compno)) |
233 | 0 | { |
234 | 0 | return false; |
235 | 0 | } |
236 | 28.5k | } |
237 | | |
238 | | // decompressor plugin debug sanity check on tile struct |
239 | 9.21k | if(!isCompressor_) |
240 | 9.21k | { |
241 | 9.21k | if(state & GRK_PLUGIN_STATE_DEBUG) |
242 | 0 | { |
243 | 0 | if(!tile_equals(current_plugin_tile, tile)) |
244 | 0 | Logger::logger_.warn("plugin tile differs from grok tile", nullptr); |
245 | 0 | } |
246 | 9.21k | } |
247 | 9.21k | numProcessedPackets = 0; |
248 | | |
249 | 9.21k | if(isCompressor_) |
250 | 0 | { |
251 | 0 | uint64_t max_precincts = 0; |
252 | 0 | for(uint16_t compno = 0; compno < headerImage->numcomps; ++compno) |
253 | 0 | { |
254 | 0 | auto tilec = tile->comps + compno; |
255 | 0 | for(uint32_t resno = 0; resno < tilec->numresolutions; ++resno) |
256 | 0 | { |
257 | 0 | auto res = tilec->resolutions_ + resno; |
258 | 0 | max_precincts = (std::max<uint64_t>)(max_precincts, (uint64_t)res->precinctGridWidth * |
259 | 0 | res->precinctGridHeight); |
260 | 0 | } |
261 | 0 | } |
262 | 0 | packetTracker_.init(tile->numcomps_, tile->comps->numresolutions, max_precincts, |
263 | 0 | tcp->num_layers_); |
264 | 0 | } |
265 | | |
266 | 9.21k | return true; |
267 | 9.21k | } |
268 | | bool TileProcessor::createWindowBuffers(const GrkImage* outputImage) |
269 | 8.76k | { |
270 | 35.4k | for(uint16_t compno = 0; compno < tile->numcomps_; ++compno) |
271 | 26.7k | { |
272 | 26.7k | auto imageComp = headerImage->comps + compno; |
273 | 26.7k | if(imageComp->dx == 0 || imageComp->dy == 0) |
274 | 0 | return false; |
275 | 26.7k | auto tileComp = tile->comps + compno; |
276 | 26.7k | grk_rect32 unreducedImageCompWindow; |
277 | 26.7k | if(isCompressor_) |
278 | 0 | { |
279 | 0 | if(!tileComp->canCreateWindow(tileComp)) |
280 | 0 | return false; |
281 | 0 | unreducedImageCompWindow = tileComp; |
282 | 0 | } |
283 | 26.7k | else |
284 | 26.7k | { |
285 | 26.7k | unreducedImageWindow = |
286 | 26.7k | grk_rect32(outputImage->x0, outputImage->y0, outputImage->x1, outputImage->y1); |
287 | 26.7k | unreducedImageCompWindow = |
288 | 26.7k | unreducedImageWindow.scaleDownCeil(imageComp->dx, imageComp->dy); |
289 | 26.7k | if(!tileComp->canCreateWindow(unreducedImageCompWindow)) |
290 | 0 | return false; |
291 | 26.7k | } |
292 | 26.7k | tileComp->createWindow(unreducedImageCompWindow); |
293 | 26.7k | } |
294 | | |
295 | 8.76k | return true; |
296 | 8.76k | } |
297 | | |
298 | | grk_rect32 TileProcessor::getUnreducedTileWindow(void) |
299 | 610k | { |
300 | 610k | return unreducedImageWindow.clip(tile); |
301 | 610k | } |
302 | | |
303 | | void TileProcessor::deallocBuffers() |
304 | 8.73k | { |
305 | 36.1k | for(uint16_t compno = 0; compno < tile->numcomps_; ++compno) |
306 | 27.3k | { |
307 | 27.3k | auto tile_comp = tile->comps + compno; |
308 | 27.3k | tile_comp->dealloc(); |
309 | 27.3k | } |
310 | 8.73k | } |
311 | | bool TileProcessor::doCompress(void) |
312 | 0 | { |
313 | 0 | uint32_t state = grk_plugin_get_debug_state(); |
314 | | #ifdef PLUGIN_DEBUG_ENCODE |
315 | | if(state & GRK_PLUGIN_STATE_DEBUG) |
316 | | set_context_stream(this); |
317 | | #endif |
318 | |
|
319 | 0 | tcp_ = &cp_->tcps[tileIndex_]; |
320 | | |
321 | | // When debugging the compressor, we do all of T1 up to and including DWT |
322 | | // in the plugin, and pass this in as image data. |
323 | | // This way, both Grok and plugin start with same inputs for |
324 | | // context formation and MQ coding. |
325 | 0 | bool debugEncode = state & GRK_PLUGIN_STATE_DEBUG; |
326 | 0 | bool debugMCT = (state & GRK_PLUGIN_STATE_MCT_ONLY) ? true : false; |
327 | |
|
328 | 0 | if(!current_plugin_tile || debugEncode) |
329 | 0 | { |
330 | 0 | if(!debugEncode) |
331 | 0 | { |
332 | 0 | if(!dcLevelShiftCompress()) |
333 | 0 | return false; |
334 | 0 | if(!mct_encode()) |
335 | 0 | return false; |
336 | 0 | } |
337 | 0 | if(!debugEncode || debugMCT) |
338 | 0 | { |
339 | 0 | if(!dwt_encode()) |
340 | 0 | return false; |
341 | 0 | } |
342 | 0 | t1_encode(); |
343 | 0 | } |
344 | | // 1. create PLT marker if required |
345 | 0 | packetLengthCache.deleteMarkers(); |
346 | 0 | if(cp_->coding_params_.enc_.write_plt) |
347 | 0 | packetLengthCache.createMarkers(stream_); |
348 | | // 2. rate control |
349 | 0 | uint32_t allPacketBytes = 0; |
350 | 0 | bool rc = rateAllocate(&allPacketBytes, false); |
351 | 0 | if(!rc) |
352 | 0 | { |
353 | 0 | Logger::logger_.warn("Unable to perform rate control on tile %d", tileIndex_); |
354 | 0 | Logger::logger_.warn("Rate control will be disabled for this tile"); |
355 | 0 | allPacketBytes = 0; |
356 | 0 | rc = rateAllocate(&allPacketBytes, true); |
357 | 0 | if(!rc) |
358 | 0 | { |
359 | 0 | Logger::logger_.error("Unable to perform rate control on tile %d", tileIndex_); |
360 | 0 | return false; |
361 | 0 | } |
362 | 0 | } |
363 | 0 | packetTracker_.clear(); |
364 | |
|
365 | 0 | if(canPreCalculateTileLen()) |
366 | 0 | { |
367 | | // SOT marker |
368 | 0 | preCalculatedTileLen = sot_marker_segment_len_minus_tile_data_len; |
369 | | // POC marker |
370 | 0 | if(canWritePocMarker()) |
371 | 0 | { |
372 | 0 | uint32_t pocSize = |
373 | 0 | CodeStreamCompress::getPocSize(tile->numcomps_, tcp_->getNumProgressions()); |
374 | 0 | preCalculatedTileLen += pocSize; |
375 | 0 | } |
376 | | // calculate PLT marker length |
377 | 0 | if(packetLengthCache.getMarkers()) |
378 | 0 | preCalculatedTileLen += packetLengthCache.getMarkers()->getTotalBytesWritten(); |
379 | | |
380 | | // calculate SOD marker length |
381 | 0 | preCalculatedTileLen += 2; |
382 | | // calculate packets length |
383 | 0 | preCalculatedTileLen += allPacketBytes; |
384 | 0 | } |
385 | 0 | return true; |
386 | 0 | } |
387 | | bool TileProcessor::canWritePocMarker(void) |
388 | 0 | { |
389 | 0 | bool firstTilePart = (tilePartCounter_ == 0); |
390 | | |
391 | | // note: DCP standard does not allow POC marker |
392 | 0 | return cp_->tcps[tileIndex_].hasPoc() && firstTilePart && !GRK_IS_CINEMA(cp_->rsiz); |
393 | 0 | } |
394 | | bool TileProcessor::writeTilePartT2(uint32_t* tileBytesWritten) |
395 | 0 | { |
396 | | // write entire PLT marker in first tile part header |
397 | 0 | if(tilePartCounter_ == 0 && packetLengthCache.getMarkers()) |
398 | 0 | { |
399 | 0 | if(!packetLengthCache.getMarkers()->write()) |
400 | 0 | return false; |
401 | 0 | *tileBytesWritten += packetLengthCache.getMarkers()->getTotalBytesWritten(); |
402 | 0 | } |
403 | | |
404 | | // write SOD |
405 | 0 | if(!stream_->writeShort(J2K_SOD)) |
406 | 0 | return false; |
407 | 0 | *tileBytesWritten += 2; |
408 | | |
409 | | // write tile packets |
410 | 0 | return encodeT2(tileBytesWritten); |
411 | 0 | } |
412 | | /** Returns whether a tile component should be fully decompressed, |
413 | | * taking into account win_* members. |
414 | | * |
415 | | * @param compno Component number |
416 | | * @return true if the tile component should be fully decompressed |
417 | | */ |
418 | | bool TileProcessor::isWholeTileDecompress(uint16_t compno) |
419 | 22.6k | { |
420 | 22.6k | auto tilec = tile->comps + compno; |
421 | | /* Compute the intersection of the area of interest, expressed in tile component coordinates, */ |
422 | | /* with the tile bounds */ |
423 | 22.6k | auto dims = tilec->getWindow()->bounds().intersection(tilec); |
424 | | |
425 | 22.6k | uint32_t shift = (uint32_t)(tilec->numresolutions - tilec->numResolutionsToDecompress); |
426 | | /* Tolerate small margin within the reduced resolution factor to consider if */ |
427 | | /* the whole tile path must be taken */ |
428 | 22.6k | return (dims.valid() && |
429 | 22.6k | (shift >= 32 || |
430 | 22.6k | (((dims.x0 - tilec->x0) >> shift) == 0 && ((dims.y0 - tilec->y0) >> shift) == 0 && |
431 | 22.6k | ((tilec->x1 - dims.x1) >> shift) == 0 && ((tilec->y1 - dims.y1) >> shift) == 0))); |
432 | 22.6k | } |
433 | | |
434 | | bool TileProcessor::decompressT2T1(GrkImage* outputImage) |
435 | 8.76k | { |
436 | 8.76k | auto tcp = getTileCodingParams(); |
437 | 8.76k | if(!tcp->compressedTileData_) |
438 | 0 | { |
439 | 0 | Logger::logger_.error("Decompress: Tile %u has no compressed data", getIndex()); |
440 | 0 | return false; |
441 | 0 | } |
442 | 8.76k | bool doT1 = !current_plugin_tile || (current_plugin_tile->decompress_flags & GRK_DECODE_T1); |
443 | 8.76k | bool doPostT1 = |
444 | 8.76k | !current_plugin_tile || (current_plugin_tile->decompress_flags & GRK_DECODE_POST_T1); |
445 | | |
446 | | // create window buffers |
447 | | // (no buffer allocation) |
448 | 8.76k | if(!createWindowBuffers(outputImage)) |
449 | 0 | return false; |
450 | | |
451 | | // T2 |
452 | | // optimization for regions that are close to largest decompressed resolution |
453 | 29.6k | for(uint16_t compno = 0; compno < headerImage->numcomps; compno++) |
454 | 22.6k | { |
455 | 22.6k | if(!isWholeTileDecompress(compno)) |
456 | 1.75k | { |
457 | 1.75k | cp_->wholeTileDecompress_ = false; |
458 | 1.75k | break; |
459 | 1.75k | } |
460 | 22.6k | } |
461 | 8.76k | bool doT2 = !current_plugin_tile || (current_plugin_tile->decompress_flags & GRK_DECODE_T2); |
462 | 8.76k | if(doT2) |
463 | 8.65k | { |
464 | 8.65k | auto t2 = std::make_unique<T2Decompress>(this); |
465 | 8.65k | t2->decompressPackets(tileIndex_, tcp->compressedTileData_, &truncated); |
466 | | // synch plugin with T2 data |
467 | | // todo re-enable decompress synch |
468 | | // decompress_synch_plugin_with_host(this); |
469 | | |
470 | | // 1. count parsers |
471 | 8.65k | auto tile = getTile(); |
472 | 8.65k | uint64_t parserCount = 0; |
473 | 36.0k | for(uint16_t compno = 0; compno < headerImage->numcomps; ++compno) |
474 | 27.3k | { |
475 | 27.3k | auto tilec = tile->comps + compno; |
476 | 199k | for(uint8_t resno = 0; resno < tilec->numResolutionsToDecompress; ++resno) |
477 | 171k | { |
478 | 171k | auto res = tilec->resolutions_ + resno; |
479 | 171k | parserCount += res->parserMap_->precinctParsers_.size(); |
480 | 171k | } |
481 | 27.3k | } |
482 | | // 2.create and populate tasks, and execute |
483 | 8.65k | if(parserCount) |
484 | 0 | { |
485 | 0 | auto num_workers = std::min<size_t>(ExecSingleton::get().num_workers(), parserCount); |
486 | 0 | if(num_workers == 1) |
487 | 0 | { |
488 | 0 | for(uint16_t compno = 0; compno < headerImage->numcomps; ++compno) |
489 | 0 | { |
490 | 0 | auto tilec = tile->comps + compno; |
491 | 0 | for(uint8_t resno = 0; resno < tilec->numResolutionsToDecompress; ++resno) |
492 | 0 | { |
493 | 0 | auto res = tilec->resolutions_ + resno; |
494 | 0 | for(const auto& pp : res->parserMap_->precinctParsers_) |
495 | 0 | { |
496 | 0 | for(uint64_t j = 0; j < pp.second->numParsers_; ++j) |
497 | 0 | { |
498 | 0 | try |
499 | 0 | { |
500 | 0 | auto parser = pp.second->parsers_[j]; |
501 | 0 | parser->readHeader(); |
502 | 0 | parser->readData(); |
503 | 0 | } |
504 | 0 | catch([[maybe_unused]] const std::exception& ex) |
505 | 0 | { |
506 | 0 | break; |
507 | 0 | } |
508 | 0 | } |
509 | 0 | } |
510 | 0 | } |
511 | 0 | } |
512 | 0 | } |
513 | 0 | else |
514 | 0 | { |
515 | 0 | tf::Taskflow taskflow; |
516 | 0 | auto numTasks = parserCount; |
517 | 0 | auto tasks = new tf::Task[numTasks]; |
518 | 0 | for(uint64_t i = 0; i < numTasks; i++) |
519 | 0 | tasks[i] = taskflow.placeholder(); |
520 | 0 | uint64_t i = 0; |
521 | 0 | for(uint16_t compno = 0; compno < headerImage->numcomps; ++compno) |
522 | 0 | { |
523 | 0 | auto tilec = tile->comps + compno; |
524 | 0 | for(uint8_t resno = 0; resno < tilec->numResolutionsToDecompress; ++resno) |
525 | 0 | { |
526 | 0 | auto res = tilec->resolutions_ + resno; |
527 | 0 | for(const auto& pp : res->parserMap_->precinctParsers_) |
528 | 0 | { |
529 | 0 | const auto& ppair = pp; |
530 | 0 | auto decompressor = [ppair]() { |
531 | 0 | for(uint64_t j = 0; j < ppair.second->numParsers_; ++j) |
532 | 0 | { |
533 | 0 | try |
534 | 0 | { |
535 | 0 | auto parser = ppair.second->parsers_[j]; |
536 | 0 | parser->readHeader(); |
537 | 0 | parser->readData(); |
538 | 0 | } |
539 | 0 | catch([[maybe_unused]] const std::exception& ex) |
540 | 0 | { |
541 | 0 | break; |
542 | 0 | } |
543 | 0 | } |
544 | 0 | }; |
545 | 0 | tasks[i++].work(decompressor); |
546 | 0 | } |
547 | 0 | } |
548 | 0 | } |
549 | 0 | ExecSingleton::get().run(taskflow).wait(); |
550 | 0 | delete[] tasks; |
551 | 0 | } |
552 | 0 | } |
553 | 8.65k | } |
554 | | // T1 |
555 | 8.76k | if(doT1) |
556 | 8.76k | { |
557 | 8.76k | scheduler_ = new DecompressScheduler(this, tile, tcp_, headerImage->comps->prec); |
558 | 8.76k | FlowComponent* mctPostProc = nullptr; |
559 | | // schedule MCT post processing |
560 | 8.76k | if(doPostT1 && needsMctDecompress()) |
561 | 4.51k | mctPostProc = scheduler_->getPrePostProc(); |
562 | 8.76k | uint16_t mctComponentCount = 0; |
563 | | |
564 | 35.9k | for(uint16_t compno = 0; compno < tile->numcomps_; ++compno) |
565 | 27.3k | { |
566 | 27.3k | auto tilec = tile->comps + compno; |
567 | 27.3k | if(!cp_->wholeTileDecompress_) |
568 | 27.2k | { |
569 | 27.2k | try |
570 | 27.2k | { |
571 | 27.2k | tilec->allocRegionWindow(tilec->highestResolutionDecompressed + 1U, truncated); |
572 | 27.2k | } |
573 | 27.2k | catch([[maybe_unused]] const std::runtime_error& ex) |
574 | 27.2k | { |
575 | 0 | continue; |
576 | 0 | } |
577 | 27.2k | catch([[maybe_unused]] const std::bad_alloc& baex) |
578 | 27.2k | { |
579 | 0 | std::string msg = std::string("Memory allocation failed: ") + baex.what(); |
580 | 0 | Logger::logger_.error("%s", msg.c_str()); |
581 | 0 | return false; |
582 | 0 | } |
583 | 27.2k | } |
584 | 27.2k | if(!tilec->getWindow()->alloc()) |
585 | 0 | { |
586 | 0 | Logger::logger_.error("Not enough memory for tile data"); |
587 | 0 | return false; |
588 | 0 | } |
589 | 27.2k | if(!scheduler_->schedule(compno)) |
590 | 0 | return false; |
591 | | |
592 | | // post processing |
593 | 27.2k | auto compFlow = scheduler_->getImageComponentFlow(compno); |
594 | 27.2k | if(compFlow) |
595 | 11.6k | { |
596 | 11.6k | if(mctPostProc && compno < 3) |
597 | 7.41k | { |
598 | | // link to MCT |
599 | 7.41k | compFlow->getFinalFlowT1()->precede(mctPostProc); |
600 | 7.41k | mctComponentCount++; |
601 | 7.41k | } |
602 | 4.20k | else if(doPostT1) |
603 | 4.20k | { |
604 | | // use with either custom MCT, or no MCT |
605 | 4.20k | if(!needsMctDecompress(compno) || tcp_->mct == 2) |
606 | 4.20k | { |
607 | 4.20k | auto dcPostProc = compFlow->getPrePostProc(scheduler_->getCodecFlow()); |
608 | 4.20k | compFlow->getFinalFlowT1()->precede(dcPostProc); |
609 | 4.20k | if((tcp_->tccps + compno)->qmfbid == 1) |
610 | 2.21k | mct_->decompress_dc_shift_rev(dcPostProc, compno); |
611 | 1.98k | else |
612 | 1.98k | mct_->decompress_dc_shift_irrev(dcPostProc, compno); |
613 | 4.20k | } |
614 | 4.20k | } |
615 | 11.6k | } |
616 | 27.2k | } |
617 | | // sanity check on MCT scheduling |
618 | 8.73k | if(doPostT1 && mctComponentCount == 3 && mctPostProc && !mctDecompress(mctPostProc)) |
619 | 0 | return false; |
620 | 8.67k | if(!scheduler_->run()) |
621 | 16 | return false; |
622 | 8.66k | delete scheduler_; |
623 | 8.66k | scheduler_ = nullptr; |
624 | 8.66k | } |
625 | | // 4. post T1 |
626 | 8.66k | bool doPost = |
627 | 8.66k | !current_plugin_tile || (current_plugin_tile->decompress_flags & GRK_DECODE_POST_T1); |
628 | 8.66k | if(doPost) |
629 | 8.73k | { |
630 | 8.73k | if(outputImage->has_multiple_tiles) |
631 | 8.64k | generateImage(outputImage, tile); |
632 | 94 | else |
633 | 94 | outputImage->transferDataFrom(tile); |
634 | 8.73k | deallocBuffers(); |
635 | 8.73k | } |
636 | 8.74k | if(doT1 && getNumDecompressedPackets() == 0) |
637 | 4.66k | { |
638 | 4.66k | Logger::logger_.warn("Tile %u was not decompressed", tileIndex_); |
639 | 4.66k | if(!outputImage->has_multiple_tiles) |
640 | 0 | return false; |
641 | 4.66k | } |
642 | 8.66k | return true; |
643 | 8.66k | } |
644 | | |
645 | | void TileProcessor::ingestImage() |
646 | 0 | { |
647 | 0 | for(uint16_t i = 0; i < headerImage->numcomps; ++i) |
648 | 0 | { |
649 | 0 | auto tilec = tile->comps + i; |
650 | 0 | auto img_comp = headerImage->comps + i; |
651 | |
|
652 | 0 | uint32_t offset_x = ceildiv<uint32_t>(headerImage->x0, img_comp->dx); |
653 | 0 | uint32_t offset_y = ceildiv<uint32_t>(headerImage->y0, img_comp->dy); |
654 | 0 | uint64_t image_offset = |
655 | 0 | (tilec->x0 - offset_x) + (uint64_t)(tilec->y0 - offset_y) * img_comp->stride; |
656 | 0 | auto src = img_comp->data + image_offset; |
657 | 0 | auto dest = tilec->getWindow()->getResWindowBufferHighestSimple(); |
658 | |
|
659 | 0 | for(uint32_t j = 0; j < tilec->height(); ++j) |
660 | 0 | { |
661 | 0 | memcpy(dest.buf_, src, tilec->width() * sizeof(int32_t)); |
662 | 0 | src += img_comp->stride; |
663 | 0 | dest.buf_ += dest.stride_; |
664 | 0 | } |
665 | 0 | } |
666 | 0 | } |
667 | | bool TileProcessor::needsMctDecompress(void) |
668 | 12.9k | { |
669 | 12.9k | if(!tcp_->mct) |
670 | 3.84k | return false; |
671 | 9.09k | if(tile->numcomps_ < 3) |
672 | 12 | { |
673 | 12 | Logger::logger_.warn("Number of components (%u) is less than 3 - skipping MCT.", |
674 | 12 | tile->numcomps_); |
675 | 12 | return false; |
676 | 12 | } |
677 | 9.08k | if(!headerImage->componentsEqual(3, false)) |
678 | 4.51k | { |
679 | 4.51k | Logger::logger_.warn("Not all tiles components have the same dimensions - skipping MCT."); |
680 | 4.51k | return false; |
681 | 4.51k | } |
682 | 4.56k | if(tcp_->mct == 2 && !tcp_->mct_decoding_matrix_) |
683 | 0 | return false; |
684 | | |
685 | 4.56k | return true; |
686 | 4.56k | } |
687 | | bool TileProcessor::needsMctDecompress(uint16_t compno) |
688 | 4.20k | { |
689 | 4.20k | if(!needsMctDecompress()) |
690 | 4.15k | return false; |
691 | | |
692 | 52 | return (compno <= 2); |
693 | 4.20k | } |
694 | | bool TileProcessor::mctDecompress(FlowComponent* flow) |
695 | 2.17k | { |
696 | | // custom MCT |
697 | 2.17k | if(tcp_->mct == 2) |
698 | 0 | { |
699 | 0 | auto data = new uint8_t*[tile->numcomps_]; |
700 | 0 | for(uint16_t i = 0; i < tile->numcomps_; ++i) |
701 | 0 | { |
702 | 0 | auto tile_comp = tile->comps + i; |
703 | 0 | data[i] = (uint8_t*)tile_comp->getWindow()->getResWindowBufferHighestSimple().buf_; |
704 | 0 | } |
705 | 0 | uint64_t samples = tile->comps->getWindow()->stridedArea(); |
706 | 0 | bool rc = mct::decompress_custom((uint8_t*)tcp_->mct_decoding_matrix_, samples, data, |
707 | 0 | tile->numcomps_, headerImage->comps->sgnd); |
708 | 0 | return rc; |
709 | 0 | } |
710 | 2.17k | else |
711 | 2.17k | { |
712 | 2.17k | if(tcp_->tccps->qmfbid == 1) |
713 | 242 | mct_->decompress_rev(flow); |
714 | 1.93k | else |
715 | 1.93k | mct_->decompress_irrev(flow); |
716 | 2.17k | } |
717 | | |
718 | 2.17k | return true; |
719 | 2.17k | } |
720 | | bool TileProcessor::dcLevelShiftCompress() |
721 | 0 | { |
722 | 0 | for(uint16_t compno = 0; compno < tile->numcomps_; compno++) |
723 | 0 | { |
724 | 0 | auto tile_comp = tile->comps + compno; |
725 | 0 | auto tccp = tcp_->tccps + compno; |
726 | 0 | auto current_ptr = tile_comp->getWindow()->getResWindowBufferHighestSimple().buf_; |
727 | 0 | uint64_t samples = tile_comp->getWindow()->stridedArea(); |
728 | 0 | #ifndef GRK_FORCE_SIGNED_COMPRESS |
729 | 0 | if(needsMctDecompress(compno)) |
730 | 0 | continue; |
731 | | #else |
732 | | tccp->dc_level_shift_ = 1 << ((this->headerImage->comps + compno)->prec - 1); |
733 | | #endif |
734 | | |
735 | 0 | if(tccp->qmfbid == 1) |
736 | 0 | { |
737 | 0 | if(tccp->dc_level_shift_ == 0) |
738 | 0 | continue; |
739 | 0 | for(uint64_t i = 0; i < samples; ++i) |
740 | 0 | { |
741 | 0 | *current_ptr -= tccp->dc_level_shift_; |
742 | 0 | ++current_ptr; |
743 | 0 | } |
744 | 0 | } |
745 | 0 | else |
746 | 0 | { |
747 | | // output float |
748 | | |
749 | | // Note: we need to convert to FP even if level shift is zero |
750 | | // todo: skip this inefficiency for zero level shift |
751 | |
|
752 | 0 | float* floatPtr = (float*)current_ptr; |
753 | 0 | for(uint64_t i = 0; i < samples; ++i) |
754 | 0 | *floatPtr++ = (float)(*current_ptr++ - tccp->dc_level_shift_); |
755 | 0 | } |
756 | | #ifdef GRK_FORCE_SIGNED_COMPRESS |
757 | | tccp->dc_level_shift_ = 0; |
758 | | #endif |
759 | 0 | } |
760 | |
|
761 | 0 | return true; |
762 | 0 | } |
763 | | bool TileProcessor::mct_encode() |
764 | 0 | { |
765 | 0 | if(!tcp_->mct) |
766 | 0 | return true; |
767 | 0 | if(tcp_->mct == 2) |
768 | 0 | { |
769 | 0 | if(!tcp_->mct_coding_matrix_) |
770 | 0 | return true; |
771 | 0 | auto data = new uint8_t*[tile->numcomps_]; |
772 | 0 | for(uint32_t i = 0; i < tile->numcomps_; ++i) |
773 | 0 | { |
774 | 0 | auto tile_comp = tile->comps + i; |
775 | 0 | data[i] = (uint8_t*)tile_comp->getWindow()->getResWindowBufferHighestSimple().buf_; |
776 | 0 | } |
777 | 0 | uint64_t samples = tile->comps->getWindow()->stridedArea(); |
778 | 0 | bool rc = mct::compress_custom((uint8_t*)tcp_->mct_coding_matrix_, samples, data, |
779 | 0 | tile->numcomps_, headerImage->comps->sgnd); |
780 | 0 | delete[] data; |
781 | 0 | return rc; |
782 | 0 | } |
783 | 0 | else if(tcp_->tccps->qmfbid == 0) |
784 | 0 | mct_->compress_irrev(nullptr); |
785 | 0 | else |
786 | 0 | mct_->compress_rev(nullptr); |
787 | | |
788 | 0 | return true; |
789 | 0 | } |
790 | | bool TileProcessor::dwt_encode() |
791 | 0 | { |
792 | 0 | bool rc = true; |
793 | 0 | for(uint16_t compno = 0; compno < tile->numcomps_; ++compno) |
794 | 0 | { |
795 | 0 | auto tile_comp = tile->comps + compno; |
796 | 0 | auto tccp = tcp_->tccps + compno; |
797 | 0 | WaveletFwdImpl w; |
798 | 0 | if(!w.compress(tile_comp, tccp->qmfbid)) |
799 | 0 | { |
800 | 0 | rc = false; |
801 | 0 | continue; |
802 | 0 | } |
803 | 0 | } |
804 | 0 | return rc; |
805 | 0 | } |
806 | | void TileProcessor::t1_encode() |
807 | 0 | { |
808 | 0 | const double* mct_norms; |
809 | 0 | uint16_t mct_numcomps = 0U; |
810 | 0 | auto tcp = tcp_; |
811 | |
|
812 | 0 | if(tcp->mct == 1) |
813 | 0 | { |
814 | 0 | mct_numcomps = 3U; |
815 | | /* irreversible compressing */ |
816 | 0 | if(tcp->tccps->qmfbid == 0) |
817 | 0 | mct_norms = mct::get_norms_irrev(); |
818 | 0 | else |
819 | 0 | mct_norms = mct::get_norms_rev(); |
820 | 0 | } |
821 | 0 | else |
822 | 0 | { |
823 | 0 | mct_numcomps = headerImage->numcomps; |
824 | 0 | mct_norms = (const double*)(tcp->mct_norms); |
825 | 0 | } |
826 | |
|
827 | 0 | scheduler_ = new CompressScheduler(tile, needsRateControl(), tcp, mct_norms, mct_numcomps); |
828 | 0 | scheduler_->schedule(0); |
829 | 0 | } |
830 | | bool TileProcessor::encodeT2(uint32_t* tileBytesWritten) |
831 | 0 | { |
832 | 0 | auto l_t2 = new T2Compress(this); |
833 | | #ifdef DEBUG_LOSSLESS_T2 |
834 | | for(uint16_t compno = 0; compno < p_image->numcomps_; ++compno) |
835 | | { |
836 | | TileComponent* tilec = &tilePtr->comps[compno]; |
837 | | tilec->round_trip_resolutions = new Resolution[tilec->numresolutions]; |
838 | | for(uint32_t resno = 0; resno < tilec->numresolutions; ++resno) |
839 | | { |
840 | | auto res = tilec->resolutions_ + resno; |
841 | | auto roundRes = tilec->round_trip_resolutions + resno; |
842 | | roundRes->x0 = res->x0; |
843 | | roundRes->y0 = res->y0; |
844 | | roundRes->x1 = res->x1; |
845 | | roundRes->y1 = res->y1; |
846 | | roundRes->numTileBandWindows = res->numTileBandWindows; |
847 | | for(uint32_t bandIndex = 0; bandIndex < roundRes->numTileBandWindows; ++bandIndex) |
848 | | { |
849 | | roundRes->tileBand[bandIndex] = res->tileBand[bandIndex]; |
850 | | roundRes->tileBand[bandIndex].x0 = res->tileBand[bandIndex].x0; |
851 | | roundRes->tileBand[bandIndex].y0 = res->tileBand[bandIndex].y0; |
852 | | roundRes->tileBand[bandIndex].x1 = res->tileBand[bandIndex].x1; |
853 | | roundRes->tileBand[bandIndex].y1 = res->tileBand[bandIndex].y1; |
854 | | } |
855 | | |
856 | | // allocate |
857 | | for(uint32_t bandIndex = 0; bandIndex < roundRes->numTileBandWindows; ++bandIndex) |
858 | | { |
859 | | auto tileBand = res->tileBand + bandIndex; |
860 | | auto decodeBand = roundRes->tileBand + bandIndex; |
861 | | if(!tileBand->num_precincts) |
862 | | continue; |
863 | | decodeBand->precincts = new Precinct[tileBand->num_precincts]; |
864 | | decodeBand->precincts_data_size = |
865 | | (uint32_t)(tileBand->num_precincts * sizeof(Precinct)); |
866 | | for(uint64_t precinctIndex = 0; precinctIndex < tileBand->num_precincts; |
867 | | ++precinctIndex) |
868 | | { |
869 | | auto prec = tileBand->precincts + precinctIndex; |
870 | | auto decodePrec = decodeBand->precincts + precinctIndex; |
871 | | decodePrec->cblk_grid_width = prec->cblk_grid_width; |
872 | | decodePrec->cblk_grid_height = prec->cblk_grid_height; |
873 | | if(prec->getCompressedBlockPtr() && prec->cblk_grid_width && prec->cblk_grid_height) |
874 | | { |
875 | | decodePrec->initTagTrees(); |
876 | | decodePrec->getDecompressedBlockPtr() = |
877 | | new DecompressCodeblock[(uint64_t)decodePrec->cblk_grid_width * |
878 | | decodePrec->cblk_grid_height]; |
879 | | for(uint64_t cblkno = 0; |
880 | | cblkno < decodePrec->cblk_grid_width * decodePrec->cblk_grid_height; ++cblkno) |
881 | | { |
882 | | auto cblk = prec->getCompressedBlockPtr() + cblkno; |
883 | | auto decodeCblk = decodePrec->getDecompressedBlockPtr() + cblkno; |
884 | | decodeCblk->x0 = cblk->x0; |
885 | | decodeCblk->y0 = cblk->y0; |
886 | | decodeCblk->x1 = cblk->x1; |
887 | | decodeCblk->y1 = cblk->y1; |
888 | | decodeCblk->alloc(); |
889 | | } |
890 | | } |
891 | | } |
892 | | } |
893 | | } |
894 | | } |
895 | | #endif |
896 | 0 | if(!l_t2->compressPackets(tileIndex_, tcp_->num_layers_, stream_, tileBytesWritten, |
897 | 0 | first_poc_tile_part_, newTilePartProgressionPosition, pino)) |
898 | 0 | { |
899 | 0 | delete l_t2; |
900 | 0 | return false; |
901 | 0 | } |
902 | 0 | delete l_t2; |
903 | | #ifdef DEBUG_LOSSLESS_T2 |
904 | | for(uint16_t compno = 0; compno < p_image->numcomps_; ++compno) |
905 | | { |
906 | | TileComponent* tilec = &tilePtr->comps[compno]; |
907 | | for(uint32_t resno = 0; resno < tilec->numresolutions; ++resno) |
908 | | { |
909 | | auto roundRes = tilec->round_trip_resolutions + resno; |
910 | | for(uint32_t bandIndex = 0; bandIndex < roundRes->numTileBandWindows; ++bandIndex) |
911 | | { |
912 | | auto decodeBand = roundRes->tileBand + bandIndex; |
913 | | if(decodeBand->precincts) |
914 | | { |
915 | | for(uint64_t precinctIndex = 0; precinctIndex < decodeBand->num_precincts; |
916 | | ++precinctIndex) |
917 | | { |
918 | | auto decodePrec = decodeBand->precincts + precinctIndex; |
919 | | decodePrec->cleanupDecodeBlocks(); |
920 | | } |
921 | | delete[] decodeBand->precincts; |
922 | | decodeBand->precincts = nullptr; |
923 | | } |
924 | | } |
925 | | } |
926 | | delete[] tilec->round_trip_resolutions; |
927 | | } |
928 | | #endif |
929 | |
|
930 | 0 | return true; |
931 | 0 | } |
932 | | bool TileProcessor::preCompressTile() |
933 | 0 | { |
934 | 0 | tilePartCounter_ = 0; |
935 | 0 | first_poc_tile_part_ = true; |
936 | | |
937 | | /* initialization before tile compressing */ |
938 | 0 | bool rc = init(); |
939 | 0 | if(!rc) |
940 | 0 | return false; |
941 | | // don't need to allocate any buffers if this is from the plugin. |
942 | 0 | if(current_plugin_tile) |
943 | 0 | return true; |
944 | 0 | rc = createWindowBuffers(nullptr); |
945 | 0 | if(!rc) |
946 | 0 | return false; |
947 | 0 | uint32_t numTiles = (uint32_t)cp_->t_grid_height * cp_->t_grid_width; |
948 | 0 | bool transfer_image_to_tile = (numTiles == 1); |
949 | | /* if we only have one tile, then simply set tile component data equal to |
950 | | * image component data. Otherwise, allocate tile data and copy */ |
951 | 0 | for(uint32_t j = 0; j < headerImage->numcomps; ++j) |
952 | 0 | { |
953 | 0 | auto tilec = tile->comps + j; |
954 | 0 | auto imagec = headerImage->comps + j; |
955 | 0 | if(transfer_image_to_tile && imagec->data) |
956 | 0 | tilec->getWindow()->attach(imagec->data, imagec->stride); |
957 | 0 | else if(!tilec->getWindow()->alloc()) |
958 | 0 | { |
959 | 0 | Logger::logger_.error("Error allocating tile component data."); |
960 | 0 | return false; |
961 | 0 | } |
962 | 0 | } |
963 | 0 | if(!transfer_image_to_tile) |
964 | 0 | ingestImage(); |
965 | |
|
966 | 0 | return true; |
967 | 0 | } |
968 | | /** |
969 | | * Assume that source stride == source width == destination width |
970 | | */ |
971 | | template<typename T> |
972 | | void grk_copy_strided(uint32_t w, uint32_t stride, uint32_t h, T* src, int32_t* dest) |
973 | 0 | { |
974 | 0 | assert(stride >= w); |
975 | 0 | uint32_t stride_diff = stride - w; |
976 | 0 | size_t src_ind = 0, dest_ind = 0; |
977 | 0 | for(uint32_t j = 0; j < h; ++j) |
978 | 0 | { |
979 | 0 | for(uint32_t i = 0; i < w; ++i) |
980 | 0 | dest[dest_ind++] = src[src_ind++]; |
981 | 0 | dest_ind += stride_diff; |
982 | 0 | } |
983 | 0 | } Unexecuted instantiation: void grk::grk_copy_strided<signed char>(unsigned int, unsigned int, unsigned int, signed char*, int*) Unexecuted instantiation: void grk::grk_copy_strided<unsigned char>(unsigned int, unsigned int, unsigned int, unsigned char*, int*) Unexecuted instantiation: void grk::grk_copy_strided<short>(unsigned int, unsigned int, unsigned int, short*, int*) Unexecuted instantiation: void grk::grk_copy_strided<unsigned short>(unsigned int, unsigned int, unsigned int, unsigned short*, int*) |
984 | | bool TileProcessor::ingestUncompressedData(uint8_t* p_src, uint64_t src_length) |
985 | 0 | { |
986 | 0 | uint64_t tile_size = 0; |
987 | 0 | for(uint32_t i = 0; i < headerImage->numcomps; ++i) |
988 | 0 | { |
989 | 0 | auto tilec = tile->comps + i; |
990 | 0 | auto img_comp = headerImage->comps + i; |
991 | 0 | uint32_t size_comp = (uint32_t)((img_comp->prec + 7) >> 3); |
992 | 0 | tile_size += size_comp * tilec->area(); |
993 | 0 | } |
994 | 0 | if(!p_src || (tile_size != src_length)) |
995 | 0 | return false; |
996 | 0 | size_t length_per_component = src_length / headerImage->numcomps; |
997 | 0 | for(uint32_t i = 0; i < headerImage->numcomps; ++i) |
998 | 0 | { |
999 | 0 | auto tilec = tile->comps + i; |
1000 | 0 | auto img_comp = headerImage->comps + i; |
1001 | 0 | uint32_t size_comp = (uint32_t)((img_comp->prec + 7) >> 3); |
1002 | 0 | auto b = tilec->getWindow()->getResWindowBufferHighestSimple(); |
1003 | 0 | auto dest_ptr = b.buf_; |
1004 | 0 | uint32_t w = (uint32_t)tilec->getWindow()->bounds().width(); |
1005 | 0 | uint32_t h = (uint32_t)tilec->getWindow()->bounds().height(); |
1006 | 0 | uint32_t stride = b.stride_; |
1007 | 0 | switch(size_comp) |
1008 | 0 | { |
1009 | 0 | case 1: |
1010 | 0 | if(img_comp->sgnd) |
1011 | 0 | { |
1012 | 0 | auto src = (int8_t*)p_src; |
1013 | 0 | grk_copy_strided<int8_t>(w, stride, h, src, dest_ptr); |
1014 | 0 | p_src = (uint8_t*)(src + length_per_component); |
1015 | 0 | } |
1016 | 0 | else |
1017 | 0 | { |
1018 | 0 | auto src = (uint8_t*)p_src; |
1019 | 0 | grk_copy_strided<uint8_t>(w, stride, h, src, dest_ptr); |
1020 | 0 | p_src = (uint8_t*)(src + length_per_component); |
1021 | 0 | } |
1022 | 0 | break; |
1023 | 0 | case 2: |
1024 | 0 | if(img_comp->sgnd) |
1025 | 0 | { |
1026 | 0 | auto src = (int16_t*)p_src; |
1027 | 0 | grk_copy_strided<int16_t>(w, stride, h, (int16_t*)p_src, dest_ptr); |
1028 | 0 | p_src = (uint8_t*)(src + length_per_component); |
1029 | 0 | } |
1030 | 0 | else |
1031 | 0 | { |
1032 | 0 | auto src = (uint16_t*)p_src; |
1033 | 0 | grk_copy_strided<uint16_t>(w, stride, h, (uint16_t*)p_src, dest_ptr); |
1034 | 0 | p_src = (uint8_t*)(src + length_per_component); |
1035 | 0 | } |
1036 | 0 | break; |
1037 | 0 | } |
1038 | 0 | } |
1039 | | |
1040 | 0 | return true; |
1041 | 0 | } |
1042 | | bool TileProcessor::cacheTilePartPackets(CodeStreamDecompress* codeStream) |
1043 | 10.8k | { |
1044 | 10.8k | assert(codeStream); |
1045 | | |
1046 | | // note: we subtract MARKER_BYTES to account for SOD marker |
1047 | 10.8k | auto tcp = codeStream->get_current_decode_tcp(); |
1048 | 10.8k | if(tilePartDataLength >= MARKER_BYTES) |
1049 | 10.8k | tilePartDataLength -= MARKER_BYTES; |
1050 | 0 | else |
1051 | | // illegal tile part data length, but we will allow it |
1052 | 0 | tilePartDataLength = 0; |
1053 | | |
1054 | 10.8k | if(tilePartDataLength) |
1055 | 10.8k | { |
1056 | 10.8k | auto bytesLeftInStream = stream_->numBytesLeft(); |
1057 | 10.8k | if(bytesLeftInStream == 0) |
1058 | 0 | { |
1059 | 0 | Logger::logger_.error("Tile %u, tile part %u: stream has been truncated and " |
1060 | 0 | "there is no tile data available", |
1061 | 0 | tileIndex_, tcp->tilePartCounter_ - 1); |
1062 | 0 | return false; |
1063 | 0 | } |
1064 | | // check that there are enough bytes in stream to fill tile data |
1065 | 10.8k | if(tilePartDataLength > bytesLeftInStream) |
1066 | 204 | { |
1067 | 204 | Logger::logger_.warn("Tile part length %lld greater than " |
1068 | 204 | "stream length %lld\n" |
1069 | 204 | "(tile: %u, tile part: %u). Tile has been truncated.", |
1070 | 204 | tilePartDataLength, stream_->numBytesLeft(), tileIndex_, |
1071 | 204 | tcp->tilePartCounter_ - 1); |
1072 | | |
1073 | | // sanitize tilePartDataLength |
1074 | 204 | tilePartDataLength = (uint64_t)bytesLeftInStream; |
1075 | 204 | truncated = true; |
1076 | 204 | } |
1077 | 10.8k | } |
1078 | | /* Index */ |
1079 | 10.8k | auto codeStreamInfo = codeStream->getCodeStreamInfo(); |
1080 | 10.8k | if(codeStreamInfo) |
1081 | 10.8k | { |
1082 | 10.8k | uint64_t current_pos = stream_->tell(); |
1083 | 10.8k | if(current_pos < MARKER_BYTES) |
1084 | 0 | { |
1085 | 0 | Logger::logger_.error("Stream too short"); |
1086 | |
|
1087 | 0 | return false; |
1088 | 0 | } |
1089 | 10.8k | current_pos = (uint64_t)(current_pos - MARKER_BYTES); |
1090 | 10.8k | auto tileInfo = codeStreamInfo->getTileInfo(tileIndex_); |
1091 | 10.8k | uint8_t current_tile_part = tileInfo->currentTilePart; |
1092 | 10.8k | auto tilePartInfo = tileInfo->getTilePartInfo(current_tile_part); |
1093 | 10.8k | tilePartInfo->endHeaderPosition = current_pos; |
1094 | 10.8k | tilePartInfo->endPosition = current_pos + tilePartDataLength + MARKER_BYTES; |
1095 | 10.8k | if(!TileLengthMarkers::addTileMarkerInfo(tileIndex_, codeStreamInfo, J2K_SOD, current_pos, 0)) |
1096 | 0 | { |
1097 | 0 | Logger::logger_.error("Not enough memory to add tl marker"); |
1098 | |
|
1099 | 0 | return false; |
1100 | 0 | } |
1101 | 10.8k | } |
1102 | 10.8k | size_t current_read_size = 0; |
1103 | 10.8k | if(tilePartDataLength) |
1104 | 10.8k | { |
1105 | 10.8k | if(!tcp->compressedTileData_) |
1106 | 9.25k | tcp->compressedTileData_ = new SparseBuffer(); |
1107 | 10.8k | auto len = tilePartDataLength; |
1108 | 10.8k | uint8_t* buff = nullptr; |
1109 | 10.8k | auto zeroCopy = stream_->supportsZeroCopy(); |
1110 | 10.8k | if(zeroCopy) |
1111 | 10.8k | { |
1112 | 10.8k | buff = stream_->getZeroCopyPtr(); |
1113 | 10.8k | } |
1114 | 0 | else |
1115 | 0 | { |
1116 | 0 | try |
1117 | 0 | { |
1118 | 0 | buff = new uint8_t[len]; |
1119 | 0 | } |
1120 | 0 | catch([[maybe_unused]] const std::bad_alloc& ex) |
1121 | 0 | { |
1122 | 0 | Logger::logger_.error("Not enough memory to allocate segment"); |
1123 | |
|
1124 | 0 | return false; |
1125 | 0 | } |
1126 | 0 | } |
1127 | 10.8k | current_read_size = stream_->read(zeroCopy ? nullptr : buff, len); |
1128 | 10.8k | tcp->compressedTileData_->pushBack(buff, len, !zeroCopy); |
1129 | 10.8k | } |
1130 | 10.8k | if(current_read_size != tilePartDataLength) |
1131 | 0 | codeStream->getDecompressorState()->setState(DECOMPRESS_STATE_NO_EOC); |
1132 | 10.8k | else |
1133 | 10.8k | codeStream->getDecompressorState()->setState(DECOMPRESS_STATE_TPH_SOT); |
1134 | | |
1135 | 10.8k | return true; |
1136 | 10.8k | } |
1137 | | // RATE CONTROL //////////////////////////////////////////// |
1138 | | bool TileProcessor::rateAllocate(uint32_t* allPacketBytes, bool disableRateControl) |
1139 | 0 | { |
1140 | 0 | return pcrdBisectSimple(allPacketBytes, disableRateControl); |
1141 | 0 | } |
1142 | | bool TileProcessor::layerNeedsRateControl(uint32_t layno) |
1143 | 0 | { |
1144 | 0 | auto enc_params = &cp_->coding_params_.enc_; |
1145 | 0 | return (enc_params->allocationByRateDistortion_ && (tcp_->rates[layno] > 0.0)) || |
1146 | 0 | (enc_params->allocationByFixedQuality_ && (tcp_->distortion[layno] > 0.0f)); |
1147 | 0 | } |
1148 | | bool TileProcessor::needsRateControl() |
1149 | 0 | { |
1150 | 0 | for(uint16_t i = 0; i < tcp_->num_layers_; ++i) |
1151 | 0 | { |
1152 | 0 | if(layerNeedsRateControl(i)) |
1153 | 0 | return true; |
1154 | 0 | } |
1155 | 0 | return false; |
1156 | 0 | } |
1157 | | // lossless in the sense that no code passes are removed; it mays still be a lossless layer |
1158 | | // due to irreversible DWT and quantization |
1159 | | bool TileProcessor::makeSingleLosslessLayer() |
1160 | 0 | { |
1161 | 0 | if(tcp_->num_layers_ == 1 && !layerNeedsRateControl(0)) |
1162 | 0 | { |
1163 | 0 | makeLayerFinal(0); |
1164 | |
|
1165 | 0 | return true; |
1166 | 0 | } |
1167 | | |
1168 | 0 | return false; |
1169 | 0 | } |
1170 | | /* |
1171 | | Simple bisect algorithm to calculate optimal layer truncation points |
1172 | | */ |
1173 | | bool TileProcessor::pcrdBisectSimple(uint32_t* allPacketBytes, bool disableRateControl) |
1174 | 0 | { |
1175 | 0 | uint32_t passno; |
1176 | 0 | const double K = 1; |
1177 | 0 | double maxSE = 0; |
1178 | 0 | double min_slope = DBL_MAX; |
1179 | 0 | double max_slope = -1; |
1180 | 0 | uint32_t state = grk_plugin_get_debug_state(); |
1181 | 0 | bool single_lossless = makeSingleLosslessLayer(); |
1182 | 0 | uint64_t numPacketsPerLayer = 0; |
1183 | 0 | uint64_t numCodeBlocks = 0; |
1184 | 0 | auto tcp = tcp_; |
1185 | 0 | for(uint16_t compno = 0; compno < tile->numcomps_; compno++) |
1186 | 0 | { |
1187 | 0 | auto tilec = &tile->comps[compno]; |
1188 | 0 | uint64_t numpix = 0; |
1189 | 0 | for(uint8_t resno = 0; resno < tilec->numresolutions; resno++) |
1190 | 0 | { |
1191 | 0 | auto res = &tilec->resolutions_[resno]; |
1192 | 0 | for(uint8_t bandIndex = 0; bandIndex < res->numTileBandWindows; bandIndex++) |
1193 | 0 | { |
1194 | 0 | auto band = &res->tileBand[bandIndex]; |
1195 | 0 | for(auto prc : band->precincts) |
1196 | 0 | { |
1197 | 0 | numPacketsPerLayer++; |
1198 | 0 | for(uint64_t cblkno = 0; cblkno < prc->getNumCblks(); cblkno++) |
1199 | 0 | { |
1200 | 0 | auto cblk = prc->getCompressedBlockPtr(cblkno); |
1201 | 0 | uint32_t num_pix = (uint32_t)cblk->area(); |
1202 | 0 | numCodeBlocks++; |
1203 | 0 | if(!(state & GRK_PLUGIN_STATE_PRE_TR1)) |
1204 | 0 | { |
1205 | 0 | compress_synch_with_plugin(this, compno, resno, bandIndex, prc->precinctIndex, |
1206 | 0 | cblkno, band, cblk, &num_pix); |
1207 | 0 | } |
1208 | 0 | if(!single_lossless) |
1209 | 0 | { |
1210 | 0 | for(passno = 0; passno < cblk->numPassesTotal; passno++) |
1211 | 0 | { |
1212 | 0 | auto pass = cblk->passes + passno; |
1213 | 0 | int32_t dr; |
1214 | 0 | double dd, rdslope; |
1215 | 0 | if(passno == 0) |
1216 | 0 | { |
1217 | 0 | dr = (int32_t)pass->rate; |
1218 | 0 | dd = pass->distortiondec; |
1219 | 0 | } |
1220 | 0 | else |
1221 | 0 | { |
1222 | 0 | dr = (int32_t)(pass->rate - cblk->passes[passno - 1].rate); |
1223 | 0 | dd = pass->distortiondec - cblk->passes[passno - 1].distortiondec; |
1224 | 0 | } |
1225 | 0 | if(dr == 0) |
1226 | 0 | continue; |
1227 | 0 | rdslope = dd / dr; |
1228 | 0 | if(rdslope < min_slope) |
1229 | 0 | min_slope = rdslope; |
1230 | 0 | if(rdslope > max_slope) |
1231 | 0 | max_slope = rdslope; |
1232 | 0 | } /* passno */ |
1233 | 0 | numpix += num_pix; |
1234 | 0 | } |
1235 | 0 | } /* cbklno */ |
1236 | 0 | } /* precinctIndex */ |
1237 | 0 | } /* bandIndex */ |
1238 | 0 | } /* resno */ |
1239 | 0 | if(!single_lossless) |
1240 | 0 | maxSE += (double)(((uint64_t)1 << headerImage->comps[compno].prec) - 1) * |
1241 | 0 | (double)(((uint64_t)1 << headerImage->comps[compno].prec) - 1) * (double)numpix; |
1242 | |
|
1243 | 0 | } /* compno */ |
1244 | |
|
1245 | 0 | auto t2 = T2Compress(this); |
1246 | 0 | if(single_lossless) |
1247 | 0 | { |
1248 | | // simulation will generate correct PLT lengths |
1249 | | // and correct tile length |
1250 | 0 | return t2.compressPacketsSimulate(tileIndex_, 0 + 1U, allPacketBytes, UINT_MAX, |
1251 | 0 | newTilePartProgressionPosition, |
1252 | 0 | packetLengthCache.getMarkers(), true, false); |
1253 | 0 | } |
1254 | 0 | double cumulativeDistortion[maxCompressLayersGRK]; |
1255 | 0 | double upperBound = max_slope; |
1256 | 0 | uint32_t maxLayerLength = UINT_MAX; |
1257 | 0 | for(uint16_t layno = 0; layno < tcp_->num_layers_; layno++) |
1258 | 0 | { |
1259 | 0 | maxLayerLength = (!disableRateControl && tcp->rates[layno] > 0.0f) |
1260 | 0 | ? ((uint32_t)ceil(tcp->rates[layno])) |
1261 | 0 | : UINT_MAX; |
1262 | 0 | if(layerNeedsRateControl(layno)) |
1263 | 0 | { |
1264 | 0 | double lowerBound = min_slope; |
1265 | | /* Threshold for Marcela Index */ |
1266 | | // start by including everything in this layer |
1267 | 0 | double goodthresh = 0; |
1268 | | // thresh from previous iteration - starts off uninitialized |
1269 | | // used to bail out if difference with current thresh is small enough |
1270 | 0 | double prevthresh = -1; |
1271 | 0 | double distortionTarget = |
1272 | 0 | tile->distortion - ((K * maxSE) / pow(10.0, tcp_->distortion[layno] / 10.0)); |
1273 | 0 | double thresh; |
1274 | 0 | for(uint32_t i = 0; i < 128; ++i) |
1275 | 0 | { |
1276 | | // thresh is half-way between lower and upper bound |
1277 | 0 | thresh = (upperBound == -1) ? lowerBound : (lowerBound + upperBound) / 2; |
1278 | 0 | makeLayerSimple(layno, thresh, false); |
1279 | 0 | if(prevthresh != -1 && (fabs(prevthresh - thresh)) < 0.001) |
1280 | 0 | break; |
1281 | 0 | prevthresh = thresh; |
1282 | 0 | if(cp_->coding_params_.enc_.allocationByFixedQuality_) |
1283 | 0 | { |
1284 | 0 | double distoachieved = |
1285 | 0 | layno == 0 ? tile->layerDistoration[0] |
1286 | 0 | : cumulativeDistortion[layno - 1] + tile->layerDistoration[layno]; |
1287 | 0 | if(distoachieved < distortionTarget) |
1288 | 0 | { |
1289 | 0 | upperBound = thresh; |
1290 | 0 | continue; |
1291 | 0 | } |
1292 | 0 | lowerBound = thresh; |
1293 | 0 | } |
1294 | 0 | else |
1295 | 0 | { |
1296 | 0 | if(!t2.compressPacketsSimulate(tileIndex_, layno + 1U, allPacketBytes, |
1297 | 0 | maxLayerLength, newTilePartProgressionPosition, |
1298 | 0 | packetLengthCache.getMarkers(), false, false)) |
1299 | 0 | { |
1300 | 0 | lowerBound = thresh; |
1301 | 0 | continue; |
1302 | 0 | } |
1303 | 0 | upperBound = thresh; |
1304 | 0 | } |
1305 | 0 | } |
1306 | | // choose conservative value for goodthresh |
1307 | 0 | goodthresh = (upperBound == -1) ? thresh : upperBound; |
1308 | 0 | makeLayerSimple(layno, goodthresh, true); |
1309 | 0 | cumulativeDistortion[layno] = |
1310 | 0 | (layno == 0) ? tile->layerDistoration[0] |
1311 | 0 | : (cumulativeDistortion[layno - 1] + tile->layerDistoration[layno]); |
1312 | | |
1313 | | // upper bound for next layer will equal lowerBound for previous layer, minus one |
1314 | 0 | upperBound = lowerBound - 1; |
1315 | 0 | } |
1316 | 0 | else |
1317 | 0 | { |
1318 | 0 | makeLayerFinal(layno); |
1319 | 0 | assert(layno == tcp_->num_layers_ - 1); |
1320 | 0 | } |
1321 | 0 | } |
1322 | | |
1323 | | // final simulation will generate correct PLT lengths |
1324 | | // and correct tile length |
1325 | | // Logger::logger_.info("Rate control final simulation"); |
1326 | 0 | return t2.compressPacketsSimulate(tileIndex_, tcp_->num_layers_, allPacketBytes, maxLayerLength, |
1327 | 0 | newTilePartProgressionPosition, packetLengthCache.getMarkers(), |
1328 | 0 | true, false); |
1329 | 0 | } |
1330 | | static void prepareBlockForFirstLayer(CompressCodeblock* cblk) |
1331 | 0 | { |
1332 | 0 | cblk->numPassesInPreviousPackets = 0; |
1333 | 0 | cblk->setNumPassesInPacket(0, 0); |
1334 | 0 | cblk->numlenbits = 0; |
1335 | 0 | } |
1336 | | /* |
1337 | | Form layer for bisect rate control algorithm |
1338 | | */ |
1339 | | void TileProcessor::makeLayerSimple(uint32_t layno, double thresh, bool finalAttempt) |
1340 | 0 | { |
1341 | 0 | tile->layerDistoration[layno] = 0; |
1342 | 0 | for(uint16_t compno = 0; compno < tile->numcomps_; compno++) |
1343 | 0 | { |
1344 | 0 | auto tilec = tile->comps + compno; |
1345 | 0 | for(uint8_t resno = 0; resno < tilec->numresolutions; resno++) |
1346 | 0 | { |
1347 | 0 | auto res = tilec->resolutions_ + resno; |
1348 | 0 | for(uint8_t bandIndex = 0; bandIndex < res->numTileBandWindows; bandIndex++) |
1349 | 0 | { |
1350 | 0 | auto band = res->tileBand + bandIndex; |
1351 | 0 | for(auto prc : band->precincts) |
1352 | 0 | { |
1353 | 0 | for(uint64_t cblkno = 0; cblkno < prc->getNumCblks(); cblkno++) |
1354 | 0 | { |
1355 | 0 | auto cblk = prc->getCompressedBlockPtr(cblkno); |
1356 | 0 | auto layer = cblk->layers + layno; |
1357 | 0 | uint32_t included_blk_passes; |
1358 | |
|
1359 | 0 | if(layno == 0) |
1360 | 0 | prepareBlockForFirstLayer(cblk); |
1361 | 0 | if(thresh == 0) |
1362 | 0 | { |
1363 | 0 | included_blk_passes = cblk->numPassesTotal; |
1364 | 0 | } |
1365 | 0 | else |
1366 | 0 | { |
1367 | 0 | included_blk_passes = cblk->numPassesInPreviousPackets; |
1368 | 0 | for(uint32_t passno = cblk->numPassesInPreviousPackets; |
1369 | 0 | passno < cblk->numPassesTotal; passno++) |
1370 | 0 | { |
1371 | 0 | uint32_t dr; |
1372 | 0 | double dd; |
1373 | 0 | CodePass* pass = &cblk->passes[passno]; |
1374 | 0 | if(included_blk_passes == 0) |
1375 | 0 | { |
1376 | 0 | dr = pass->rate; |
1377 | 0 | dd = pass->distortiondec; |
1378 | 0 | } |
1379 | 0 | else |
1380 | 0 | { |
1381 | 0 | dr = pass->rate - cblk->passes[included_blk_passes - 1].rate; |
1382 | 0 | dd = pass->distortiondec - |
1383 | 0 | cblk->passes[included_blk_passes - 1].distortiondec; |
1384 | 0 | } |
1385 | |
|
1386 | 0 | if(!dr) |
1387 | 0 | { |
1388 | 0 | if(dd != 0) |
1389 | 0 | included_blk_passes = passno + 1; |
1390 | 0 | continue; |
1391 | 0 | } |
1392 | 0 | auto slope = dd / dr; |
1393 | | /* do not rely on float equality, check with DBL_EPSILON margin */ |
1394 | 0 | if(thresh - slope < DBL_EPSILON) |
1395 | 0 | included_blk_passes = passno + 1; |
1396 | 0 | } |
1397 | 0 | } |
1398 | 0 | layer->numpasses = included_blk_passes - cblk->numPassesInPreviousPackets; |
1399 | 0 | if(!layer->numpasses) |
1400 | 0 | { |
1401 | 0 | layer->distortion = 0; |
1402 | 0 | continue; |
1403 | 0 | } |
1404 | | |
1405 | | // update layer |
1406 | 0 | if(cblk->numPassesInPreviousPackets == 0) |
1407 | 0 | { |
1408 | 0 | layer->len = cblk->passes[included_blk_passes - 1].rate; |
1409 | 0 | layer->data = cblk->paddedCompressedStream; |
1410 | 0 | layer->distortion = cblk->passes[included_blk_passes - 1].distortiondec; |
1411 | 0 | } |
1412 | 0 | else |
1413 | 0 | { |
1414 | 0 | layer->len = cblk->passes[included_blk_passes - 1].rate - |
1415 | 0 | cblk->passes[cblk->numPassesInPreviousPackets - 1].rate; |
1416 | 0 | layer->data = cblk->paddedCompressedStream + |
1417 | 0 | cblk->passes[cblk->numPassesInPreviousPackets - 1].rate; |
1418 | 0 | layer->distortion = |
1419 | 0 | cblk->passes[included_blk_passes - 1].distortiondec - |
1420 | 0 | cblk->passes[cblk->numPassesInPreviousPackets - 1].distortiondec; |
1421 | 0 | } |
1422 | 0 | tile->layerDistoration[layno] += layer->distortion; |
1423 | 0 | if(finalAttempt) |
1424 | 0 | cblk->numPassesInPreviousPackets = included_blk_passes; |
1425 | 0 | } |
1426 | 0 | } |
1427 | 0 | } |
1428 | 0 | } |
1429 | 0 | } |
1430 | 0 | } |
1431 | | // Add all remaining passes to this layer |
1432 | | void TileProcessor::makeLayerFinal(uint32_t layno) |
1433 | 0 | { |
1434 | 0 | tile->layerDistoration[layno] = 0; |
1435 | 0 | for(uint16_t compno = 0; compno < tile->numcomps_; compno++) |
1436 | 0 | { |
1437 | 0 | auto tilec = tile->comps + compno; |
1438 | 0 | for(uint8_t resno = 0; resno < tilec->numresolutions; resno++) |
1439 | 0 | { |
1440 | 0 | auto res = tilec->resolutions_ + resno; |
1441 | 0 | for(uint8_t bandIndex = 0; bandIndex < res->numTileBandWindows; bandIndex++) |
1442 | 0 | { |
1443 | 0 | auto band = res->tileBand + bandIndex; |
1444 | 0 | for(auto prc : band->precincts) |
1445 | 0 | { |
1446 | 0 | for(uint64_t cblkno = 0; cblkno < prc->getNumCblks(); cblkno++) |
1447 | 0 | { |
1448 | 0 | auto cblk = prc->getCompressedBlockPtr(cblkno); |
1449 | 0 | auto layer = cblk->layers + layno; |
1450 | 0 | if(layno == 0) |
1451 | 0 | prepareBlockForFirstLayer(cblk); |
1452 | 0 | uint32_t included_blk_passes = cblk->numPassesInPreviousPackets; |
1453 | 0 | if(cblk->numPassesTotal > cblk->numPassesInPreviousPackets) |
1454 | 0 | included_blk_passes = cblk->numPassesTotal; |
1455 | |
|
1456 | 0 | layer->numpasses = included_blk_passes - cblk->numPassesInPreviousPackets; |
1457 | 0 | if(!layer->numpasses) |
1458 | 0 | { |
1459 | 0 | layer->distortion = 0; |
1460 | 0 | continue; |
1461 | 0 | } |
1462 | | // update layer |
1463 | 0 | if(cblk->numPassesInPreviousPackets == 0) |
1464 | 0 | { |
1465 | 0 | layer->len = cblk->passes[included_blk_passes - 1].rate; |
1466 | 0 | layer->data = cblk->paddedCompressedStream; |
1467 | 0 | layer->distortion = cblk->passes[included_blk_passes - 1].distortiondec; |
1468 | 0 | } |
1469 | 0 | else |
1470 | 0 | { |
1471 | 0 | layer->len = cblk->passes[included_blk_passes - 1].rate - |
1472 | 0 | cblk->passes[cblk->numPassesInPreviousPackets - 1].rate; |
1473 | 0 | layer->data = cblk->paddedCompressedStream + |
1474 | 0 | cblk->passes[cblk->numPassesInPreviousPackets - 1].rate; |
1475 | 0 | layer->distortion = |
1476 | 0 | cblk->passes[included_blk_passes - 1].distortiondec - |
1477 | 0 | cblk->passes[cblk->numPassesInPreviousPackets - 1].distortiondec; |
1478 | 0 | } |
1479 | 0 | tile->layerDistoration[layno] += layer->distortion; |
1480 | 0 | cblk->numPassesInPreviousPackets = included_blk_passes; |
1481 | 0 | assert(cblk->numPassesInPreviousPackets == cblk->numPassesTotal); |
1482 | 0 | } |
1483 | 0 | } |
1484 | 0 | } |
1485 | 0 | } |
1486 | 0 | } |
1487 | 0 | } |
1488 | 10.0k | Tile::Tile() : numcomps_(0), comps(nullptr), distortion(0) |
1489 | 10.0k | { |
1490 | 1.01M | for(uint32_t i = 0; i < maxCompressLayersGRK; ++i) |
1491 | 1.00M | layerDistoration[i] = 0; |
1492 | 10.0k | } |
1493 | 10.0k | Tile::Tile(uint16_t numcomps) : Tile() |
1494 | 10.0k | { |
1495 | 10.0k | assert(numcomps); |
1496 | 10.0k | numcomps_ = numcomps; |
1497 | 10.0k | if(numcomps) |
1498 | 10.0k | comps = new TileComponent[numcomps]; |
1499 | 10.0k | } |
1500 | | Tile::~Tile() |
1501 | 10.0k | { |
1502 | 10.0k | delete[] comps; |
1503 | 10.0k | } |
1504 | 10.0k | PacketTracker::PacketTracker() : bits(nullptr), numcomps_(0), numres_(0), numprec_(0), numlayers_(0) |
1505 | 10.0k | {} |
1506 | | PacketTracker::~PacketTracker() |
1507 | 10.0k | { |
1508 | 10.0k | delete[] bits; |
1509 | 10.0k | } |
1510 | | void PacketTracker::init(uint32_t numcomps, uint32_t numres, uint64_t numprec, uint32_t numlayers) |
1511 | 0 | { |
1512 | 0 | uint64_t len = get_buffer_len(numcomps, numres, numprec, numlayers); |
1513 | 0 | if(!bits) |
1514 | 0 | { |
1515 | 0 | bits = new uint8_t[len]; |
1516 | 0 | } |
1517 | 0 | else |
1518 | 0 | { |
1519 | 0 | uint64_t currentLen = get_buffer_len(numcomps_, numres_, numprec_, numlayers_); |
1520 | 0 | if(len > currentLen) |
1521 | 0 | { |
1522 | 0 | delete[] bits; |
1523 | 0 | bits = new uint8_t[len]; |
1524 | 0 | } |
1525 | 0 | } |
1526 | 0 | clear(); |
1527 | 0 | numcomps_ = numcomps; |
1528 | 0 | numres_ = numres; |
1529 | 0 | numprec_ = numprec; |
1530 | 0 | numlayers_ = numlayers; |
1531 | 0 | } |
1532 | | void PacketTracker::clear(void) |
1533 | 0 | { |
1534 | 0 | uint64_t currentLen = get_buffer_len(numcomps_, numres_, numprec_, numlayers_); |
1535 | 0 | memset(bits, 0, currentLen); |
1536 | 0 | } |
1537 | | uint64_t PacketTracker::get_buffer_len(uint32_t numcomps, uint32_t numres, uint64_t numprec, |
1538 | | uint32_t numlayers) |
1539 | 0 | { |
1540 | 0 | uint64_t len = (uint64_t)numcomps * numres * numprec * numlayers; |
1541 | |
|
1542 | 0 | return ((len + 7) >> 3) << 3; |
1543 | 0 | } |
1544 | | void PacketTracker::packet_encoded(uint32_t comps, uint32_t res, uint64_t prec, uint32_t layer) |
1545 | 0 | { |
1546 | 0 | if(comps >= numcomps_ || prec >= numprec_ || res >= numres_ || layer >= numlayers_) |
1547 | 0 | return; |
1548 | | |
1549 | 0 | uint64_t ind = index(comps, res, prec, layer); |
1550 | 0 | uint64_t ind_maj = ind >> 3; |
1551 | 0 | uint64_t ind_min = ind & 7; |
1552 | |
|
1553 | 0 | bits[ind_maj] = (uint8_t)(bits[ind_maj] | (1 << ind_min)); |
1554 | 0 | } |
1555 | | bool PacketTracker::is_packet_encoded(uint32_t comps, uint32_t res, uint64_t prec, uint32_t layer) |
1556 | 0 | { |
1557 | 0 | if(comps >= numcomps_ || prec >= numprec_ || res >= numres_ || layer >= numlayers_) |
1558 | 0 | return true; |
1559 | | |
1560 | 0 | uint64_t ind = index(comps, res, prec, layer); |
1561 | 0 | uint64_t ind_maj = ind >> 3; |
1562 | 0 | uint64_t ind_min = ind & 7; |
1563 | |
|
1564 | 0 | return ((bits[ind_maj] >> ind_min) & 1); |
1565 | 0 | } |
1566 | | uint64_t PacketTracker::index(uint32_t comps, uint32_t res, uint64_t prec, uint32_t layer) |
1567 | 0 | { |
1568 | 0 | return prec + (uint64_t)res * numprec_ + (uint64_t)comps * numres_ * numprec_ + |
1569 | 0 | (uint64_t)layer * numcomps_ * numres_ * numprec_; |
1570 | 0 | } |
1571 | | |
1572 | | } // namespace grk |