/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 |