/src/librawspeed/src/librawspeed/decompressors/AbstractDngDecompressor.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | RawSpeed - RAW file decoder. |
3 | | |
4 | | Copyright (C) 2009-2014 Klaus Post |
5 | | Copyright (C) 2017-2018 Roman Lebeedv |
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 | | #include "rawspeedconfig.h" |
23 | | #include "decompressors/AbstractDngDecompressor.h" |
24 | | #include "adt/Array1DRef.h" |
25 | | #include "adt/Casts.h" |
26 | | #include "adt/Invariant.h" |
27 | | #include "adt/Point.h" |
28 | | #include "bitstreams/BitStreams.h" |
29 | | #include "common/Common.h" |
30 | | #include "common/RawImage.h" |
31 | | #include "decoders/RawDecoderException.h" |
32 | | #include "decompressors/LJpegDecoder.h" |
33 | | #include "decompressors/UncompressedDecompressor.h" |
34 | | #include "decompressors/VC5Decompressor.h" |
35 | | #include "io/ByteStream.h" |
36 | | #include "io/Endianness.h" |
37 | | #include "io/IOException.h" |
38 | | #include <cstdint> |
39 | | #include <limits> |
40 | | #include <string> |
41 | | #include <vector> |
42 | | |
43 | | #ifdef HAVE_ZLIB |
44 | | #include "decompressors/DeflateDecompressor.h" |
45 | | #include <memory> |
46 | | #endif |
47 | | |
48 | | #ifdef HAVE_JPEG |
49 | | #include "decompressors/JpegDecompressor.h" |
50 | | #endif |
51 | | |
52 | | namespace rawspeed { |
53 | | |
54 | 91.1k | template <> void AbstractDngDecompressor::decompressThread<1>() const noexcept { |
55 | 91.1k | #ifdef HAVE_OPENMP |
56 | 91.1k | #pragma omp for schedule(static) |
57 | 91.1k | #endif |
58 | 91.1k | for (const auto& e : |
59 | 91.1k | Array1DRef(slices.data(), implicit_cast<int>(slices.size()))) { |
60 | 91.1k | try { |
61 | 91.1k | iPoint2D tileSize(e.width, e.height); |
62 | 91.1k | iPoint2D pos(e.offX, e.offY); |
63 | | |
64 | 91.1k | bool big_endian = e.bs.getByteOrder() == Endianness::big; |
65 | | |
66 | | // DNG spec says that if not 8/16/32 bit/sample, always use big endian. |
67 | | // It's not very obvious, but that does not appear to apply to FP. |
68 | 91.1k | switch (mBps) { |
69 | 91.1k | case 8: |
70 | 91.1k | case 16: |
71 | 91.1k | case 32: |
72 | 91.1k | break; |
73 | 91.1k | default: |
74 | 91.1k | if (mRaw->getDataType() == RawImageType::UINT16) |
75 | 91.1k | big_endian = true; |
76 | 91.1k | break; |
77 | 91.1k | } |
78 | | |
79 | 91.1k | const uint32_t inputPixelBits = mRaw->getCpp() * mBps; |
80 | | |
81 | 91.1k | if (e.dsc.tileW > std::numeric_limits<int>::max() / inputPixelBits) |
82 | 91.1k | ThrowIOE("Integer overflow when calculating input pitch"); |
83 | | |
84 | 91.1k | const int inputPitchBits = inputPixelBits * e.dsc.tileW; |
85 | 91.1k | invariant(inputPitchBits > 0); |
86 | | |
87 | 91.1k | if (inputPitchBits % 8 != 0) { |
88 | 91.1k | ThrowRDE("Bad combination of cpp (%u), bps (%u) and width (%u), the " |
89 | 91.1k | "pitch is %u bits, which is not a multiple of 8 (1 byte)", |
90 | 91.1k | mRaw->getCpp(), mBps, e.width, inputPitchBits); |
91 | 91.1k | } |
92 | | |
93 | 91.1k | const int inputPitch = inputPitchBits / 8; |
94 | 91.1k | if (inputPitch == 0) |
95 | 91.1k | ThrowRDE("Data input pitch is too short. Can not decode!"); |
96 | | |
97 | 91.1k | UncompressedDecompressor decompressor( |
98 | 91.1k | e.bs, mRaw, iRectangle2D(pos, tileSize), inputPitch, mBps, |
99 | 91.1k | big_endian ? BitOrder::MSB : BitOrder::LSB); |
100 | 91.1k | decompressor.readUncompressedRaw(); |
101 | 91.1k | } catch (const RawDecoderException& err) { |
102 | 91.1k | mRaw->setError(err.what()); |
103 | 91.1k | } catch (const IOException& err) { |
104 | 91.1k | mRaw->setError(err.what()); |
105 | 91.1k | } catch (...) { |
106 | | // We should not get any other exception type here. |
107 | 91.1k | __builtin_unreachable(); |
108 | 91.1k | } |
109 | 91.1k | } |
110 | 91.1k | } |
111 | | |
112 | 30.9k | template <> void AbstractDngDecompressor::decompressThread<7>() const noexcept { |
113 | 30.9k | #ifdef HAVE_OPENMP |
114 | 30.9k | #pragma omp for schedule(static) |
115 | 30.9k | #endif |
116 | 30.9k | for (const auto& e : |
117 | 30.9k | Array1DRef(slices.data(), implicit_cast<int>(slices.size()))) { |
118 | 30.9k | try { |
119 | 30.9k | LJpegDecoder d(e.bs, mRaw); |
120 | 30.9k | d.decode(e.offX, e.offY, e.width, e.height, |
121 | 30.9k | iPoint2D(e.dsc.tileW, e.dsc.tileH), mFixLjpeg); |
122 | 30.9k | } catch (const RawDecoderException& err) { |
123 | 30.9k | mRaw->setError(err.what()); |
124 | 30.9k | } catch (const IOException& err) { |
125 | 30.9k | mRaw->setError(err.what()); |
126 | 30.9k | } catch (...) { |
127 | | // We should not get any other exception type here. |
128 | 30.9k | __builtin_unreachable(); |
129 | 30.9k | } |
130 | 30.9k | } |
131 | 30.9k | } |
132 | | |
133 | | #ifdef HAVE_ZLIB |
134 | | template <> void AbstractDngDecompressor::decompressThread<8>() const noexcept { |
135 | | // NOLINTNEXTLINE(modernize-avoid-c-arrays) |
136 | | std::unique_ptr<unsigned char[]> uBuffer; |
137 | | |
138 | | #ifdef HAVE_OPENMP |
139 | | #pragma omp for schedule(static) |
140 | | #endif |
141 | | for (const auto& e : |
142 | | Array1DRef(slices.data(), implicit_cast<int>(slices.size()))) { |
143 | | try { |
144 | | DeflateDecompressor z(e.bs.peekBuffer(e.bs.getRemainSize()), mRaw, |
145 | | mPredictor, mBps); |
146 | | z.decode(&uBuffer, iPoint2D(mRaw->getCpp() * e.dsc.tileW, e.dsc.tileH), |
147 | | iPoint2D(mRaw->getCpp() * e.width, e.height), |
148 | | iPoint2D(mRaw->getCpp() * e.offX, e.offY)); |
149 | | } catch (const RawDecoderException& err) { |
150 | | mRaw->setError(err.what()); |
151 | | } catch (const IOException& err) { |
152 | | mRaw->setError(err.what()); |
153 | | } catch (...) { |
154 | | // We should not get any other exception type here. |
155 | | __builtin_unreachable(); |
156 | | } |
157 | | } |
158 | | } |
159 | | #endif |
160 | | |
161 | 31.5k | template <> void AbstractDngDecompressor::decompressThread<9>() const noexcept { |
162 | 31.5k | #ifdef HAVE_OPENMP |
163 | 31.5k | #pragma omp for schedule(static) |
164 | 31.5k | #endif |
165 | 31.5k | for (const auto& e : |
166 | 31.5k | Array1DRef(slices.data(), implicit_cast<int>(slices.size()))) { |
167 | 31.5k | try { |
168 | 31.5k | VC5Decompressor d(e.bs, mRaw); |
169 | 31.5k | d.decode(e.offX, e.offY, e.width, e.height); |
170 | 31.5k | } catch (const RawDecoderException& err) { |
171 | 31.5k | mRaw->setError(err.what()); |
172 | 31.5k | } catch (const IOException& err) { |
173 | 31.5k | mRaw->setError(err.what()); |
174 | 31.5k | } catch (...) { |
175 | | // We should not get any other exception type here. |
176 | 31.5k | __builtin_unreachable(); |
177 | 31.5k | } |
178 | 31.5k | } |
179 | 31.5k | } |
180 | | |
181 | | #ifdef HAVE_JPEG |
182 | | template <> |
183 | | void AbstractDngDecompressor::decompressThread<0x884c>() const noexcept { |
184 | | #ifdef HAVE_OPENMP |
185 | | #pragma omp for schedule(static) |
186 | | #endif |
187 | | for (const auto& e : |
188 | | Array1DRef(slices.data(), implicit_cast<int>(slices.size()))) { |
189 | | try { |
190 | | JpegDecompressor j(e.bs.peekBuffer(e.bs.getRemainSize()), mRaw); |
191 | | j.decode(e.offX, e.offY); |
192 | | } catch (const RawDecoderException& err) { |
193 | | mRaw->setError(err.what()); |
194 | | } catch (const IOException& err) { |
195 | | mRaw->setError(err.what()); |
196 | | } catch (...) { |
197 | | // We should not get any other exception type here. |
198 | | __builtin_unreachable(); |
199 | | } |
200 | | } |
201 | | } |
202 | | #endif |
203 | | |
204 | 39.8k | void AbstractDngDecompressor::decompressThread() const noexcept { |
205 | 39.8k | invariant(mRaw->dim.x > 0); |
206 | 39.9k | invariant(mRaw->dim.y > 0); |
207 | 39.0k | invariant(mRaw->getCpp() > 0 && mRaw->getCpp() <= 4); |
208 | 37.6k | invariant(mBps > 0 && mBps <= 32); |
209 | | |
210 | 37.7k | if (compression == 1) { |
211 | | /* Uncompressed */ |
212 | 14.1k | decompressThread<1>(); |
213 | 23.5k | } else if (compression == 7) { |
214 | | /* Lossless JPEG */ |
215 | 10.9k | decompressThread<7>(); |
216 | 12.6k | } else if (compression == 8) { |
217 | | /* Deflate compression */ |
218 | | #ifdef HAVE_ZLIB |
219 | | decompressThread<8>(); |
220 | | #else |
221 | 0 | #pragma message \ |
222 | 0 | "ZLIB is not present! Deflate compression will not be supported!" |
223 | 0 | mRaw->setError("deflate support is disabled."); |
224 | 0 | #endif |
225 | 12.6k | } else if (compression == 9) { |
226 | | /* GOPRO VC-5 */ |
227 | 12.6k | decompressThread<9>(); |
228 | 12.6k | } else if (compression == 0x884c) { |
229 | | /* Lossy DNG */ |
230 | | #ifdef HAVE_JPEG |
231 | | decompressThread<0x884c>(); |
232 | | #else |
233 | 0 | #pragma message "JPEG is not present! Lossy JPEG DNG will not be supported!" |
234 | 0 | mRaw->setError("jpeg support is disabled."); |
235 | 0 | #endif |
236 | 0 | } else |
237 | 16 | mRaw->setError("AbstractDngDecompressor: Unknown compression"); |
238 | 37.7k | } |
239 | | |
240 | 11.7k | void AbstractDngDecompressor::decompress() const { |
241 | 11.7k | #ifdef HAVE_OPENMP |
242 | 11.7k | #pragma omp parallel default(none) num_threads( \ |
243 | 11.7k | rawspeed_get_number_of_processor_cores()) if (slices.size() > 1) |
244 | 11.7k | #endif |
245 | 40.0k | decompressThread(); |
246 | | |
247 | 11.7k | std::string firstErr; |
248 | 11.7k | if (mRaw->isTooManyErrors(1, &firstErr)) { |
249 | 2.87k | ThrowRDE("Too many errors encountered. Giving up. First Error:\n%s", |
250 | 2.87k | firstErr.c_str()); |
251 | 2.87k | } |
252 | 11.7k | } |
253 | | |
254 | | } // namespace rawspeed |