Grok 20.3.2
CodeblockDecompressImpl.h
Go to the documentation of this file.
1/*
2 * Copyright (C) 2016-2026 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
18#pragma once
19
20#include <memory>
21
22#include "BitIO.h"
23#include "CodeblockImpl.h"
24#include "CodeStreamLimits.h"
25#include "t1_common.h"
26#include "mqc.h"
27
28namespace grk::t1
29{
30
39struct Segment
40{
44 Segment(uint16_t numlayers)
45 : numLayers_(numlayers), calculatedPassesInLayer_(new uint8_t[numLayers_]),
47 {
48 clear();
49 }
50
55 {
58 }
59
63 void clear()
64 {
65 totalPasses_ = 0;
66 totalBytes_ = 0;
67 maxPasses_ = 0;
68 memset(calculatedPassesInLayer_, 0, numLayers_ * sizeof(uint8_t));
69 memset(signalledBytesInLayer_, 0, numLayers_ * sizeof(uint16_t));
70 for(auto& b : data_chunks_)
71 delete b;
72 data_chunks_.clear();
73 }
74
75 void print(uint16_t layno)
76 {
77 grklog.info(
78 "Segment %p: total passes: %d, max passes: %d, calculated passes in layer: %d total "
79 "bytes: %d signalled bytes in layer: %d",
82 }
83
88 size_t getDataChunksLength() const
89 {
90 return std::accumulate(data_chunks_.begin(), data_chunks_.end(), (size_t)0,
91 [](const size_t s, Buffer8* a) { return s + a->num_elts(); });
92 }
93
99 size_t copyDataChunksToContiguous(uint8_t* buffer) const
100 {
101 size_t offset = 0;
102 for(auto& buf : data_chunks_)
103 {
104 if(buf->num_elts())
105 {
106 memcpy(buffer + offset, buf->buf(), buf->num_elts());
107 offset += buf->num_elts();
108 }
109 }
110 return offset;
111 }
112
116 uint16_t numLayers_ = 0;
117
121 uint8_t totalPasses_ = 0;
126 uint8_t maxPasses_ = 0;
132
136 uint32_t totalBytes_ = 0;
137
142
143 std::vector<Buffer8*> data_chunks_;
144};
145
151{
162
166 {
167 release();
168 delete[] buffers_;
169 delete[] buffer_lengths_;
170 }
171
174 void init()
175 {
177 }
178
183 std::vector<Segment*>::iterator toBeDecompressedBegin()
184 {
185 return segs_.begin() + numDecompressedSegments_;
186 }
187
192 std::vector<Segment*>::iterator toBeDecompressedEnd()
193 {
194 return segs_.begin() + numDataParsedSegments_;
195 }
196
200 void setNumBps(uint8_t bps)
201 {
202 numbps_ = bps;
204 }
205
211 Segment* getSegment(uint16_t index)
212 {
213 if(index == segs_.size())
214 segs_.push_back(new Segment(numLayers_));
215
216 return segs_[index];
217 }
218
225 void readPacketHeader(std::shared_ptr<t1_t2::BitIO> bio, uint32_t& signalledLayerDataBytes,
226 uint16_t layno, uint8_t cblk_sty)
227 {
228 // 1. read signalled passes in layer
229 uint8_t remainingPassesInLayer;
230 bio->getnumpasses(&remainingPassesInLayer);
231 assert(signalledPassesByLayer_[layno] == 0);
232 signalledPassesByLayer_[layno] = remainingPassesInLayer;
233
234 // 2. read signalled length bits
235 uint8_t increment = bio->getcommacode();
236 setNumLenBits(numlenbits() + increment);
237
238 // 3. prepare to parse segments:
239 // create new segment if there are currently none
240 // or the current segment has maxed out its passes
241 auto seg = currHeaderParsedSegment();
242 if(seg == segs_.end() || (*seg)->totalPasses_ == (*seg)->maxPasses_)
243 newSegment(cblk_sty);
244
245 // 4. parse all segments in this layer
246 do
247 {
248 // 1. set seg->calculatedPassesInLayer_
249 auto seg = segs_.back();
250 if(seg->maxPasses_ == maxPassesPerSegmentJ2K)
251 {
252 /* sanity check when there is no mode switch */
253 if(remainingPassesInLayer > maxPassesPerSegmentJ2K)
254 {
255 grklog.warn("Number of code block passes (%u) in packet is "
256 "suspiciously large.",
257 remainingPassesInLayer);
259 }
260 else
261 {
262 seg->calculatedPassesInLayer_[layno] = remainingPassesInLayer;
263 }
264 }
265 else
266 {
267 assert(seg->maxPasses_ >= seg->totalPasses_);
268 seg->calculatedPassesInLayer_[layno] = std::min<uint8_t>(
269 (uint8_t)(seg->maxPasses_ - seg->totalPasses_), remainingPassesInLayer);
270 }
271 if(seg->calculatedPassesInLayer_[layno] > remainingPassesInLayer)
272 {
273 grklog.warn("readHeader: number of segment passes %d in packet"
274 "is greater than total layer passes in packet %d ",
275 seg->calculatedPassesInLayer_[layno], remainingPassesInLayer);
277 }
278
279 // 2. read signalled number of bytes in this layer for current segment
280 uint8_t bits_to_read = numlenbits() + floorlog2(seg->calculatedPassesInLayer_[layno]);
281 if(bits_to_read > 16)
282 {
283 grklog.warn("readPacketHeader: signalled bits (%d) for layer bytes must be <= 16",
284 bits_to_read);
286 }
287 bio->read(seg->signalledBytesInLayer_ + layno, bits_to_read);
288 signalledLayerDataBytes += seg->signalledBytesInLayer_[layno];
289 assert(remainingPassesInLayer >= seg->calculatedPassesInLayer_[layno]);
290 remainingPassesInLayer -= seg->calculatedPassesInLayer_[layno];
291
292 // 3. create next segment if this layer spans multiple segments
293 if(remainingPassesInLayer > 0)
294 newSegment(cblk_sty);
295
296 } while(remainingPassesInLayer > 0);
297 }
298
317 void parsePacketData(uint16_t layno, size_t& remainingTilePartBytes, bool isHT,
318 uint8_t* layerData, uint32_t& layerDataOffset)
319 {
320 if(!signalledPassesByLayer_[layno])
321 return;
322
323 // 1. prepare to parse data for segments:
324 // move to next segment if there are currently no data-parsed segments
325 // or the current data-parsed segment has maxed out its passes
326 auto dSeg = currDataParsedSegment();
327 if(dSeg == segs_.end() || ((*dSeg)->totalPasses_ == (*dSeg)->maxPasses_))
328 dSeg = nextDataParsedSegment();
329 if(dSeg == segs_.end())
330 return;
331
332 dataParsedLayers_ = std::max(dataParsedLayers_, (uint16_t)(layno + 1));
333 uint8_t signalledPassesInLayer = signalledPassesByLayer_[layno];
334
335 // 2.run through all signalled passes in layer for all code block segments, generating
336 // segment buffers as we go
337 do
338 {
339 // 1. parse number of bytes and push segment buffer
340 if(((*dSeg)->signalledBytesInLayer_[layno] > remainingTilePartBytes))
341 {
342 // HT doesn't tolerate truncated code blocks since decoding runs both forward
343 // and reverse. So, in this case, we ignore the entire code block
344 if(isHT)
345 release();
346 (*dSeg)->signalledBytesInLayer_[layno] = 0;
347 (*dSeg)->totalPasses_ = 0;
348 return;
349 }
350 if((*dSeg)->signalledBytesInLayer_[layno])
351 {
352 // 1. sanity check on (*seg)->signalledBytesInLayer_
353 if(UINT_MAX - (*dSeg)->signalledBytesInLayer_[layno] < (*dSeg)->totalBytes_)
355
356 // 2. correct for truncated packet
357 if((*dSeg)->signalledBytesInLayer_[layno] > remainingTilePartBytes)
358 {
359 grklog.warn("CodeblockDecompress: signalled segment bytes in layer %d exceeds remaining"
360 "tile part bytes %d. Packet is trancated.",
361 (*dSeg)->signalledBytesInLayer_[layno], remainingTilePartBytes);
362
363 (*dSeg)->signalledBytesInLayer_[layno] = (uint16_t)remainingTilePartBytes;
364 }
365
366 // 3. push segment buffer
367 (*dSeg)->data_chunks_.push_back(new Buffer8(layerData + layerDataOffset,
368 (*dSeg)->signalledBytesInLayer_[layno], false));
369 layerDataOffset += (*dSeg)->signalledBytesInLayer_[layno];
370
371 // 4. update total bytes in segment
372 (*dSeg)->totalBytes_ += (*dSeg)->signalledBytesInLayer_[layno];
373 assert(remainingTilePartBytes >= (*dSeg)->signalledBytesInLayer_[layno]);
374 remainingTilePartBytes -= (*dSeg)->signalledBytesInLayer_[layno];
375 }
376
377 // 2. update total passes in segment
378 (*dSeg)->totalPasses_ += (*dSeg)->calculatedPassesInLayer_[layno];
379 assert(signalledPassesInLayer >= (*dSeg)->calculatedPassesInLayer_[layno]);
380 signalledPassesInLayer -= (*dSeg)->calculatedPassesInLayer_[layno];
381
382 // 3. this layer spans multiple segments, so move to next segment
383 if(signalledPassesInLayer > 0)
384 dSeg = nextDataParsedSegment();
385
386 } while(dSeg != segs_.end() && signalledPassesInLayer > 0);
387 }
388
393 void nextToBeDecompressedSegment(std::vector<Segment*>::iterator& s)
394 {
395 compressDataOffset_ += (*s)->totalBytes_;
396 passno_ = 0;
397 needsSegInit_ = true;
398 s++;
400 }
401#define T1_TYPE_MQ 0
402#define T1_TYPE_RAW 1
403
404 void prepareBufferList(std::vector<Segment*>::iterator seg)
405 {
406 delete[] buffers_;
407 buffers_ = nullptr;
408 delete[] buffer_lengths_;
409 buffer_lengths_ = nullptr;
410 num_buffers_ = (uint16_t)(*seg)->data_chunks_.size();
411 if(num_buffers_)
412 {
413 buffers_ = new uint8_t*[num_buffers_];
414 buffer_lengths_ = new uint32_t[num_buffers_];
415 uint16_t i = 0;
416 for(auto& bc : (*seg)->data_chunks_)
417 {
418 buffers_[i] = bc->buf();
419 buffer_lengths_[i] = (uint32_t)bc->num_elts();
420 i++;
421 }
422 }
423 }
424
430
440 template<typename T>
441 bool decompress(T* coder, uint8_t orientation, uint32_t cblksty)
442 {
444 {
445 grk::grklog.error("unsupported number of bit planes: %u > %u", bitPlanesToDecompress_,
447 return false;
448 }
449 if(!canDecompress())
450 return true;
451
452 auto segBegin = segs_.begin();
453 auto seg = toBeDecompressedBegin();
454
455 // restore from cache if needed
456 coder->decompressRestore(&passno_, &passtype_, &bitPlanesToDecompress_);
457
458 // IF we have maxed out segment passes
459 // AND this is the final layer so no more passes are possible
460 // OR there are now more data parsed segments
461 // THEN we can deduce that the previous decode reached end of segment
462 if(passno_ == (*seg)->totalPasses_ &&
463 (dataParsedLayers_ == numLayers_ || seg != segBegin + numDataParsedSegments_ - 1))
465
466 coder->decompressInitOrientation(orientation);
467 auto segEnd = toBeDecompressedEnd();
468 while(bitPlanesToDecompress_ > 0 && seg != segEnd)
469 {
470 /* BYPASS mode */
471 uint8_t type = ((cblksty & GRK_CBLKSTY_LAZY) && numbps_ >= 4 &&
472 (bitPlanesToDecompress_ <= ((int8_t)(numbps_)) - 4) && passtype_ < 2)
474 : T1_TYPE_MQ;
475
476 // if we need a segment init, then there is no point in also performing
477 // a segment update. Either way, we must toggle needsSegUpdate_
478 // to false, below
481 if(needsSegInit_)
482 {
483 coder->decompressInitSegment(type, buffers_, buffer_lengths_, num_buffers_);
484 needsSegInit_ = false;
485 }
486 else if(needsSegUpdate_)
487 {
488 coder->decompressUpdateSegment(buffers_, buffer_lengths_, num_buffers_);
489 }
490 needsSegUpdate_ = false;
491
492 while(passno_ < (*seg)->totalPasses_ && bitPlanesToDecompress_ > 0)
493 {
494 coder->decompressPass(passno_, passtype_, bitPlanesToDecompress_, type, cblksty);
495 if(++passtype_ == 3)
496 {
497 passtype_ = 0;
499 }
500 passno_++;
501 }
502
503 // we don't know yet whether this segment has ended
504 if(passno_ == (*seg)->totalPasses_ && dataParsedLayers_ != numLayers_ &&
505 seg == segBegin + numDataParsedSegments_ - 1)
506 break;
507
508 // force end of segment when bitPlanesToDecompress_ reaches zero
509 if((passno_ == (*seg)->totalPasses_ || bitPlanesToDecompress_ == 0))
511 }
512 coder->decompressFinish(cblksty, dataParsedLayers_ == numLayers_);
513 needsSegUpdate_ = true;
514
515 return true;
516 }
517
522 {
524 }
525
529 std::vector<Segment*>::iterator currDataParsedSegment(void)
530 {
531 return numDataParsedSegments_ ? segs_.begin() + numDataParsedSegments_ - 1 : segs_.end();
532 }
533
537 std::vector<Segment*>::iterator nextDataParsedSegment(void)
538 {
540 return currDataParsedSegment();
541 }
542
546 std::vector<Segment*>::iterator currHeaderParsedSegment(void)
547 {
548 return segs_.empty() ? segs_.end() : segs_.end() - 1;
549 }
550
556 {
557 for(const auto& segment : segs_)
558 {
559 if(!segment->data_chunks_.empty())
560 {
561 return false;
562 }
563 }
564 return true;
565 }
566
572 size_t getDataChunksLength() const
573 {
574 size_t total_length = 0;
575 for(auto s = segs_.begin(); s != segs_.end(); ++s)
576 total_length += (*s)->getDataChunksLength();
577
578 return total_length;
579 }
580
587 bool copyDataChunksToContiguous(uint8_t* buffer) const
588 {
589 if(!buffer)
590 return false;
591
592 size_t offset = 0;
593 for(auto s = segs_.begin(); s != segs_.end(); ++s)
594 offset += (*s)->copyDataChunksToContiguous(buffer + offset);
595
596 return true;
597 }
598
599private:
603 void release()
604 {
605 for(auto s : segs_)
606 {
607 s->clear();
608 delete s;
609 }
610 segs_.clear();
613 }
614
620 void newSegment(uint8_t cblk_sty)
621 {
622 segs_.push_back(new Segment(numLayers_));
623 auto seg = segs_.back();
624 if(cblk_sty & GRK_CBLKSTY_TERMALL)
625 {
626 seg->maxPasses_ = 1;
627 }
628 else if(cblk_sty & GRK_CBLKSTY_LAZY)
629 {
630 // first segment
631 if(segs_.size() == 1)
632 {
633 seg->maxPasses_ = 10;
634 }
635 else
636 {
637 auto prev_segment = segs_.end() - 2;
638 seg->maxPasses_ =
639 (((*prev_segment)->maxPasses_ == 1) || ((*prev_segment)->maxPasses_ == 10)) ? 2 : 1;
640 }
641 }
642 else
643 {
644 seg->maxPasses_ = maxPassesPerSegmentJ2K;
645 }
646 }
647
665 std::vector<Segment*> segs_;
666
670 uint8_t** buffers_;
671
676
680 uint16_t num_buffers_;
681
689 uint8_t passtype_;
697 uint8_t passno_;
702
711};
712
713} // namespace grk::t1
#define T1_TYPE_MQ
Definition CodeblockDecompressImpl.h:401
#define T1_TYPE_RAW
Definition CodeblockDecompressImpl.h:402
Definition Codeblock.h:37
Definition Codeblock.h:34
#define GRK_CBLKSTY_TERMALL
Definition grok.h:1886
#define GRK_CBLKSTY_LAZY
Definition grok.h:1884
Definition SchedulerFreebyrd.h:36
ILogger & grklog
Definition Logger.cpp:24
static uint8_t floorlog2(uint32_t a)
Get logarithm of an integer and round downwards.
Definition intmath.h:74
const uint8_t maxPassesPerSegmentJ2K
Definition CodeStreamLimits.h:28
const uint32_t maxBitPlanesJ2K
Definition CodeStreamLimits.h:35
Buffer< uint8_t, AllocatorVanilla > Buffer8
Definition buffer.h:257
uint16_t num_buffers_
Number of buffers.
Definition CodeblockDecompressImpl.h:680
std::vector< Segment * >::iterator toBeDecompressedEnd()
Iterator pointing one location past the last Segment whose data has been parsed.
Definition CodeblockDecompressImpl.h:192
void init()
Initializes the code block.
Definition CodeblockDecompressImpl.h:174
bool needsSegInit_
decompression: segment needs initialization
Definition CodeblockDecompressImpl.h:701
uint8_t ** buffers_
Array of pointers to buffers.
Definition CodeblockDecompressImpl.h:670
bool dataChunksEmpty()
Checks whether all segments' data chunks are empty.
Definition CodeblockDecompressImpl.h:555
uint8_t numDataParsedSegments_
Number of segments whose data has been read from their respective layers.
Definition CodeblockDecompressImpl.h:657
uint32_t compressDataOffset_
offset into contiguous buffer of compressed data
Definition CodeblockDecompressImpl.h:693
std::vector< Segment * > segs_
Collection of Segment.
Definition CodeblockDecompressImpl.h:665
void newSegment(uint8_t cblk_sty)
Creates a new Segment.
Definition CodeblockDecompressImpl.h:620
bool copyDataChunksToContiguous(uint8_t *buffer) const
Copies all segment data chunk buffers for all uncompressed segments whose data has been parsed,...
Definition CodeblockDecompressImpl.h:587
std::vector< Segment * >::iterator nextDataParsedSegment(void)
Increments to next segment whose data is going to be parsed.
Definition CodeblockDecompressImpl.h:537
uint16_t dataParsedLayers_
number of layers whose data has been parsed
Definition CodeblockDecompressImpl.h:710
bool needsSegUpdate_
decompression: segment needs update, as more packets have been parsed
Definition CodeblockDecompressImpl.h:706
Segment * getSegment(uint16_t index)
Gets segment for the specified index If index equals number of segments, then a new segment will be a...
Definition CodeblockDecompressImpl.h:211
void setNumBps(uint8_t bps)
Sets number of bit planes to be decompressed.
Definition CodeblockDecompressImpl.h:200
uint8_t passno_
decompression: current pass number
Definition CodeblockDecompressImpl.h:697
uint8_t numDecompressedSegments_
Number of decompressed segments.
Definition CodeblockDecompressImpl.h:661
bool decompress(T *coder, uint8_t orientation, uint32_t cblksty)
Decompresses all layers specified so far.
Definition CodeblockDecompressImpl.h:441
std::vector< Segment * >::iterator currHeaderParsedSegment(void)
Gets iterator pointing to current segment being populated by packet header.
Definition CodeblockDecompressImpl.h:546
bool canDecompress(void)
Definition CodeblockDecompressImpl.h:425
void readPacketHeader(std::shared_ptr< t1_t2::BitIO > bio, uint32_t &signalledLayerDataBytes, uint16_t layno, uint8_t cblk_sty)
Reads packet header.
Definition CodeblockDecompressImpl.h:225
void parsePacketData(uint16_t layno, size_t &remainingTilePartBytes, bool isHT, uint8_t *layerData, uint32_t &layerDataOffset)
Parses packet data based on packet header.
Definition CodeblockDecompressImpl.h:317
~CodeblockDecompressImpl()
Destroys a CodeblockDecompressImpl.
Definition CodeblockDecompressImpl.h:165
void nextToBeDecompressedSegment(std::vector< Segment * >::iterator &s)
Increments iterator for next segment to be decompressed.
Definition CodeblockDecompressImpl.h:393
uint16_t getNumDataParsedSegments(void)
Gets number of segments whose layer data has been parsed.
Definition CodeblockDecompressImpl.h:521
uint8_t bitPlanesToDecompress_
Remaining bit planes to decompress.
Definition CodeblockDecompressImpl.h:685
CodeblockDecompressImpl(uint16_t numLayers)
Constructs a CodeblockDecompressImpl.
Definition CodeblockDecompressImpl.h:156
size_t getDataChunksLength() const
Gets combined length of all data chunks across all uncompressed segments whose datg has been parsed.
Definition CodeblockDecompressImpl.h:572
uint32_t * buffer_lengths_
Array of buffer lengths.
Definition CodeblockDecompressImpl.h:675
std::vector< Segment * >::iterator toBeDecompressedBegin()
Iterator pointing to the beginning of the segments yet to be decompressed.
Definition CodeblockDecompressImpl.h:183
std::vector< Segment * >::iterator currDataParsedSegment(void)
Gets iterator pointing to current segment whose layer data is being parsed.
Definition CodeblockDecompressImpl.h:529
uint8_t passtype_
Type of pass: cleanup, magnitude refinement or significance propagation.
Definition CodeblockDecompressImpl.h:689
void prepareBufferList(std::vector< Segment * >::iterator seg)
Definition CodeblockDecompressImpl.h:404
void release()
Releases resources.
Definition CodeblockDecompressImpl.h:603
uint16_t numLayers_
Definition CodeblockImpl.h:80
uint8_t * signalledPassesByLayer_
Definition CodeblockImpl.h:79
CodeblockImpl(uint16_t numLayers)
Definition CodeblockImpl.h:25
void init()
Definition CodeblockImpl.h:70
void setNumLenBits(uint8_t bits)
Definition CodeblockImpl.h:64
uint8_t numbps_
Definition CodeblockImpl.h:77
uint8_t numlenbits()
Definition CodeblockImpl.h:60
Stores information for a code block segment.
Definition CodeblockDecompressImpl.h:40
uint16_t numLayers_
Number of layers for this code block.
Definition CodeblockDecompressImpl.h:116
~Segment(void)
Destroys a Segment.
Definition CodeblockDecompressImpl.h:54
uint8_t * calculatedPassesInLayer_
Number of passes contributed by layer, calculated by decompress codeblock when parsing packet header.
Definition CodeblockDecompressImpl.h:131
std::vector< Buffer8 * > data_chunks_
Definition CodeblockDecompressImpl.h:143
void clear()
Clears a Segment.
Definition CodeblockDecompressImpl.h:63
size_t getDataChunksLength() const
Gets combined length of all data chunks.
Definition CodeblockDecompressImpl.h:88
size_t copyDataChunksToContiguous(uint8_t *buffer) const
Copies data chunks into a single contiguous buffer.
Definition CodeblockDecompressImpl.h:99
uint8_t maxPasses_
Maximum number of passes in this code block This is determined by the code block style i....
Definition CodeblockDecompressImpl.h:126
uint32_t totalBytes_
Total number of bytes in segment.
Definition CodeblockDecompressImpl.h:136
Segment(uint16_t numlayers)
Constructs a Segment.
Definition CodeblockDecompressImpl.h:44
uint16_t * signalledBytesInLayer_
Number of bytes signalled by layer.
Definition CodeblockDecompressImpl.h:141
void print(uint16_t layno)
Definition CodeblockDecompressImpl.h:75
uint8_t totalPasses_
Running total of number of passes across multiple layers.
Definition CodeblockDecompressImpl.h:121