Coverage Report

Created: 2025-02-15 06:43

/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