1 /*
2     RawSpeed - RAW file decoder.
3 
4     Copyright (C) 2018 Stefan Löffler
5     Copyright (C) 2018-2019 Roman Lebedev
6 
7     This library is free software; you can redistribute it and/or
8     modify it under the terms of the GNU Lesser General Public
9     License as published by the Free Software Foundation; either
10     version 2 of the License, or (at your option) any later version.
11 
12     This library is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15     Lesser General Public License for more details.
16 
17     You should have received a copy of the GNU Lesser General Public
18     License along with this library; if not, write to the Free Software
19     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21 
22 /*
23   This is a decompressor for VC-5 raw compression algo, as used in GoPro raws.
24   This implementation is similar to that one of the official reference
25   implementation of the https://github.com/gopro/gpr project, and is producing
26   bitwise-identical output as compared with the Adobe DNG Converter
27   implementation.
28  */
29 
30 #include "rawspeedconfig.h" // for HAVE_OPENMP
31 #include "decompressors/VC5Decompressor.h"
32 #include "common/Array2DRef.h"            // for Array2DRef
33 #include "common/Common.h"                // for clampBits, roundUpDivision
34 #include "common/Point.h"                 // for iPoint2D
35 #include "common/RawspeedException.h"     // for RawspeedException
36 #include "common/SimpleLUT.h"             // for SimpleLUT, SimpleLUT<>::va...
37 #include "decoders/RawDecoderException.h" // for ThrowRDE
38 #include "io/Endianness.h"                // for Endianness, Endianness::big
39 #include <cassert>                        // for assert
40 #include <cmath>                          // for pow
41 #include <initializer_list>               // for initializer_list
42 #include <limits>                         // for numeric_limits
43 #include <optional>                       // for optional
44 #include <string>                         // for string
45 #include <utility>                        // for move
46 
47 namespace {
48 
49 // Definitions needed by table17.inc
50 // Taken from
51 // https://github.com/gopro/gpr/blob/a513701afce7b03173213a2f67dfd9dd28fa1868/source/lib/vc5_decoder/vlc.h
52 struct RLV {
53   uint_fast8_t size; //!< Size of code word in bits
54   uint32_t bits;     //!< Code word bits right justified
55   uint16_t count;    //!< Run length
56   uint16_t value;    //!< Run value (unsigned)
57 };
58 #define RLVTABLE(n)                                                            \
59   struct {                                                                     \
60     const uint32_t length;                                                     \
61     const RLV entries[n];                                                      \
62   } constexpr
63 #include "gopro/vc5/table17.inc"
64 
decompand(int16_t val)65 constexpr int16_t decompand(int16_t val) {
66   double c = val;
67   // Invert companding curve
68   c += (c * c * c * 768) / (255. * 255. * 255.);
69   if (c > std::numeric_limits<int16_t>::max())
70     return std::numeric_limits<int16_t>::max();
71   if (c < std::numeric_limits<int16_t>::min())
72     return std::numeric_limits<int16_t>::min();
73   return c;
74 }
75 
76 #ifndef NDEBUG
__anonba823cc30202() 77 [[maybe_unused]] const int ignore = []() {
78   for (const RLV& entry : table17.entries) {
79     assert(((-decompand(entry.value)) == decompand(-int16_t(entry.value))) &&
80            "negation of decompanded value is the same as decompanding of "
81            "negated value");
82   }
83   return 0;
84 }();
85 #endif
86 
__anonba823cc30302() 87 const std::array<RLV, table17.length> decompandedTable17 = []() {
88   std::array<RLV, table17.length> d;
89   for (auto i = 0U; i < table17.length; i++) {
90     d[i] = table17.entries[i];
91     d[i].value = decompand(table17.entries[i].value);
92   }
93   return d;
94 }();
95 
readValue(const bool & storage)96 inline bool readValue(const bool& storage) {
97   bool value;
98 
99 #ifdef HAVE_OPENMP
100 #pragma omp atomic read
101 #endif
102   value = storage;
103 
104   return value;
105 }
106 
107 constexpr int PRECISION_MIN = 8;
108 constexpr int PRECISION_MAX = 16;
109 constexpr int MARKER_BAND_END = 1;
110 
111 } // namespace
112 
113 namespace rawspeed {
114 
setBandValid(const int band)115 void VC5Decompressor::Wavelet::setBandValid(const int band) {
116   mDecodedBandMask |= (1 << band);
117 }
118 
isBandValid(const int band) const119 bool VC5Decompressor::Wavelet::isBandValid(const int band) const {
120   return mDecodedBandMask & (1 << band);
121 }
122 
allBandsValid() const123 bool VC5Decompressor::Wavelet::allBandsValid() const {
124   return mDecodedBandMask == static_cast<uint32_t>((1 << maxBands) - 1);
125 }
126 
127 namespace {
128 template <typename LowGetter>
convolute(int row,int col,std::array<int,4> muls,const Array2DRef<const int16_t> high,LowGetter lowGetter,int DescaleShift=0)129 inline auto convolute(int row, int col, std::array<int, 4> muls,
130                       const Array2DRef<const int16_t> high, LowGetter lowGetter,
131                       int DescaleShift = 0) {
132   auto highCombined = muls[0] * high(row, col);
133   auto lowsCombined = [muls, &lowGetter]() {
134     int lows = 0;
135     for (int i = 0; i < 3; i++)
136       lows += muls[1 + i] * lowGetter(i);
137     return lows;
138   }();
139   // Round up 'lows' up
140   lowsCombined += 4;
141   // And finally 'average' them.
142   auto lowsRounded = lowsCombined >> 3;
143   auto total = highCombined + lowsRounded;
144   // Descale it.
145   total <<= DescaleShift;
146   // And average it.
147   total >>= 1;
148   return total;
149 }
150 
151 struct ConvolutionParams {
152   struct First {
153     static constexpr std::array<int, 4> mul_even = {+1, +11, -4, +1};
154     static constexpr std::array<int, 4> mul_odd = {-1, +5, +4, -1};
155     static constexpr int coord_shift = 0;
156   };
157 
158   struct Middle {
159     static constexpr std::array<int, 4> mul_even = {+1, +1, +8, -1};
160     static constexpr std::array<int, 4> mul_odd = {-1, -1, +8, +1};
161     static constexpr int coord_shift = -1;
162   };
163 
164   struct Last {
165     static constexpr std::array<int, 4> mul_even = {+1, -1, +4, +5};
166     static constexpr std::array<int, 4> mul_odd = {-1, +1, -4, +11};
167     static constexpr int coord_shift = -2;
168   };
169 };
170 
171 } // namespace
172 
reconstructPass(const Array2DRef<const int16_t> high,const Array2DRef<const int16_t> low)173 VC5Decompressor::BandData VC5Decompressor::Wavelet::reconstructPass(
174     const Array2DRef<const int16_t> high,
175     const Array2DRef<const int16_t> low) noexcept {
176   BandData combined;
177   auto& dst = combined.description;
178   dst = Array2DRef<int16_t>::create(combined.storage, high.width,
179                                     2 * high.height);
180 
181   auto process = [low, high, dst](auto segment, int row, int col) {
182     using SegmentTy = decltype(segment);
183     auto lowGetter = [&row, &col, low](int delta) {
184       return low(row + SegmentTy::coord_shift + delta, col);
185     };
186     auto convolution = [&row, &col, high, &lowGetter](std::array<int, 4> muls) {
187       return convolute(row, col, muls, high, lowGetter, /*DescaleShift*/ 0);
188     };
189 
190     int even = convolution(SegmentTy::mul_even);
191     int odd = convolution(SegmentTy::mul_odd);
192 
193     dst(2 * row, col) = static_cast<int16_t>(even);
194     dst(2 * row + 1, col) = static_cast<int16_t>(odd);
195   };
196 
197 #pragma GCC diagnostic push
198 // See https://bugs.llvm.org/show_bug.cgi?id=51666
199 #pragma GCC diagnostic ignored "-Wsign-compare"
200 #ifdef HAVE_OPENMP
201 #pragma omp taskloop default(none) firstprivate(dst, process) num_tasks(       \
202     roundUpDivision(rawspeed_get_number_of_processor_cores(), numChannels))
203 #endif
204   for (int row = 0; row < dst.height / 2; ++row) {
205 #pragma GCC diagnostic pop
206     if (row == 0) {
207       // 1st row
208       for (int col = 0; col < dst.width; ++col)
209         process(ConvolutionParams::First(), row, col);
210     } else if (row + 1 < dst.height / 2) {
211       // middle rows
212       for (int col = 0; col < dst.width; ++col)
213         process(ConvolutionParams::Middle(), row, col);
214     } else {
215       // last row
216       for (int col = 0; col < dst.width; ++col)
217         process(ConvolutionParams::Last(), row, col);
218     }
219   }
220 
221   return combined;
222 }
223 
combineLowHighPass(const Array2DRef<const int16_t> low,const Array2DRef<const int16_t> high,int descaleShift,bool clampUint=false,bool finalWavelet=false)224 VC5Decompressor::BandData VC5Decompressor::Wavelet::combineLowHighPass(
225     const Array2DRef<const int16_t> low, const Array2DRef<const int16_t> high,
226     int descaleShift, bool clampUint = false,
227     [[maybe_unused]] bool finalWavelet = false) noexcept {
228   BandData combined;
229   auto& dst = combined.description;
230   dst = Array2DRef<int16_t>::create(combined.storage, 2 * high.width,
231                                     high.height);
232 
233   auto process = [low, high, descaleShift, clampUint, dst](auto segment,
234                                                            int row, int col) {
235     using SegmentTy = decltype(segment);
236     auto lowGetter = [&row, &col, low](int delta) {
237       return low(row, col + SegmentTy::coord_shift + delta);
238     };
239     auto convolution = [&row, &col, high, &lowGetter,
240                         descaleShift](std::array<int, 4> muls) {
241       return convolute(row, col, muls, high, lowGetter, descaleShift);
242     };
243 
244     int even = convolution(SegmentTy::mul_even);
245     int odd = convolution(SegmentTy::mul_odd);
246 
247     if (clampUint) {
248       even = clampBits(even, 14);
249       odd = clampBits(odd, 14);
250     }
251     dst(row, 2 * col) = static_cast<int16_t>(even);
252     dst(row, 2 * col + 1) = static_cast<int16_t>(odd);
253   };
254 
255   // Horizontal reconstruction
256 #pragma GCC diagnostic push
257   // See https://bugs.llvm.org/show_bug.cgi?id=51666
258 #pragma GCC diagnostic ignored "-Wsign-compare"
259 #ifdef HAVE_OPENMP
260 #pragma omp taskloop if (finalWavelet) default(none) firstprivate(dst,         \
261                                                                   process)     \
262     num_tasks(roundUpDivision(rawspeed_get_number_of_processor_cores(), 2))    \
263         mergeable
264 #endif
265   for (int row = 0; row < dst.height; ++row) {
266 #pragma GCC diagnostic pop
267     // First col
268     int col = 0;
269     process(ConvolutionParams::First(), row, col);
270     // middle cols
271     for (col = 1; col + 1 < dst.width / 2; ++col) {
272       process(ConvolutionParams::Middle(), row, col);
273     }
274     // last col
275     process(ConvolutionParams::Last(), row, col);
276   }
277 
278   return combined;
279 }
280 
281 void VC5Decompressor::Wavelet::ReconstructableBand::
createLowpassReconstructionTask(const bool & exceptionThrown)282     createLowpassReconstructionTask(const bool& exceptionThrown) noexcept {
283   auto& highlow = wavelet.bands[2]->data;
284   auto& lowlow = wavelet.bands[0]->data;
285   auto& lowpass = intermediates.lowpass;
286 
287 #ifdef HAVE_OPENMP
288 #pragma omp task default(none)                                                 \
289     shared(exceptionThrown, highlow, lowlow, lowpass)                          \
290         depend(in                                                              \
291                : highlow, lowlow) depend(out                                   \
292                                          : lowpass)
293 #endif
294   {
295     // Proceed only if decoding did not fail.
296     if (!readValue(exceptionThrown)) {
297       assert(highlow.has_value() && lowlow.has_value() &&
298              "Failed to produce precursor bands?");
299       // Reconstruct the "immediates", the actual low pass ...
300       assert(!lowpass.has_value() && "Combined this precursor band already?");
301       lowpass.emplace(
302           Wavelet::reconstructPass(highlow->description, lowlow->description));
303     }
304   }
305 }
306 
307 void VC5Decompressor::Wavelet::ReconstructableBand::
createHighpassReconstructionTask(const bool & exceptionThrown)308     createHighpassReconstructionTask(const bool& exceptionThrown) noexcept {
309   auto& highhigh = wavelet.bands[3]->data;
310   auto& lowhigh = wavelet.bands[1]->data;
311   auto& highpass = intermediates.highpass;
312 
313 #ifdef HAVE_OPENMP
314 #pragma omp task default(none)                                                 \
315     shared(exceptionThrown, highhigh, lowhigh, highpass)                       \
316         depend(in                                                              \
317                : highhigh, lowhigh) depend(out                                 \
318                                            : highpass)
319 #endif
320   {
321     // Proceed only if decoding did not fail.
322     if (!readValue(exceptionThrown)) {
323       assert(highhigh.has_value() && lowhigh.has_value() &&
324              "Failed to produce precursor bands?");
325       assert(!highpass.has_value() && "Combined this precursor band already?");
326       highpass.emplace(Wavelet::reconstructPass(highhigh->description,
327                                                 lowhigh->description));
328     }
329   }
330 }
331 
332 void VC5Decompressor::Wavelet::ReconstructableBand::
createLowHighPassCombiningTask(const bool & exceptionThrown)333     createLowHighPassCombiningTask(const bool& exceptionThrown) noexcept {
334   auto& lowpass = intermediates.lowpass;
335   auto& highpass = intermediates.highpass;
336   auto& reconstructedLowpass = data;
337 
338 #ifdef HAVE_OPENMP
339 #pragma omp task default(none) depend(in : lowpass, highpass)
340 #endif
341   wavelet.bands.clear();
342 
343 #ifdef HAVE_OPENMP
344 #pragma omp task default(none)                                                 \
345     shared(exceptionThrown, lowpass, highpass, reconstructedLowpass)           \
346         depend(in                                                              \
347                : lowpass, highpass) depend(out                                 \
348                                            : reconstructedLowpass)
349 #endif
350   {
351     // Proceed only if decoding did not fail.
352     if (!readValue(exceptionThrown)) {
353       assert(lowpass.has_value() && highpass.has_value() &&
354              "Failed to combine precursor bands?");
355       assert(!data.has_value() && "Reconstructed this band already?");
356 
357       int16_t descaleShift = (wavelet.prescale == 2 ? 2 : 0);
358 
359       // And finally, combine the low pass, and high pass.
360       reconstructedLowpass.emplace(Wavelet::combineLowHighPass(
361           lowpass->description, highpass->description, descaleShift, clampUint,
362           finalWavelet));
363     }
364   }
365 }
366 
createDecodingTasks(ErrorLog & errLog,bool & exceptionThrow)367 void VC5Decompressor::Wavelet::ReconstructableBand::createDecodingTasks(
368     ErrorLog& errLog, bool& exceptionThrow) noexcept {
369   assert(wavelet.allBandsValid());
370   createLowpassReconstructionTask(exceptionThrow);
371   createHighpassReconstructionTask(exceptionThrow);
372   createLowHighPassCombiningTask(exceptionThrow);
373 }
374 
VC5Decompressor(ByteStream bs,const RawImage & img)375 VC5Decompressor::VC5Decompressor(ByteStream bs, const RawImage& img)
376     : mRaw(img), mBs(std::move(bs)) {
377   if (!mRaw->dim.hasPositiveArea())
378     ThrowRDE("Bad image dimensions.");
379 
380   if (mRaw->dim.x % mVC5.patternWidth != 0)
381     ThrowRDE("Width %u is not a multiple of %u", mRaw->dim.x,
382              mVC5.patternWidth);
383 
384   if (mRaw->dim.y % mVC5.patternHeight != 0)
385     ThrowRDE("Height %u is not a multiple of %u", mRaw->dim.y,
386              mVC5.patternHeight);
387 
388   // Initialize wavelet sizes.
389   for (Channel& channel : channels) {
390     uint16_t waveletWidth = mRaw->dim.x;
391     uint16_t waveletHeight = mRaw->dim.y;
392     for (Wavelet& wavelet : channel.wavelets) {
393       // Pad dimensions as necessary and divide them by two for the next wavelet
394       for (auto* dimension : {&waveletWidth, &waveletHeight})
395         *dimension = roundUpDivision(*dimension, 2);
396       wavelet.width = waveletWidth;
397       wavelet.height = waveletHeight;
398 
399       wavelet.bands.resize(
400           &wavelet == channel.wavelets.begin() ? 1 : Wavelet::maxBands);
401     }
402   }
403 
404   if (img->whitePoint <= 0 || img->whitePoint > int(((1U << 16U) - 1U)))
405     ThrowRDE("Bad white level %i", img->whitePoint);
406 
407   outputBits = 0;
408   for (int wp = img->whitePoint; wp != 0; wp >>= 1)
409     ++outputBits;
410   assert(outputBits <= 16);
411 
412   parseVC5();
413 }
414 
initVC5LogTable()415 void VC5Decompressor::initVC5LogTable() {
416   mVC5LogTable = decltype(mVC5LogTable)(
417       [outputBits = outputBits](unsigned i, unsigned tableSize) {
418         // The vanilla "inverse log" curve for decoding.
419         auto normalizedCurve = [](auto normalizedI) {
420           return (std::pow(113.0, normalizedI) - 1) / 112.0;
421         };
422 
423         auto normalizeI = [tableSize](auto x) { return x / (tableSize - 1.0); };
424         auto denormalizeY = [maxVal = std::numeric_limits<uint16_t>::max()](
425                                 auto y) { return maxVal * y; };
426         // Adjust for output whitelevel bitdepth.
427         auto rescaleY = [outputBits](auto y) {
428           auto scale = 16 - outputBits;
429           return y >> scale;
430         };
431 
432         const auto naiveY = denormalizeY(normalizedCurve(normalizeI(i)));
433         const auto intY = static_cast<unsigned int>(naiveY);
434         const auto rescaledY = rescaleY(intY);
435         return rescaledY;
436       });
437 }
438 
parseVC5()439 void VC5Decompressor::parseVC5() {
440   mBs.setByteOrder(Endianness::big);
441 
442   assert(mRaw->dim.x > 0);
443   assert(mRaw->dim.y > 0);
444 
445   // All VC-5 data must start with "VC-%" (0x56432d35)
446   if (mBs.getU32() != 0x56432d35)
447     ThrowRDE("not a valid VC-5 datablock");
448 
449   bool done = false;
450   while (!done) {
451     auto tag = static_cast<VC5Tag>(mBs.getU16());
452     uint16_t val = mBs.getU16();
453 
454     bool optional = matches(tag, VC5Tag::Optional);
455     if (optional)
456       tag = -tag;
457 
458     switch (tag) {
459     case VC5Tag::ChannelCount:
460       if (val != numChannels)
461         ThrowRDE("Bad channel count %u, expected %u", val, numChannels);
462       break;
463     case VC5Tag::ImageWidth:
464       if (val != mRaw->dim.x)
465         ThrowRDE("Image width mismatch: %u vs %u", val, mRaw->dim.x);
466       break;
467     case VC5Tag::ImageHeight:
468       if (val != mRaw->dim.y)
469         ThrowRDE("Image height mismatch: %u vs %u", val, mRaw->dim.y);
470       break;
471     case VC5Tag::LowpassPrecision:
472       if (val < PRECISION_MIN || val > PRECISION_MAX)
473         ThrowRDE("Invalid precision %i", val);
474       mVC5.lowpassPrecision = val;
475       break;
476     case VC5Tag::ChannelNumber:
477       if (val >= numChannels)
478         ThrowRDE("Bad channel number (%u)", val);
479       mVC5.iChannel = val;
480       break;
481     case VC5Tag::ImageFormat:
482       if (val != mVC5.imgFormat)
483         ThrowRDE("Image format %i is not 4(RAW)", val);
484       break;
485     case VC5Tag::SubbandCount:
486       if (val != numSubbands)
487         ThrowRDE("Unexpected subband count %u, expected %u", val, numSubbands);
488       break;
489     case VC5Tag::MaxBitsPerComponent:
490       if (val != VC5_LOG_TABLE_BITWIDTH) {
491         ThrowRDE("Bad bits per componend %u, not %u", val,
492                  VC5_LOG_TABLE_BITWIDTH);
493       }
494       break;
495     case VC5Tag::PatternWidth:
496       if (val != mVC5.patternWidth)
497         ThrowRDE("Bad pattern width %u, not %u", val, mVC5.patternWidth);
498       break;
499     case VC5Tag::PatternHeight:
500       if (val != mVC5.patternHeight)
501         ThrowRDE("Bad pattern height %u, not %u", val, mVC5.patternHeight);
502       break;
503     case VC5Tag::SubbandNumber:
504       if (val >= numSubbands)
505         ThrowRDE("Bad subband number %u", val);
506       mVC5.iSubband = val;
507       break;
508     case VC5Tag::Quantization:
509       mVC5.quantization = static_cast<int16_t>(val);
510       break;
511     case VC5Tag::ComponentsPerSample:
512       if (val != mVC5.cps)
513         ThrowRDE("Bad component per sample count %u, not %u", val, mVC5.cps);
514       break;
515     case VC5Tag::PrescaleShift:
516       // FIXME: something is wrong. We get this before VC5Tag::ChannelNumber.
517       // Defaulting to 'mVC5.iChannel=0' seems to work *for existing samples*.
518       for (int iWavelet = 0; iWavelet < numWaveletLevels; ++iWavelet) {
519         auto& channel = channels[mVC5.iChannel];
520         auto& wavelet = channel.wavelets[1 + iWavelet];
521         wavelet.prescale =
522             extractHighBits(val, 2 * iWavelet, /*effectiveBitwidth=*/14) & 0x03;
523       }
524       break;
525     default: { // A chunk.
526       unsigned int chunkSize = 0;
527       if (matches(tag, VC5Tag::LARGE_CHUNK)) {
528         chunkSize = static_cast<unsigned int>(
529             ((static_cast<std::underlying_type_t<VC5Tag>>(tag) & 0xff) << 16) |
530             (val & 0xffff));
531       } else if (matches(tag, VC5Tag::SMALL_CHUNK)) {
532         chunkSize = (val & 0xffff);
533       }
534 
535       if (is(tag, VC5Tag::LargeCodeblock)) {
536         parseLargeCodeblock(mBs.getStream(chunkSize, 4));
537         break;
538       }
539 
540       // And finally, we got here if we didn't handle this tag/maybe-chunk.
541 
542       // Magic, all the other 'large' chunks are actually optional,
543       // and don't specify any chunk bytes-to-be-skipped.
544       if (matches(tag, VC5Tag::LARGE_CHUNK)) {
545         optional = true;
546         chunkSize = 0;
547       }
548 
549       if (!optional) {
550         ThrowRDE("Unknown (unhandled) non-optional Tag 0x%04hx",
551                  static_cast<std::underlying_type_t<VC5Tag>>(tag));
552       }
553 
554       if (chunkSize)
555         mBs.skipBytes(chunkSize, 4);
556 
557       break;
558     }
559     }
560 
561     done = std::all_of(channels.begin(), channels.end(),
562                        [](const Channel& channel) {
563                          return channel.wavelets[0].isBandValid(0);
564                        });
565   }
566 }
567 
createDecodingTasks(ErrorLog & errLog,bool & exceptionThrown)568 void VC5Decompressor::Wavelet::AbstractDecodeableBand::createDecodingTasks(
569     ErrorLog& errLog, bool& exceptionThrown) noexcept {
570   auto& decodedData = data;
571 
572 #ifdef HAVE_OPENMP
573 #pragma omp task default(none) shared(decodedData, errLog, exceptionThrown)    \
574     depend(out                                                                 \
575            : decodedData)
576 #endif
577   {
578     // Proceed only if decoding did not fail.
579     if (!readValue(exceptionThrown)) {
580       try {
581         assert(!decodedData.has_value() && "Decoded this band already?");
582         decodedData = decode();
583       } catch (const RawspeedException& err) {
584         // Propagate the exception out of OpenMP magic.
585         errLog.setError(err.what());
586 #ifdef HAVE_OPENMP
587 #pragma omp atomic write
588 #endif
589       exceptionThrown = true;
590       }
591     }
592   }
593 }
594 
LowPassBand(Wavelet & wavelet_,ByteStream bs_,uint16_t lowpassPrecision_)595 VC5Decompressor::Wavelet::LowPassBand::LowPassBand(Wavelet& wavelet_,
596                                                    ByteStream bs_,
597                                                    uint16_t lowpassPrecision_)
598     : AbstractDecodeableBand(wavelet_, std::move(bs_)),
599       lowpassPrecision(lowpassPrecision_) {
600   // Low-pass band is a uncompressed version of the image, hugely downscaled.
601   // It consists of width * height pixels, `lowpassPrecision` each.
602   // We can easily check that we have sufficient amount of bits to decode it.
603   const auto waveletArea = iPoint2D(wavelet.width, wavelet.height).area();
604   const auto bitsTotal = waveletArea * lowpassPrecision;
605   const auto bytesTotal = roundUpDivision(bitsTotal, 8);
606   bs = bs.getStream(bytesTotal); // And clamp the size while we are at it.
607 }
608 
609 VC5Decompressor::BandData
decode() const610 VC5Decompressor::Wavelet::LowPassBand::decode() const noexcept {
611   BandData lowpass;
612   auto& band = lowpass.description;
613   band = Array2DRef<int16_t>::create(lowpass.storage, wavelet.width,
614                                      wavelet.height);
615 
616   BitPumpMSB bits(bs);
617   for (auto row = 0; row < band.height; ++row) {
618     for (auto col = 0; col < band.width; ++col)
619       band(row, col) = static_cast<int16_t>(bits.getBits(lowpassPrecision));
620   }
621 
622   return lowpass;
623 }
624 
625 VC5Decompressor::BandData
decode() const626 VC5Decompressor::Wavelet::HighPassBand::decode() const {
627   class DeRLVer final {
628     BitPumpMSB bits;
629     const int16_t quant;
630 
631     int16_t pixelValue = 0;
632     unsigned int numPixelsLeft = 0;
633 
634     void decodeNextPixelGroup() {
635       assert(numPixelsLeft == 0);
636       std::tie(pixelValue, numPixelsLeft) = getRLV(bits);
637     }
638 
639   public:
640     DeRLVer(const ByteStream& bs, int16_t quant_) : bits(bs), quant(quant_) {}
641 
642     void verifyIsAtEnd() {
643       if (numPixelsLeft != 0)
644         ThrowRDE("Not all pixels consumed?");
645       decodeNextPixelGroup();
646       static_assert(decompand(MARKER_BAND_END) == MARKER_BAND_END,
647                     "passthrough");
648       if (pixelValue != MARKER_BAND_END || numPixelsLeft != 0)
649         ThrowRDE("EndOfBand marker not found");
650     }
651 
652     int16_t decode() {
653       auto dequantize = [quant = quant](int16_t val) { return val * quant; };
654 
655       if (numPixelsLeft == 0) {
656         decodeNextPixelGroup();
657         pixelValue = dequantize(pixelValue);
658       }
659 
660       if (numPixelsLeft == 0)
661         ThrowRDE("Got EndOfBand marker while looking for next pixel");
662 
663       --numPixelsLeft;
664       return pixelValue;
665     }
666   };
667 
668   // decode highpass band
669   DeRLVer d(bs, quant);
670   BandData highpass;
671   auto& band = highpass.description;
672   band = Array2DRef<int16_t>::create(highpass.storage, wavelet.width,
673                                      wavelet.height);
674   for (int row = 0; row != wavelet.height; ++row)
675     for (int col = 0; col != wavelet.width; ++col)
676       band(row, col) = d.decode();
677   d.verifyIsAtEnd();
678   return highpass;
679 }
680 
parseLargeCodeblock(const ByteStream & bs)681 void VC5Decompressor::parseLargeCodeblock(const ByteStream& bs) {
682   static const auto subband_wavelet_index = []() {
683     std::array<int, numSubbands> wavelets;
684     int wavelet = 0;
685     for (auto i = wavelets.size() - 1; i > 0;) {
686       for (auto t = 0; t < numWaveletLevels; t++) {
687         wavelets[i] = wavelet;
688         i--;
689       }
690       if (i > 0)
691         wavelet++;
692     }
693     wavelets.front() = wavelet;
694     return wavelets;
695   }();
696   static const auto subband_band_index = []() {
697     std::array<int, numSubbands> bands;
698     bands.front() = 0;
699     for (auto i = 1U; i < bands.size();) {
700       for (int t = 1; t <= numWaveletLevels;) {
701         bands[i] = t;
702         t++;
703         i++;
704       }
705     }
706     return bands;
707   }();
708 
709   if (!mVC5.iSubband.has_value())
710     ThrowRDE("Did not see VC5Tag::SubbandNumber yet");
711 
712   const int idx = subband_wavelet_index[*mVC5.iSubband];
713   const int band = subband_band_index[*mVC5.iSubband];
714 
715   auto& wavelets = channels[mVC5.iChannel].wavelets;
716 
717   Wavelet& wavelet = wavelets[1 + idx];
718   if (wavelet.isBandValid(band)) {
719     ThrowRDE("Band %u for wavelet %u on channel %u was already seen", band, idx,
720              mVC5.iChannel);
721   }
722 
723   std::unique_ptr<Wavelet::AbstractBand>& dstBand = wavelet.bands[band];
724   if (mVC5.iSubband == 0) {
725     assert(band == 0);
726     // low-pass band, only one, for the smallest wavelet, per channel per image
727     if (!mVC5.lowpassPrecision.has_value())
728       ThrowRDE("Did not see VC5Tag::LowpassPrecision yet");
729     dstBand = std::make_unique<Wavelet::LowPassBand>(wavelet, bs,
730                                                      *mVC5.lowpassPrecision);
731     mVC5.lowpassPrecision.reset();
732   } else {
733     if (!mVC5.quantization.has_value())
734       ThrowRDE("Did not see VC5Tag::Quantization yet");
735     dstBand = std::make_unique<Wavelet::HighPassBand>(wavelet, bs,
736                                                       *mVC5.quantization);
737     mVC5.quantization.reset();
738   }
739   wavelet.setBandValid(band);
740 
741   // If this wavelet is fully specified, mark the low-pass band of the
742   // next lower wavelet as specified.
743   if (wavelet.allBandsValid()) {
744     Wavelet& nextWavelet = wavelets[idx];
745     assert(!nextWavelet.isBandValid(0));
746     bool finalWavelet = idx == 0;
747     nextWavelet.bands[0] = std::make_unique<Wavelet::ReconstructableBand>(
748         wavelet, /*clampUint=*/finalWavelet, finalWavelet);
749     nextWavelet.setBandValid(0);
750   }
751 
752   mVC5.iSubband.reset();
753 }
754 
createWaveletBandDecodingTasks(bool & exceptionThrown) const755 void VC5Decompressor::createWaveletBandDecodingTasks(
756     bool& exceptionThrown) const noexcept {
757   for (int waveletLevel = numWaveletLevels; waveletLevel >= 0; waveletLevel--) {
758     const int numBandsInCurrentWavelet =
759         waveletLevel == 0 ? 1 : Wavelet::maxBands;
760     for (int bandId = 0; bandId != numBandsInCurrentWavelet; ++bandId) {
761       for (const auto& channel : channels) {
762         channel.wavelets[waveletLevel].bands[bandId]->createDecodingTasks(
763             static_cast<ErrorLog&>(*mRaw), exceptionThrown);
764       }
765     }
766   }
767 }
768 
decodeThread(bool & exceptionThrown) const769 void VC5Decompressor::decodeThread(bool& exceptionThrown) const noexcept {
770 #ifdef HAVE_OPENMP
771 #pragma omp taskgroup
772 #pragma omp single
773 #endif
774   createWaveletBandDecodingTasks(exceptionThrown);
775 
776   // Proceed only if decoding did not fail.
777   if (!readValue(exceptionThrown)) {
778     // And finally!
779     combineFinalLowpassBands();
780   }
781 }
782 
decode(unsigned int offsetX,unsigned int offsetY,unsigned int width,unsigned int height)783 void VC5Decompressor::decode(unsigned int offsetX, unsigned int offsetY,
784                              unsigned int width, unsigned int height) {
785   if (offsetX || offsetY || mRaw->dim != iPoint2D(width, height))
786     ThrowRDE("VC5Decompressor expects to fill the whole image, not some tile.");
787 
788   initVC5LogTable();
789 
790   alignas(RAWSPEED_CACHELINESIZE) bool exceptionThrown = false;
791 
792 #ifdef HAVE_OPENMP
793 #pragma omp parallel default(none) shared(exceptionThrown)                     \
794     num_threads(rawspeed_get_number_of_processor_cores())
795 #endif
796   decodeThread(exceptionThrown);
797 
798   std::string firstErr;
799   if (mRaw->isTooManyErrors(1, &firstErr)) {
800     assert(exceptionThrown);
801     ThrowRDE("Too many errors encountered. Giving up. First Error:\n%s",
802              firstErr.c_str());
803   } else {
804     assert(!exceptionThrown);
805   }
806 }
807 
combineFinalLowpassBands() const808 void VC5Decompressor::combineFinalLowpassBands() const noexcept {
809   const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());
810 
811   const int width = out.width / 2;
812   const int height = out.height / 2;
813 
814   assert(channels[0].wavelets[0].bands[0]->data.has_value() &&
815          channels[1].wavelets[0].bands[0]->data.has_value() &&
816          channels[2].wavelets[0].bands[0]->data.has_value() &&
817          channels[3].wavelets[0].bands[0]->data.has_value() &&
818          "Failed to reconstruct all final lowpass bands?");
819 
820   const Array2DRef<const int16_t> lowbands0 =
821       channels[0].wavelets[0].bands[0]->data->description;
822   const Array2DRef<const int16_t> lowbands1 =
823       channels[1].wavelets[0].bands[0]->data->description;
824   const Array2DRef<const int16_t> lowbands2 =
825       channels[2].wavelets[0].bands[0]->data->description;
826   const Array2DRef<const int16_t> lowbands3 =
827       channels[3].wavelets[0].bands[0]->data->description;
828 
829   // Convert to RGGB output
830 #ifdef HAVE_OPENMP
831 #pragma omp for schedule(static)
832 #endif
833   for (int row = 0; row < height; ++row) {
834     for (int col = 0; col < width; ++col) {
835       const int mid = 2048;
836 
837       int gs = lowbands0(row, col);
838       int rg = lowbands1(row, col) - mid;
839       int bg = lowbands2(row, col) - mid;
840       int gd = lowbands3(row, col) - mid;
841 
842       int r = gs + 2 * rg;
843       int b = gs + 2 * bg;
844       int g1 = gs + gd;
845       int g2 = gs - gd;
846 
847       out(2 * row + 0, 2 * col + 0) = static_cast<uint16_t>(mVC5LogTable[r]);
848       out(2 * row + 0, 2 * col + 1) = static_cast<uint16_t>(mVC5LogTable[g1]);
849       out(2 * row + 1, 2 * col + 0) = static_cast<uint16_t>(mVC5LogTable[g2]);
850       out(2 * row + 1, 2 * col + 1) = static_cast<uint16_t>(mVC5LogTable[b]);
851     }
852   }
853 }
854 
855 inline std::pair<int16_t /*value*/, unsigned int /*count*/>
getRLV(BitPumpMSB & bits)856 VC5Decompressor::getRLV(BitPumpMSB& bits) {
857   unsigned int iTab;
858 
859   static constexpr auto maxBits = 1 + table17.entries[table17.length - 1].size;
860 
861   // Ensure the maximum number of bits are cached to make peekBits() as fast as
862   // possible.
863   bits.fill(maxBits);
864   for (iTab = 0; iTab < table17.length; ++iTab) {
865     if (decompandedTable17[iTab].bits ==
866         bits.peekBitsNoFill(decompandedTable17[iTab].size))
867       break;
868   }
869   if (iTab >= table17.length)
870     ThrowRDE("Code not found in codebook");
871 
872   bits.skipBitsNoFill(decompandedTable17[iTab].size);
873   int16_t value = decompandedTable17[iTab].value;
874   unsigned int count = decompandedTable17[iTab].count;
875   if (value != 0 && bits.getBitsNoFill(1))
876     value = -value;
877 
878   return {value, count};
879 }
880 
881 } // namespace rawspeed
882