diff options
Diffstat (limited to 'src/external/rawspeed/src/librawspeed/decompressors/NikonDecompressor.cpp')
-rw-r--r-- | src/external/rawspeed/src/librawspeed/decompressors/NikonDecompressor.cpp | 434 |
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 |