summaryrefslogtreecommitdiff
path: root/src/external/rawspeed/src/librawspeed/decompressors/NikonDecompressor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/external/rawspeed/src/librawspeed/decompressors/NikonDecompressor.cpp')
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/NikonDecompressor.cpp434
1 files changed, 379 insertions, 55 deletions
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/NikonDecompressor.cpp b/src/external/rawspeed/src/librawspeed/decompressors/NikonDecompressor.cpp
index d8c0d7962..f07a60f81 100644
--- a/src/external/rawspeed/src/librawspeed/decompressors/NikonDecompressor.cpp
+++ b/src/external/rawspeed/src/librawspeed/decompressors/NikonDecompressor.cpp
@@ -19,44 +19,352 @@
*/
#include "decompressors/NikonDecompressor.h"
-#include "common/Common.h" // for uint32, ushort16, clampBits
+#include "common/Common.h" // for uint32, clampBits, ushort16
#include "common/Point.h" // for iPoint2D
-#include "common/RawImage.h" // for RawImage, RawImageData, RawI...
+#include "common/RawImage.h" // for RawImage, RawImageData
#include "decoders/RawDecoderException.h" // for ThrowRDE
#include "decompressors/HuffmanTable.h" // for HuffmanTable
-#include "io/BitPumpMSB.h" // for BitPumpMSB, BitStream<>::fil...
+#include "io/BitPumpMSB.h" // for BitPumpMSB, BitStream<>::f...
#include "io/Buffer.h" // for Buffer
#include "io/ByteStream.h" // for ByteStream
-#include <cstdio> // for size_t, NULL
-#include <vector> // for vector, allocator
+#include <cassert> // for assert
+#include <cstdio> // for size_t
+#include <vector> // for vector
namespace rawspeed {
-const uchar8 NikonDecompressor::nikon_tree[][2][16] = {
- {/* 12-bit lossy */
- {0, 1, 5, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0},
- {5, 4, 3, 6, 2, 7, 1, 0, 8, 9, 11, 10, 12}},
- {/* 12-bit lossy after split */
- {0, 1, 5, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0},
- {0x39, 0x5a, 0x38, 0x27, 0x16, 5, 4, 3, 2, 1, 0, 11, 12, 12}},
- {/* 12-bit lossless */
- {0, 1, 4, 2, 3, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {5, 4, 6, 3, 7, 2, 8, 1, 9, 0, 10, 11, 12}},
- {/* 14-bit lossy */
- {0, 1, 4, 3, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0},
- {5, 6, 4, 7, 8, 3, 9, 2, 1, 0, 10, 11, 12, 13, 14}},
- {/* 14-bit lossy after split */
- {0, 1, 5, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0},
- {8, 0x5c, 0x4b, 0x3a, 0x29, 7, 6, 5, 4, 3, 2, 1, 0, 13, 14}},
- {/* 14-bit lossless */
- {0, 1, 4, 2, 2, 3, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0},
- {7, 6, 8, 5, 9, 4, 10, 3, 11, 12, 2, 0, 1, 13, 14}},
+const std::array<std::array<std::array<uchar8, 16>, 2>, 6>
+ NikonDecompressor::nikon_tree = {{
+ {{/* 12-bit lossy */
+ {0, 1, 5, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0},
+ {5, 4, 3, 6, 2, 7, 1, 0, 8, 9, 11, 10, 12}}},
+ {{/* 12-bit lossy after split */
+ {0, 1, 5, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0},
+ {0x39, 0x5a, 0x38, 0x27, 0x16, 5, 4, 3, 2, 1, 0, 11, 12, 12}}},
+ {{/* 12-bit lossless */
+ {0, 1, 4, 2, 3, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {5, 4, 6, 3, 7, 2, 8, 1, 9, 0, 10, 11, 12}}},
+ {{/* 14-bit lossy */
+ {0, 1, 4, 3, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0},
+ {5, 6, 4, 7, 8, 3, 9, 2, 1, 0, 10, 11, 12, 13, 14}}},
+ {{/* 14-bit lossy after split */
+ {0, 1, 5, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0},
+ {8, 0x5c, 0x4b, 0x3a, 0x29, 7, 6, 5, 4, 3, 2, 1, 0, 13, 14}}},
+ {{/* 14-bit lossless */
+ {0, 1, 4, 2, 2, 3, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0},
+ {7, 6, 8, 5, 9, 4, 10, 3, 11, 12, 2, 0, 1, 13, 14}}},
+ }};
+
+namespace {
+
+const std::array<uint32, 32> bitMask = {
+ {0xffffffff, 0x7fffffff, 0x3fffffff, 0x1fffffff, 0x0fffffff, 0x07ffffff,
+ 0x03ffffff, 0x01ffffff, 0x00ffffff, 0x007fffff, 0x003fffff, 0x001fffff,
+ 0x000fffff, 0x0007ffff, 0x0003ffff, 0x0001ffff, 0x0000ffff, 0x00007fff,
+ 0x00003fff, 0x00001fff, 0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff,
+ 0x000000ff, 0x0000007f, 0x0000003f, 0x0000001f, 0x0000000f, 0x00000007,
+ 0x00000003, 0x00000001}};
+
+class NikonLASDecompressor {
+ bool mUseBigtable = true;
+ bool mDNGCompatible = false;
+
+ struct HuffmanTable {
+ /*
+ * These two fields directly represent the contents of a JPEG DHT
+ * marker
+ */
+ std::array<uint32, 17> bits;
+ std::array<uint32, 256> huffval;
+
+ /*
+ * The remaining fields are computed from the above to allow more
+ * efficient coding and decoding. These fields should be considered
+ * private to the Huffman compression & decompression modules.
+ */
+
+ std::array<ushort16, 17> mincode;
+ std::array<int, 18> maxcode;
+ std::array<short, 17> valptr;
+ std::array<uint32, 256> numbits;
+ std::vector<int> bigTable;
+ bool initialized;
+ } dctbl1;
+
+ void createHuffmanTable() {
+ int p;
+ int i;
+ int l;
+ int lastp;
+ int si;
+ std::array<char, 257> huffsize;
+ std::array<ushort16, 257> huffcode;
+ ushort16 code;
+ int size;
+ int value;
+ int ll;
+ int ul;
+
+ /*
+ * Figure C.1: make table of Huffman code length for each symbol
+ * Note that this is in code-length order.
+ */
+ p = 0;
+ for (l = 1; l <= 16; l++) {
+ for (i = 1; i <= static_cast<int>(dctbl1.bits[l]); i++) {
+ huffsize[p++] = static_cast<char>(l);
+ if (p > 256)
+ ThrowRDE("LJpegDecompressor::createHuffmanTable: Code length too "
+ "long. Corrupt data.");
+ }
+ }
+ huffsize[p] = 0;
+ lastp = p;
+
+ /*
+ * Figure C.2: generate the codes themselves
+ * Note that this is in code-length order.
+ */
+ code = 0;
+ si = huffsize[0];
+ p = 0;
+ while (huffsize[p]) {
+ while ((static_cast<int>(huffsize[p])) == si) {
+ huffcode[p++] = code;
+ code++;
+ }
+ code <<= 1;
+ si++;
+ if (p > 256)
+ ThrowRDE("createHuffmanTable: Code length too long. Corrupt data.");
+ }
+
+ /*
+ * Figure F.15: generate decoding tables
+ */
+ dctbl1.mincode[0] = 0;
+ dctbl1.maxcode[0] = 0;
+ p = 0;
+ for (l = 1; l <= 16; l++) {
+ if (dctbl1.bits[l]) {
+ dctbl1.valptr[l] = p;
+ dctbl1.mincode[l] = huffcode[p];
+ p += dctbl1.bits[l];
+ dctbl1.maxcode[l] = huffcode[p - 1];
+ } else {
+ dctbl1.valptr[l] =
+ 0xff; // This check must be present to avoid crash on junk
+ dctbl1.maxcode[l] = -1;
+ }
+ if (p > 256)
+ ThrowRDE("createHuffmanTable: Code length too long. Corrupt data.");
+ }
+
+ /*
+ * We put in this value to ensure HuffDecode terminates.
+ */
+ dctbl1.maxcode[17] = 0xFFFFFL;
+
+ /*
+ * Build the numbits, value lookup tables.
+ * These table allow us to gather 8 bits from the bits stream,
+ * and immediately lookup the size and value of the huffman codes.
+ * If size is zero, it means that more than 8 bits are in the huffman
+ * code (this happens about 3-4% of the time).
+ */
+ dctbl1.numbits.fill(0);
+ for (p = 0; p < lastp; p++) {
+ size = huffsize[p];
+ if (size <= 8) {
+ value = dctbl1.huffval[p];
+ code = huffcode[p];
+ ll = code << (8 - size);
+ if (size < 8) {
+ ul = ll | bitMask[24 + size];
+ } else {
+ ul = ll;
+ }
+ if (ul > 256 || ll > ul)
+ ThrowRDE("createHuffmanTable: Code length too long. Corrupt data.");
+ for (i = ll; i <= ul; i++) {
+ dctbl1.numbits[i] = size | (value << 4);
+ }
+ }
+ }
+ if (mUseBigtable)
+ createBigTable();
+ dctbl1.initialized = true;
+ }
+
+ /************************************
+ * Bitable creation
+ *
+ * This is expanding the concept of fast lookups
+ *
+ * A complete table for 14 arbitrary bits will be
+ * created that enables fast lookup of number of bits used,
+ * and final delta result.
+ * Hit rate is about 90-99% for typical LJPEGS, usually about 98%
+ *
+ ************************************/
+
+ void createBigTable() {
+ const uint32 bits =
+ 14; // HuffDecode functions must be changed, if this is modified.
+ const uint32 size = 1 << bits;
+ int rv = 0;
+ int temp;
+ uint32 l;
+
+ dctbl1.bigTable.resize(size);
+ for (uint32 i = 0; i < size; i++) {
+ ushort16 input = i << 2; // Calculate input value
+ int code = input >> 8; // Get 8 bits
+ uint32 val = dctbl1.numbits[code];
+ l = val & 15;
+ if (l) {
+ rv = val >> 4;
+ } else {
+ l = 8;
+ while (code > dctbl1.maxcode[l]) {
+ temp = input >> (15 - l) & 1;
+ code = (code << 1) | temp;
+ l++;
+ }
+
+ /*
+ * With garbage input we may reach the sentinel value l = 17.
+ */
+
+ if (l > 16 || dctbl1.valptr[l] == 0xff) {
+ dctbl1.bigTable[i] = 0xff;
+ continue;
+ }
+ rv = dctbl1.huffval[dctbl1.valptr[l] + (code - dctbl1.mincode[l])];
+ }
+
+ if (rv == 16) {
+ if (mDNGCompatible)
+ dctbl1.bigTable[i] = (-(32768 << 8)) | (16 + l);
+ else
+ dctbl1.bigTable[i] = (-(32768 << 8)) | l;
+ continue;
+ }
+
+ if (rv + l > bits) {
+ dctbl1.bigTable[i] = 0xff;
+ continue;
+ }
+
+ if (rv) {
+ int x = input >> (16 - l - rv) & ((1 << rv) - 1);
+ if ((x & (1 << (rv - 1))) == 0)
+ x -= (1 << rv) - 1;
+ dctbl1.bigTable[i] =
+ static_cast<int>((static_cast<unsigned>(x) << 8) | (l + rv));
+ } else {
+ dctbl1.bigTable[i] = l;
+ }
+ }
+ }
+
+public:
+ uint32 setNCodesPerLength(const Buffer& data) {
+ uint32 acc = 0;
+ for (uint32 i = 0; i < 16; i++) {
+ dctbl1.bits[i + 1] = data[i];
+ acc += dctbl1.bits[i + 1];
+ }
+ dctbl1.bits[0] = 0;
+ return acc;
+ }
+
+ void setCodeValues(const Buffer& data) {
+ for (uint32 i = 0; i < data.getSize(); i++)
+ dctbl1.huffval[i] = data[i];
+ }
+
+ void setup(bool fullDecode_, bool fixDNGBug16_) { createHuffmanTable(); }
+
+ /*
+ *--------------------------------------------------------------
+ *
+ * HuffDecode --
+ *
+ * Taken from Figure F.16: extract next coded symbol from
+ * input stream. This should becode a macro.
+ *
+ * Results:
+ * Next coded symbol
+ *
+ * Side effects:
+ * Bitstream is parsed.
+ *
+ *--------------------------------------------------------------
+ */
+ int decodeNext(BitPumpMSB& bits) { // NOLINT: google-runtime-references
+ int rv;
+ int l;
+ int temp;
+ int code;
+ unsigned val;
+
+ bits.fill();
+ code = bits.peekBitsNoFill(14);
+ val = static_cast<unsigned>(dctbl1.bigTable[code]);
+ if ((val & 0xff) != 0xff) {
+ bits.skipBitsNoFill(val & 0xff);
+ return static_cast<int>(val) >> 8;
+ }
+ rv = 0;
+ code = bits.peekBitsNoFill(8);
+ val = dctbl1.numbits[code];
+ l = val & 15;
+ if (l) {
+ bits.skipBitsNoFill(l);
+ rv = static_cast<int>(val) >> 4;
+ } else {
+ bits.skipBits(8);
+ l = 8;
+ while (code > dctbl1.maxcode[l]) {
+ temp = bits.getBitsNoFill(1);
+ code = (code << 1) | temp;
+ l++;
+ }
+
+ if (l > 16) {
+ ThrowRDE("Corrupt JPEG data: bad Huffman code:%u\n", l);
+ } else {
+ rv = dctbl1.huffval[dctbl1.valptr[l] + (code - dctbl1.mincode[l])];
+ }
+ }
+
+ if (rv == 16)
+ return -32768;
+
+ /*
+ * Section F.2.2.1: decode the difference and
+ * Figure F.12: extend sign bit
+ */
+ uint32 len = rv & 15;
+ uint32 shl = rv >> 4;
+ int diff = ((bits.getBits(len - shl) << 1) + 1) << shl >> 1;
+ if ((diff & (1 << (len - 1))) == 0)
+ diff -= (1 << len) - !shl;
+ return diff;
+ }
};
+} // namespace
+
std::vector<ushort16> NikonDecompressor::createCurve(ByteStream* metadata,
uint32 bitsPS, uint32 v0,
uint32 v1, uint32* split) {
+ // Nikon Z7 12/14 bit compressed hack.
+ if (v0 == 68 && v1 == 64)
+ bitsPS -= 2;
+
// 'curve' will hold a peace wise linearly interpolated function.
// there are 'csize' segments, each is 'step' values long.
// the very last value is not part of the used table but necessary
@@ -73,7 +381,7 @@ std::vector<ushort16> NikonDecompressor::createCurve(ByteStream* metadata,
if (csize > 1)
step = curve.size() / (csize - 1);
- if (v0 == 68 && v1 == 32 && step > 0) {
+ if (v0 == 68 && (v1 == 32 || v1 == 64) && step > 0) {
if ((csize - 1) * step != curve.size() - 1)
ThrowRDE("Bad curve segment count (%u)", csize);
@@ -114,15 +422,18 @@ std::vector<ushort16> NikonDecompressor::createCurve(ByteStream* metadata,
return curve;
}
-HuffmanTable NikonDecompressor::createHuffmanTable(uint32 huffSelect) {
- HuffmanTable ht;
- uint32 count = ht.setNCodesPerLength(Buffer(nikon_tree[huffSelect][0], 16));
- ht.setCodeValues(Buffer(nikon_tree[huffSelect][1], count));
+template <typename Huffman>
+Huffman NikonDecompressor::createHuffmanTable(uint32 huffSelect) {
+ Huffman ht;
+ uint32 count =
+ ht.setNCodesPerLength(Buffer(nikon_tree[huffSelect][0].data(), 16));
+ ht.setCodeValues(Buffer(nikon_tree[huffSelect][1].data(), count));
ht.setup(true, false);
return ht;
}
-NikonDecompressor::NikonDecompressor(const RawImage& raw, uint32 bitsPS_)
+NikonDecompressor::NikonDecompressor(const RawImage& raw, ByteStream metadata,
+ uint32 bitsPS_)
: mRaw(raw), bitsPS(bitsPS_) {
if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
mRaw->getBpp() != 2)
@@ -140,18 +451,9 @@ NikonDecompressor::NikonDecompressor(const RawImage& raw, uint32 bitsPS_)
default:
ThrowRDE("Invalid bpp found: %u", bitsPS);
}
-}
-
-void NikonDecompressor::decompress(ByteStream metadata, const ByteStream& data,
- bool uncorrectedRawValues) {
- const iPoint2D& size = mRaw->dim;
uint32 v0 = metadata.getByte();
uint32 v1 = metadata.getByte();
- uint32 huffSelect = 0;
- uint32 split = 0;
- int pUp1[2];
- int pUp2[2];
writeLog(DEBUG_PRIO_EXTRA, "Nef version v0:%u, v1:%u", v0, v1);
@@ -168,33 +470,36 @@ void NikonDecompressor::decompress(ByteStream metadata, const ByteStream& data,
pUp2[0] = metadata.getU16();
pUp2[1] = metadata.getU16();
- HuffmanTable ht = createHuffmanTable(huffSelect);
+ curve = createCurve(&metadata, bitsPS, v0, v1, &split);
- auto curve = createCurve(&metadata, bitsPS, v0, v1, &split);
- RawImageCurveGuard curveHandler(&mRaw, curve, uncorrectedRawValues);
+ // If the 'split' happens outside of the image, it does not actually happen.
+ if (split >= static_cast<unsigned>(mRaw->dim.y))
+ split = 0;
+}
+
+template <typename Huffman>
+void NikonDecompressor::decompress(BitPumpMSB* bits, int start_y, int end_y) {
+ Huffman ht = createHuffmanTable<Huffman>(huffSelect);
- BitPumpMSB bits(data);
uchar8* draw = mRaw->getData();
uint32 pitch = mRaw->pitch;
int pLeft1 = 0;
int pLeft2 = 0;
- uint32 random = bits.peekBits(24);
- //allow gcc to devirtualize the calls below
+
+ // allow gcc to devirtualize the calls below
auto* rawdata = reinterpret_cast<RawImageDataU16*>(mRaw.get());
+ const iPoint2D& size = mRaw->dim;
assert(size.x % 2 == 0);
assert(size.x >= 2);
- for (uint32 y = 0; y < static_cast<unsigned>(size.y); y++) {
- if (split && y == split) {
- ht = createHuffmanTable(huffSelect + 1);
- }
+ for (uint32 y = start_y; y < static_cast<uint32>(end_y); y++) {
auto* dest =
reinterpret_cast<ushort16*>(&draw[y * pitch]); // Adjust destination
- pUp1[y&1] += ht.decodeNext(bits);
- pUp2[y&1] += ht.decodeNext(bits);
- pLeft1 = pUp1[y&1];
- pLeft2 = pUp2[y&1];
+ pUp1[y & 1] += ht.decodeNext(*bits);
+ pUp2[y & 1] += ht.decodeNext(*bits);
+ pLeft1 = pUp1[y & 1];
+ pLeft2 = pUp2[y & 1];
rawdata->setWithLookUp(clampBits(pLeft1, 15),
reinterpret_cast<uchar8*>(dest + 0), &random);
@@ -204,8 +509,8 @@ void NikonDecompressor::decompress(ByteStream metadata, const ByteStream& data,
dest += 2;
for (uint32 x = 2; x < static_cast<uint32>(size.x); x += 2) {
- pLeft1 += ht.decodeNext(bits);
- pLeft2 += ht.decodeNext(bits);
+ pLeft1 += ht.decodeNext(*bits);
+ pLeft2 += ht.decodeNext(*bits);
rawdata->setWithLookUp(clampBits(pLeft1, 15),
reinterpret_cast<uchar8*>(dest + 0), &random);
@@ -217,4 +522,23 @@ void NikonDecompressor::decompress(ByteStream metadata, const ByteStream& data,
}
}
+void NikonDecompressor::decompress(const ByteStream& data,
+ bool uncorrectedRawValues) {
+ RawImageCurveGuard curveHandler(&mRaw, curve, uncorrectedRawValues);
+
+ BitPumpMSB bits(data);
+
+ random = bits.peekBits(24);
+
+ assert(split == 0 || split < static_cast<unsigned>(mRaw->dim.y));
+
+ if (!split) {
+ decompress<HuffmanTable>(&bits, 0, mRaw->dim.y);
+ } else {
+ decompress<HuffmanTable>(&bits, 0, split);
+ huffSelect += 1;
+ decompress<NikonLASDecompressor>(&bits, split, mRaw->dim.y);
+ }
+}
+
} // namespace rawspeed