Coverage Report

Created: 2024-09-08 06:18

/src/librawspeed/src/librawspeed/decompressors/PhaseOneDecompressor.cpp
Line
Count
Source
1
/*
2
    RawSpeed - RAW file decoder.
3
4
    Copyright (C) 2009-2014 Klaus Post
5
    Copyright (C) 2014-2015 Pedro CĂ´rte-Real
6
    Copyright (C) 2017-2018 Roman Lebedev
7
8
    This library is free software; you can redistribute it and/or
9
    modify it under the terms of the GNU Lesser General Public
10
    License as published by the Free Software Foundation; either
11
    version 2 of the License, or (at your option) any later version.
12
13
    This library is distributed in the hope that it will be useful,
14
    but WITHOUT ANY WARRANTY; without even the implied warranty of
15
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
    Lesser General Public License for more details.
17
18
    You should have received a copy of the GNU Lesser General Public
19
    License along with this library; if not, write to the Free Software
20
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
*/
22
23
#include "rawspeedconfig.h"
24
#include "decompressors/PhaseOneDecompressor.h"
25
#include "adt/Array1DRef.h"
26
#include "adt/Array2DRef.h"
27
#include "adt/Casts.h"
28
#include "adt/Invariant.h"
29
#include "adt/Point.h"
30
#include "bitstreams/BitStreamerMSB32.h"
31
#include "common/Common.h"
32
#include "common/RawImage.h"
33
#include "decoders/RawDecoderException.h"
34
#include <algorithm>
35
#include <array>
36
#include <cstdint>
37
#include <string>
38
#include <utility>
39
#include <vector>
40
41
namespace rawspeed {
42
43
PhaseOneDecompressor::PhaseOneDecompressor(RawImage img,
44
                                           std::vector<PhaseOneStrip>&& strips_)
45
4.82k
    : mRaw(std::move(img)), strips(std::move(strips_)) {
46
4.82k
  if (mRaw->getDataType() != RawImageType::UINT16)
47
4.82k
    ThrowRDE("Unexpected data type");
48
49
4.82k
  if (mRaw->getCpp() != 1 || mRaw->getBpp() != sizeof(uint16_t))
50
4.82k
    ThrowRDE("Unexpected cpp: %u", mRaw->getCpp());
51
52
4.81k
  if (!mRaw->dim.hasPositiveArea() || mRaw->dim.x % 2 != 0 ||
53
4.81k
      mRaw->dim.x > 11976 || mRaw->dim.y > 8854) {
54
111
    ThrowRDE("Unexpected image dimensions found: (%u; %u)", mRaw->dim.x,
55
111
             mRaw->dim.y);
56
111
  }
57
58
4.70k
  prepareStrips();
59
4.70k
}
60
61
4.70k
void PhaseOneDecompressor::prepareStrips() {
62
  // The 'strips' vector should contain exactly one element per row of image.
63
64
  // If the length is different, then the 'strips' vector is clearly incorrect.
65
4.70k
  if (strips.size() != static_cast<decltype(strips)::size_type>(mRaw->dim.y)) {
66
34
    ThrowRDE("Height (%u) vs strip count %zu mismatch", mRaw->dim.y,
67
34
             strips.size());
68
34
  }
69
70
  // Now, the strips in 'strips' vector aren't in order.
71
  // The 'decltype(strips)::value_type::n' is the row number of a strip.
72
  // We need to make sure that we have every row (0..mRaw->dim.y-1), once.
73
  // For that, first let's sort them to have monothonically increasting `n`.
74
  // This will also serialize the per-line outputting.
75
4.67k
  std::sort(
76
4.67k
      strips.begin(), strips.end(),
77
4.53M
      [](const PhaseOneStrip& a, const PhaseOneStrip& b) { return a.n < b.n; });
78
  // And now ensure that slice number matches the slice's row.
79
20.6k
  for (decltype(strips)::size_type i = 0; i < strips.size(); ++i)
80
17.3k
    if (static_cast<decltype(strips)::size_type>(strips[i].n) != i)
81
4.67k
      ThrowRDE("Strips validation issue.");
82
  // All good.
83
4.67k
}
84
85
15.0k
void PhaseOneDecompressor::decompressStrip(const PhaseOneStrip& strip) const {
86
15.0k
  const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());
87
88
15.0k
  invariant(out.width() > 0);
89
14.6k
  invariant(out.width() % 2 == 0);
90
91
14.6k
  static constexpr std::array<const int, 10> length = {8,  7, 6,  9,  11,
92
14.6k
                                                       10, 5, 12, 14, 13};
93
94
14.6k
  BitStreamerMSB32 pump(strip.bs.peekRemainingBuffer().getAsArray1DRef());
95
96
14.6k
  std::array<int32_t, 2> pred;
97
14.6k
  pred.fill(0);
98
14.6k
  std::array<int, 2> len;
99
14.6k
  const int row = strip.n;
100
2.10M
  for (int col = 0; col < out.width(); col++) {
101
2.09M
    pump.fill(32);
102
2.09M
    if (static_cast<unsigned>(col) >=
103
2.09M
        (out.width() & ~7U)) // last 'width % 8' pixels.
104
18.3k
      len[0] = len[1] = 14;
105
2.07M
    else if ((col & 7) == 0) {
106
534k
      for (int& i : len) {
107
534k
        int j = 0;
108
109
1.89M
        for (; j < 5; j++) {
110
1.66M
          if (pump.getBitsNoFill(1) != 0) {
111
305k
            if (col == 0)
112
305k
              ThrowRDE("Can not initialize lengths. Data is corrupt.");
113
114
            // else, we have previously initialized lengths, so we are fine
115
300k
            break;
116
305k
          }
117
1.66M
        }
118
119
528k
        invariant((col == 0 && j > 0) || col != 0);
120
526k
        if (j > 0)
121
378k
          i = length[2 * (j - 1) + pump.getBitsNoFill(1)];
122
526k
      }
123
270k
    }
124
125
2.08M
    int i = len[col & 1];
126
2.08M
    if (i == 14) {
127
1.05M
      pred[col & 1] = pump.getBitsNoFill(16);
128
1.05M
      out(row, col) = implicit_cast<uint16_t>(pred[col & 1]);
129
1.05M
    } else {
130
1.02M
      pred[col & 1] +=
131
1.02M
          static_cast<signed>(pump.getBitsNoFill(i)) + 1 - (1 << (i - 1));
132
      // FIXME: is the truncation the right solution here?
133
1.02M
      out(row, col) = uint16_t(pred[col & 1]);
134
1.02M
    }
135
2.08M
  }
136
14.6k
}
137
138
229k
void PhaseOneDecompressor::decompressThread() const noexcept {
139
229k
#ifdef HAVE_OPENMP
140
229k
#pragma omp for schedule(static)
141
229k
#endif
142
229k
  for (const auto& strip :
143
229k
       Array1DRef(strips.data(), implicit_cast<int>(strips.size()))) {
144
229k
    try {
145
229k
      decompressStrip(strip);
146
229k
    } catch (const RawspeedException& err) {
147
      // Propagate the exception out of OpenMP magic.
148
229k
      mRaw->setError(err.what());
149
229k
    } catch (...) {
150
      // We should not get any other exception type here.
151
229k
      __builtin_unreachable();
152
229k
    }
153
229k
  }
154
229k
}
155
156
3.25k
void PhaseOneDecompressor::decompress() const {
157
3.25k
#ifdef HAVE_OPENMP
158
3.25k
#pragma omp parallel default(none)                                             \
159
3.25k
    num_threads(rawspeed_get_number_of_processor_cores())
160
3.25k
#endif
161
97.9k
  decompressThread();
162
163
3.25k
  std::string firstErr;
164
3.25k
  if (mRaw->isTooManyErrors(1, &firstErr)) {
165
1.38k
    ThrowRDE("Too many errors encountered. Giving up. First Error:\n%s",
166
1.38k
             firstErr.c_str());
167
1.38k
  }
168
3.25k
}
169
170
} // namespace rawspeed