RawSpeed
fast raw decoding library
Loading...
Searching...
No Matches
OlympusDecompressor.cpp
Go to the documentation of this file.
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-2024 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
24#include "adt/Array2DRef.h"
25#include "adt/Bit.h"
26#include "adt/Casts.h"
27#include "adt/Invariant.h"
28#include "adt/Point.h"
30#include "common/RawImage.h"
31#include "common/SimpleLUT.h"
34#include "io/ByteStream.h"
35#include <algorithm>
36#include <array>
37#include <cassert>
38#include <cmath>
39#include <cstddef>
40#include <cstdint>
41#include <cstdlib>
42#include <utility>
43
44namespace rawspeed {
45
46namespace {
47
50
51 std::array<int, 3> carry{{}};
52
53public:
54 // NOLINTNEXTLINE(google-explicit-constructor)
57
59};
60
61inline __attribute__((always_inline)) int
63 bits.fill();
64
65 int numLowBitsBias = (carry[2] < 3) ? 2 : 0;
66 int numLowBits = numActiveBits(implicit_cast<uint16_t>(carry[0]));
67 numLowBits -= numLowBitsBias;
68 numLowBits = std::max(numLowBits, 2 + numLowBitsBias);
69 assert(numLowBits >= 2);
70 assert(numLowBits <= 14);
71
72 int b = bits.peekBitsNoFill(15);
73 int sign = (b >> 14) * -1;
74 int low = (b >> 12) & 3;
75 int numLeadingZeros = numLZ[b & 4095];
76
77 int highBits;
78 // Skip bytes used above or read bits
79 if (numLeadingZeros != 12) [[likely]] { // Happens in 99.9% of cases.
80 bits.skipBitsNoFill(numLeadingZeros + 1 + 3);
81 highBits = numLeadingZeros;
82 } else {
83 bits.skipBitsNoFill(15);
84 int numHighBits = 15 - numLowBits;
85 assert(numHighBits >= 1);
86 assert(numHighBits <= 13);
87 highBits = bits.peekBitsNoFill(numHighBits);
88 bits.skipBitsNoFill(1 + numHighBits);
89 }
90
91 carry[0] = (highBits << numLowBits) | bits.getBitsNoFill(numLowBits);
92 int diff = (carry[0] ^ sign) + carry[1];
93 carry[1] = (diff * 3 + carry[1]) >> 5;
94 carry[2] = carry[0] > 16 ? 0 : carry[2] + 1;
95
96 return (diff * 4) | low;
97}
98
101
102 // A table to quickly look up the number of leading zeros in a value.
104 [](size_t i, [[maybe_unused]] unsigned tableSize) {
105 return 12 - numActiveBits(i);
106 }};
107
108 static __attribute__((always_inline)) int getPred(Array2DRef<uint16_t> out,
109 int row, int col);
110
111 inline __attribute__((always_inline)) void
112 decompressGroup(std::array<OlympusDifferenceDecoder, 2>& acarry,
113 BitStreamerMSB& bits, int row, int group) const;
114
115 void decompressRow(BitStreamerMSB& bits, int row) const;
116
117public:
118 explicit OlympusDecompressorImpl(RawImage img) : mRaw(std::move(img)) {}
119
120 void decompress(ByteStream input) const;
121};
122
123/* This is probably the slowest decoder of them all.
124 * I cannot see any way to effectively speed up the prediction
125 * phase, which is by far the slowest part of this algorithm.
126 * Also there is no way to multithread this code, since prediction
127 * is based on the output of all previous pixel (bar the first four)
128 */
129
130inline __attribute__((always_inline)) int
131OlympusDecompressorImpl::getPred(const Array2DRef<uint16_t> out, int row,
132 int col) {
133 auto getLeft = [&]() { return out(row, col - 2); };
134 auto getUp = [&]() { return out(row - 2, col); };
135 auto getLeftUp = [&]() { return out(row - 2, col - 2); };
136
137 int pred;
138 if (row < 2 && col < 2)
139 pred = 0;
140 else if (row < 2)
141 pred = getLeft();
142 else if (col < 2)
143 pred = getUp();
144 else {
145 int left = getLeft();
146 int up = getUp();
147 int leftUp = getLeftUp();
148
149 int leftMinusNw = left - leftUp;
150 int upMinusNw = up - leftUp;
151
152 // Check if sign is different, and they are both not zero
153 if ((std::signbit(leftMinusNw) != std::signbit(upMinusNw)) &&
154 (leftMinusNw != 0 && upMinusNw != 0)) {
155 if (std::abs(leftMinusNw) > 32 || std::abs(upMinusNw) > 32)
156 pred = left + upMinusNw;
157 else
158 pred = (left + up) >> 1;
159 } else {
160 pred = std::abs(leftMinusNw) > std::abs(upMinusNw) ? left : up;
161 }
162 }
163
164 return pred;
165}
166
167inline __attribute__((always_inline)) void
168OlympusDecompressorImpl::decompressGroup(
169 std::array<OlympusDifferenceDecoder, 2>& acarry, BitStreamerMSB& bits,
170 int row, int group) const {
172
173 for (int c = 0; c != 2; ++c) {
174 const int col = (2 * group) + c;
175 OlympusDifferenceDecoder& carry = acarry[c];
176
177 int diff = carry.getDiff(bits);
178 int pred = getPred(out, row, col);
179
180 out(row, col) = implicit_cast<uint16_t>(pred + diff);
181 }
182}
183
184void OlympusDecompressorImpl::decompressRow(BitStreamerMSB& bits,
185 int row) const {
187
188 invariant(out.width() > 0);
189 invariant(out.width() % 2 == 0);
190
191 std::array<OlympusDifferenceDecoder, 2> acarry{numLZ, numLZ};
192
193 const int numGroups = out.width() / 2;
194 int group = 0;
195 {
196 // Process first group separately, allows to unswitch predictor calculation.
197 decompressGroup(acarry, bits, row, group);
198 ++group;
199 }
200 for (; group != numGroups; ++group) {
201 decompressGroup(acarry, bits, row, group);
202 }
203}
204
205void OlympusDecompressorImpl::decompress(ByteStream input) const {
206 invariant(mRaw->dim.y > 0);
207 invariant(mRaw->dim.x > 0);
208 invariant(mRaw->dim.x % 2 == 0);
209
211
212 for (int y = 0; y < mRaw->dim.y; y++)
213 decompressRow(bits, y);
214}
215
216} // namespace
217
219 if (mRaw->getCpp() != 1 || mRaw->getDataType() != RawImageType::UINT16 ||
220 mRaw->getBpp() != sizeof(uint16_t))
221 ThrowRDE("Unexpected component count / data type");
222
223 if (!mRaw->dim.hasPositiveArea() || mRaw->dim.x % 2 != 0 ||
224 mRaw->dim.y % 2 != 0 || mRaw->dim.x > 10400 || mRaw->dim.y > 7792)
225 ThrowRDE("Unexpected image dimensions found: (%d; %d)", mRaw->dim.x,
226 mRaw->dim.y);
227}
228
230 OlympusDecompressorImpl(mRaw).decompress(input);
231}
232
233} // namespace rawspeed
#define invariant(expr)
Definition Invariant.h:27
#define ThrowRDE(...)
bool RAWSPEED_READNONE __attribute__((visibility("default"))) benchmarkDryRun()
Definition Common.cpp:35
assert(dim.area() >=area)
dim y
Definition Common.cpp:51
Buffer peekRemainingBuffer() const
Definition ByteStream.h:108
int RAWSPEED_READONLY width() const
uint32_t getBitsNoFill(int nbits)
void skipBitsNoFill(int nbits)
uint32_t RAWSPEED_READONLY peekBitsNoFill(int nbits)
void fill(int nbits=Cache::MaxGetBits)
Array1DRef< const uint8_t > getAsArray1DRef() const
Definition Buffer.h:70
void decompress(const ByteStream &input) const
Array2DRef< uint16_t > getU16DataAsUncroppedArray2DRef() noexcept
Definition RawImage.h:290
__attribute__((always_inline)) void decompressGroup(std void decompressRow(BitStreamerMSB &bits, int row) const
static __attribute__((always_inline)) int getPred(Array2DRef< uint16_t > out
value_type x
Definition Point.h:102
value_type y
Definition Point.h:103
constexpr RAWSPEED_READNONE Ttgt implicit_cast(Tsrc value)
Definition Casts.h:32
unsigned numActiveBits(const T v)
Definition Bit.h:56
__attribute__((noinline)) __attribute__((visibility("default"))) JPEGStuffedByteStreamGenerator