diff --git a/bench/librawspeed/io/BitStreamBenchmark.cpp b/bench/librawspeed/io/BitStreamBenchmark.cpp index 74a06c851..f21e8963d 100644 --- a/bench/librawspeed/io/BitStreamBenchmark.cpp +++ b/bench/librawspeed/io/BitStreamBenchmark.cpp @@ -125,7 +125,7 @@ template void registerPump(const char* pumpName) { name += ">>"; const auto Fn = BM_BitStream; - auto* b = benchmark::RegisterBenchmark(name.c_str(), Fn, i, j); + auto* b = benchmark::RegisterBenchmark(name, Fn, i, j); b->Apply(CustomArguments); } } diff --git a/fuzz/librawspeed/decompressors/LJpegDecompressor.cpp b/fuzz/librawspeed/decompressors/LJpegDecompressor.cpp index 4f5395e00..bff077eb9 100644 --- a/fuzz/librawspeed/decompressors/LJpegDecompressor.cpp +++ b/fuzz/librawspeed/decompressors/LJpegDecompressor.cpp @@ -45,11 +45,13 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { rawspeed::RawImage mRaw(CreateRawImage(bs)); - const int N_COMP = bs.getI32(); const int frame_w = bs.getI32(); const int frame_h = bs.getI32(); - const rawspeed::LJpegDecompressor::Frame frame{ - N_COMP, rawspeed::iPoint2D(frame_w, frame_h)}; + const int MCU_w = bs.getI32(); + const int MCU_h = bs.getI32(); + + const rawspeed::iPoint2D frame = {frame_w, frame_h}; + const rawspeed::iPoint2D MCU = {MCU_w, MCU_h}; const unsigned num_recips = bs.getU32(); @@ -82,7 +84,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { }); rawspeed::LJpegDecompressor d( - mRaw, rawspeed::iRectangle2D(mRaw->dim.x, mRaw->dim.y), frame, rec, + mRaw, rawspeed::iRectangle2D(mRaw->dim.x, mRaw->dim.y), frame, MCU, rec, bs.getSubStream(/*offset=*/0)); mRaw->createData(); d.decode(); diff --git a/src/librawspeed/adt/Point.h b/src/librawspeed/adt/Point.h index 0acc0c046..199adb197 100644 --- a/src/librawspeed/adt/Point.h +++ b/src/librawspeed/adt/Point.h @@ -55,14 +55,14 @@ class iPoint2D { return *this; } - constexpr bool operator==(const iPoint2D& rhs) const { + constexpr bool RAWSPEED_READONLY operator==(const iPoint2D& rhs) const { return x == rhs.x && y == rhs.y; } constexpr bool operator!=(const iPoint2D& rhs) const { return !operator==(rhs); } - constexpr bool operator>(const iPoint2D& rhs) const { + constexpr bool RAWSPEED_READONLY operator>(const iPoint2D& rhs) const { return x > rhs.x && y > rhs.y; } constexpr bool operator<(const iPoint2D& rhs) const { @@ -76,7 +76,9 @@ class iPoint2D { return x <= rhs.x && y <= rhs.y; } - [[nodiscard]] bool hasPositiveArea() const { return operator>({0, 0}); } + [[nodiscard]] bool RAWSPEED_READONLY hasPositiveArea() const { + return operator>({0, 0}); + } [[nodiscard]] area_type RAWSPEED_READONLY area() const { using signed_area = std::make_signed_t; diff --git a/src/librawspeed/decoders/ArwDecoder.cpp b/src/librawspeed/decoders/ArwDecoder.cpp index f20b03908..413cb14f3 100644 --- a/src/librawspeed/decoders/ArwDecoder.cpp +++ b/src/librawspeed/decoders/ArwDecoder.cpp @@ -23,7 +23,9 @@ #include "adt/NORangesSet.h" // for NORangesSet #include "adt/Point.h" // for iPoint2D #include "common/Common.h" // for roundDown -#include "decoders/RawDecoderException.h" // for ThrowException +#include "common/RawspeedException.h" // for RawspeedException +#include "decoders/RawDecoderException.h" // for ThrowRDE +#include "decompressors/LJpegDecoder.h" // for LJpegDecoder #include "decompressors/SonyArw1Decompressor.h" // for SonyArw1Decompre... #include "decompressors/SonyArw2Decompressor.h" // for SonyArw2Decompre... #include "decompressors/UncompressedDecompressor.h" // for UncompressedDeco... @@ -145,6 +147,13 @@ RawImage ArwDecoder::decodeRawInternal() { return mRaw; } + if (7 == compression) { + DecodeLJpeg(raw); + // cropping of lossless compressed L files already done in Ljpeg decoder + applyCrop = false; + return mRaw; + } + if (32767 != compression) ThrowRDE("Unsupported compression %i", compression); @@ -197,7 +206,7 @@ RawImage ArwDecoder::decodeRawInternal() { mRaw->dim = iPoint2D(width, height); std::vector curve(0x4001); - const TiffEntry* c = raw->getEntry(TiffTag::SONY_CURVE); + const TiffEntry* c = raw->getEntry(TiffTag::SONYCURVE); std::array sony_curve = {{0, 0, 0, 0, 0, 4095}}; for (uint32_t i = 0; i < 4; i++) @@ -245,7 +254,7 @@ void ArwDecoder::DecodeUncompressed(const TiffIFD* raw) const { mRaw->dim = iPoint2D(width, height); - if (width == 0 || height == 0 || width > 9600 || height > 6376) + if (width == 0 || height == 0 || width > 9728 || height > 6656) ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height); if (c2 == 0) @@ -270,6 +279,80 @@ void ArwDecoder::DecodeUncompressed(const TiffIFD* raw) const { } } +void ArwDecoder::DecodeLJpeg(const TiffIFD* raw) const { + uint32_t width = raw->getEntry(TiffTag::IMAGEWIDTH)->getU32(); + uint32_t height = raw->getEntry(TiffTag::IMAGELENGTH)->getU32(); + uint32_t bitPerPixel = raw->getEntry(TiffTag::BITSPERSAMPLE)->getU32(); + + switch (bitPerPixel) { + case 8: + case 12: + case 14: + break; + default: + ThrowRDE("Unexpected bits per pixel: %u", bitPerPixel); + } + + if (width == 0 || height == 0 || width % 2 != 0 || height % 2 != 0 || + width > 9728 || height > 6656) + ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height); + + mRaw->dim = iPoint2D(width, height); + + const uint32_t tilew = raw->getEntry(TiffTag::TILEWIDTH)->getU32(); + const uint32_t tileh = raw->getEntry(TiffTag::TILELENGTH)->getU32(); + + if (tilew <= 0 || tileh <= 0) + ThrowRDE("Invalid tile size: (%u, %u)", tilew, tileh); + + assert(tilew > 0); + const uint32_t tilesX = roundUpDivision(mRaw->dim.x, tilew); + if (!tilesX) + ThrowRDE("Zero tiles horizontally"); + + assert(tileh > 0); + const uint32_t tilesY = roundUpDivision(mRaw->dim.y, tileh); + if (!tilesY) + ThrowRDE("Zero tiles vertically"); + + const TiffEntry* offsets = raw->getEntry(TiffTag::TILEOFFSETS); + const TiffEntry* counts = raw->getEntry(TiffTag::TILEBYTECOUNTS); + if (offsets->count != counts->count) { + ThrowRDE("Tile count mismatch: offsets:%u count:%u", offsets->count, + counts->count); + } + + // tilesX * tilesY may overflow, but division is fine, so let's do that. + if ((offsets->count / tilesX != tilesY || (offsets->count % tilesX != 0)) || + (offsets->count / tilesY != tilesX || (offsets->count % tilesY != 0))) { + ThrowRDE("Tile X/Y count mismatch: total:%u X:%u, Y:%u", offsets->count, + tilesX, tilesY); + } + + mRaw->createData(); +#ifdef HAVE_OPENMP +#pragma omp parallel for schedule(static) default(none) \ + shared(offsets, counts) firstprivate(tilesX, tilew, tileh) +#endif + for (int tile = 0U; tile < static_cast(offsets->count); tile++) { + const uint32_t tileX = tile % tilesX; + const uint32_t tileY = tile / tilesX; + const uint32_t offset = offsets->getU32(tile); + const uint32_t length = counts->getU32(tile); + + LJpegDecoder decoder(ByteStream(DataBuffer(mFile.getSubView(offset, length), + Endianness::little)), + mRaw, true); + decoder.decode(tileX * tilew, tileY * tileh, tilew, tileh, false); + } + + const TiffEntry* size_entry = raw->hasEntry(TiffTag::SONYRAWIMAGESIZE) + ? raw->getEntry(TiffTag::SONYRAWIMAGESIZE) + : raw->getEntry(TiffTag::DEFAULTCROPSIZE); + iRectangle2D crop(0, 0, size_entry->getU32(0), size_entry->getU32(1)); + mRaw->subFrame(crop); +} + void ArwDecoder::DecodeARW2(ByteStream input, uint32_t w, uint32_t h, uint32_t bpp) { @@ -427,11 +510,11 @@ void ArwDecoder::GetWB() const { priv->getU32()); const TiffEntry* sony_offset = - makerNoteIFD.getEntryRecursive(TiffTag::SONY_OFFSET); + makerNoteIFD.getEntryRecursive(TiffTag::SONYOFFSET); const TiffEntry* sony_length = - makerNoteIFD.getEntryRecursive(TiffTag::SONY_LENGTH); + makerNoteIFD.getEntryRecursive(TiffTag::SONYLENGTH); const TiffEntry* sony_key = - makerNoteIFD.getEntryRecursive(TiffTag::SONY_KEY); + makerNoteIFD.getEntryRecursive(TiffTag::SONYKEY); if (!sony_offset || !sony_length || !sony_key || sony_key->count != 4) ThrowRDE("couldn't find the correct metadata for WB decoding"); diff --git a/src/librawspeed/decoders/ArwDecoder.h b/src/librawspeed/decoders/ArwDecoder.h index a916e15cb..7e6adf6b4 100644 --- a/src/librawspeed/decoders/ArwDecoder.h +++ b/src/librawspeed/decoders/ArwDecoder.h @@ -49,6 +49,7 @@ class ArwDecoder final : public AbstractTiffDecoder { [[nodiscard]] int getDecoderVersion() const override { return 1; } RawImage decodeSRF(const TiffIFD* raw); void DecodeARW2(ByteStream input, uint32_t w, uint32_t h, uint32_t bpp); + void DecodeLJpeg(const TiffIFD* raw) const; void DecodeUncompressed(const TiffIFD* raw) const; static void SonyDecrypt(const uint32_t* ibuf, uint32_t* obuf, uint32_t len, uint32_t key); diff --git a/src/librawspeed/decompressors/LJpegDecoder.cpp b/src/librawspeed/decompressors/LJpegDecoder.cpp index 8bf8b222d..a4b3b3cfd 100644 --- a/src/librawspeed/decompressors/LJpegDecoder.cpp +++ b/src/librawspeed/decompressors/LJpegDecoder.cpp @@ -36,8 +36,9 @@ using std::copy_n; namespace rawspeed { -LJpegDecoder::LJpegDecoder(ByteStream bs, const RawImage& img) - : AbstractLJpegDecoder(bs, img) { +LJpegDecoder::LJpegDecoder(ByteStream bs, const RawImage& img, + bool interleaveRows_) + : AbstractLJpegDecoder(bs, img), interleaveRows{interleaveRows_} { if (mRaw->getDataType() != RawImageType::UINT16) ThrowRDE("Unexpected data type (%u)", static_cast(mRaw->getDataType())); @@ -101,6 +102,10 @@ void LJpegDecoder::decodeScan() { int N_COMP = frame.cps; + const iPoint2D MCUSize = !interleaveRows + ? iPoint2D(frame.cps, 1) + : iPoint2D(frame.cps / 2, frame.cps / 2); + std::vector rec; rec.reserve(N_COMP); std::generate_n(std::back_inserter(rec), N_COMP, @@ -111,9 +116,9 @@ void LJpegDecoder::decodeScan() { return {*hts[i], initPred[i]}; }); - LJpegDecompressor d( - mRaw, iRectangle2D({(int)offX, (int)offY}, {(int)w, (int)h}), - LJpegDecompressor::Frame{N_COMP, iPoint2D(frame.w, frame.h)}, rec, input); + LJpegDecompressor d(mRaw, + iRectangle2D({(int)offX, (int)offY}, {(int)w, (int)h}), + {(int)frame.w, (int)frame.h}, MCUSize, rec, input); d.decode(); } diff --git a/src/librawspeed/decompressors/LJpegDecoder.h b/src/librawspeed/decompressors/LJpegDecoder.h index 9160e35e0..4374e7c5c 100644 --- a/src/librawspeed/decompressors/LJpegDecoder.h +++ b/src/librawspeed/decompressors/LJpegDecoder.h @@ -37,9 +37,10 @@ class LJpegDecoder final : public AbstractLJpegDecoder { uint32_t offY = 0; uint32_t w = 0; uint32_t h = 0; + bool interleaveRows = false; public: - LJpegDecoder(ByteStream bs, const RawImage& img); + LJpegDecoder(ByteStream bs, const RawImage& img, bool interleaveRows = false); void decode(uint32_t offsetX, uint32_t offsetY, uint32_t width, uint32_t height, bool fixDng16Bug_); diff --git a/src/librawspeed/decompressors/LJpegDecompressor.cpp b/src/librawspeed/decompressors/LJpegDecompressor.cpp index 090898f63..e3951fe51 100644 --- a/src/librawspeed/decompressors/LJpegDecompressor.cpp +++ b/src/librawspeed/decompressors/LJpegDecompressor.cpp @@ -30,19 +30,19 @@ #include "io/ByteStream.h" // for ByteStream #include // for transform #include // for array +#include // for PRId64 #include // for allocator_traits<>::value_... #include // for move -using std::copy_n; - namespace rawspeed { LJpegDecompressor::LJpegDecompressor(const RawImage& img, - iRectangle2D imgFrame_, Frame frame_, + iRectangle2D imgFrame_, iPoint2D frame_, + iPoint2D MCUSize_, std::vector rec_, ByteStream bs) - : mRaw(img), input(bs), imgFrame(imgFrame_), frame(std::move(frame_)), - rec(std::move(rec_)) { + : mRaw(img), input(bs), imgFrame(imgFrame_), frame(frame_), + MCUSize(MCUSize_), rec(std::move(rec_)) { if (mRaw->getDataType() != RawImageType::UINT16) ThrowRDE("Unexpected data type (%u)", static_cast(mRaw->getDataType())); @@ -78,10 +78,14 @@ LJpegDecompressor::LJpegDecompressor(const RawImage& img, if (imgFrame.pos.y + imgFrame.dim.y > mRaw->dim.y) ThrowRDE("Tile overflows image vertically"); - if (frame.cps < 1 || frame.cps > 4) - ThrowRDE("Unsupported number of components: %u", frame.cps); + auto cps = MCUSize.area(); + if (cps < 1 || cps > 4) + ThrowRDE("Unsupported number of components: %" PRId64, cps); + + if (MCUSize != iPoint2D(cps, 1) && MCUSize != iPoint2D(2, 2)) + ThrowRDE("Unsupported LJpeg MCU: %i x %i", MCUSize.x, MCUSize.y); - if (rec.size() != (unsigned)frame.cps) + if (rec.size() != (unsigned)cps) ThrowRDE("Must have exactly one recepie per component"); for (const auto& recip : rec) { @@ -89,33 +93,34 @@ LJpegDecompressor::LJpegDecompressor(const RawImage& img, ThrowRDE("Huffman table is not of a full decoding variety"); } - if ((unsigned)frame.cps < mRaw->getCpp()) + if ((unsigned)cps < mRaw->getCpp()) ThrowRDE("Unexpected number of components"); - if ((int64_t)frame.cps * frame.dim.x > std::numeric_limits::max()) + if ((int64_t)cps * frame.x > std::numeric_limits::max()) ThrowRDE("LJpeg frame is too big"); - invariant(mRaw->dim.x > imgFrame.pos.x); - if (((int)mRaw->getCpp() * (mRaw->dim.x - imgFrame.pos.x)) < frame.cps) - ThrowRDE("Got less pixels than the components per sample"); + if (!(imgFrame.dim >= MCUSize)) + ThrowRDE("Image frame is smaller than a single LJpeg MCU."); // How many output pixels are we expected to produce, as per DNG tiling? const int tileRequiredWidth = (int)mRaw->getCpp() * imgFrame.dim.x; + // How many of these rows do we need? + invariant(imgFrame.dim.y % MCUSize.y == 0); + const auto numRows = imgFrame.dim.y / MCUSize.y; // How many full pixel blocks do we need to consume for that? - if (const int blocksToConsume = roundUpDivision(tileRequiredWidth, frame.cps); - frame.dim.x < blocksToConsume || frame.dim.y < imgFrame.dim.y || - (int64_t)frame.cps * frame.dim.x < - (int64_t)mRaw->getCpp() * imgFrame.dim.x) { + if (const int blocksToConsume = roundUpDivision(tileRequiredWidth, MCUSize.x); + frame.x < blocksToConsume || frame.y < numRows || + (int64_t)MCUSize.x * frame.x < (int64_t)mRaw->getCpp() * imgFrame.dim.x) { ThrowRDE("LJpeg frame (%u, %u) is smaller than expected (%u, %u)", - frame.cps * frame.dim.x, frame.dim.y, tileRequiredWidth, - imgFrame.dim.y); + MCUSize.x * frame.x, frame.y, tileRequiredWidth, numRows); } // How many full pixel blocks will we produce? - fullBlocks = tileRequiredWidth / frame.cps; // Truncating division! + fullCols = tileRequiredWidth / MCUSize.x; // Truncating division! + invariant(fullCols > 0); // Do we need to also produce part of a block? - trailingPixels = tileRequiredWidth % frame.cps; + havePartialCol = tileRequiredWidth % MCUSize.x; } template @@ -143,7 +148,19 @@ std::array LJpegDecompressor::getInitialPreds() const { // N_COMP == number of components (2, 3 or 4) -template void LJpegDecompressor::decodeN() { +namespace { + +template +constexpr iPoint2D MCU = {MCUWidth, MCUHeight}; + +} // namespace + +template void LJpegDecompressor::decodeN() { + invariant(MCU == this->MCUSize); + + invariant(MCU.hasPositiveArea()); + // FIXME: workarounding lack of constexpr std::abs() :( + constexpr int N_COMP = MCU.x * MCU.y; invariant(mRaw->getCpp() > 0); invariant(N_COMP > 0); invariant(N_COMP >= mRaw->getCpp()); @@ -158,7 +175,6 @@ template void LJpegDecompressor::decodeN() { const auto ht = getPrefixCodeDecoders(); auto pred = getInitialPreds(); - uint16_t* predNext = pred.data(); BitPumpJPEG bitStream(input); @@ -166,103 +182,108 @@ template void LJpegDecompressor::decodeN() { // The tiles at the bottom and the right may extend beyond the dimension of // the raw image buffer. The excessive content has to be ignored. - invariant(frame.dim.y >= imgFrame.dim.y); - invariant((int64_t)frame.cps * frame.dim.x >= + // invariant(frame.y >= imgFrame.dim.y); // FIXME + invariant((int64_t)N_COMP * frame.x >= (int64_t)mRaw->getCpp() * imgFrame.dim.x); invariant(imgFrame.pos.y + imgFrame.dim.y <= mRaw->dim.y); invariant(imgFrame.pos.x + imgFrame.dim.x <= mRaw->dim.x); - // For y, we can simply stop decoding when we reached the border. - for (int row = 0; row < imgFrame.dim.y; ++row) { - int col = 0; + invariant(imgFrame.dim.y % MCU.y == 0); + const auto numFrameRows = imgFrame.dim.y / MCU.y; - copy_n(predNext, N_COMP, pred.data()); - // the predictor for the next line is the start of this line - predNext = &img(row, col); + // For y, we can simply stop decoding when we reached the border. + invariant(numFrameRows > 0); + for (int frameRow = 0; frameRow < numFrameRows; ++frameRow) { + int frameCol = 0; // FIXME: predictor may have value outside of the uint16_t. // https://github.com/darktable-org/rawspeed/issues/175 // For x, we first process all full pixel blocks within the image buffer ... - for (; col < N_COMP * fullBlocks; col += N_COMP) { - for (int i = 0; i != N_COMP; ++i) { - pred[i] = uint16_t( - pred[i] + - ((const PrefixCodeDecoder<>&)(ht[i])).decodeDifference(bitStream)); - img(row, col + i) = pred[i]; + invariant(fullCols > 0); + for (; frameCol < fullCols; ++frameCol) { + for (int MCURow = 0; MCURow != MCU.y; ++MCURow) { + for (int MCUСol = 0; MCUСol != MCU.x; ++MCUСol) { + int c = MCU.x * MCURow + MCUСol; + pred[c] = uint16_t(pred[c] + ((const PrefixCodeDecoder<>&)(ht[c])) + .decodeDifference(bitStream)); + int imgRow = (frameRow * MCU.y) + MCURow; + int imgCol = (frameCol * MCU.x) + MCUСol; + img(imgRow, imgCol) = pred[c]; + } } } // Sometimes we also need to consume one more block, and produce part of it. - if /*constexpr*/ (WeirdWidth) { - // FIXME: evaluate i-cache implications due to this being compile-time. - static_assert(N_COMP > 1 || !WeirdWidth, - "can't want part of 1-pixel-wide block"); + if (havePartialCol) { + invariant(N_COMP > 1 && "can't want part of 1-pixel-wide block"); // Some rather esoteric DNG's have odd dimensions, e.g. width % 2 = 1. // We may end up needing just part of last N_COMP pixels. - invariant(trailingPixels > 0); - invariant(trailingPixels < N_COMP); - int c = 0; - for (; c < trailingPixels; ++c) { - pred[c] = uint16_t( - pred[c] + - ((const PrefixCodeDecoder<>&)(ht[c])).decodeDifference(bitStream)); - img(row, col + c) = pred[c]; + for (int MCURow = 0; MCURow != MCU.y; ++MCURow) { + for (int MCUСol = 0; MCUСol != MCU.x; ++MCUСol) { + int c = MCU.x * MCURow + MCUСol; + pred[c] = uint16_t(pred[c] + ((const PrefixCodeDecoder<>&)(ht[c])) + .decodeDifference(bitStream)); + int imgRow = (frameRow * MCU.y) + MCURow; + int imgCol = (frameCol * MCU.x) + MCUСol; + if (imgCol < img.croppedWidth) + img(imgRow, imgCol) = pred[c]; + } } - // Discard the rest of the block. - invariant(c < N_COMP); - for (; c < N_COMP; ++c) { - ((const PrefixCodeDecoder<>&)(ht[c])).decodeDifference(bitStream); - } - col += N_COMP; // We did just process one more block. + ++frameCol; // We did just process one more block. } // ... and discard the rest. - for (; col < N_COMP * frame.dim.x; col += N_COMP) { - for (int i = 0; i != N_COMP; ++i) - ((const PrefixCodeDecoder<>&)(ht[i])).decodeDifference(bitStream); + for (; frameCol < frame.x; ++frameCol) { + for (int c = 0; c != N_COMP; ++c) + ((const PrefixCodeDecoder<>&)(ht[c])).decodeDifference(bitStream); + } + + // The first sample of the next row is calculated based on the first sample + // of this row, so copy it for the next iteration + for (int MCURow = 0; MCURow != MCU.y; ++MCURow) { + for (int MCUСol = 0; MCUСol != MCU.x; ++MCUСol) { + pred[MCU.x * MCURow + MCUСol] = img(frameRow * MCU.y + MCURow, MCUСol); + } } } } void LJpegDecompressor::decode() { - if (trailingPixels == 0) { - switch (frame.cps) { - case 1: - decodeN<1>(); - break; - case 2: - decodeN<2>(); - break; - case 3: - decodeN<3>(); - break; - case 4: - decodeN<4>(); - break; - default: - __builtin_unreachable(); + switch (MCUSize.area()) { + case 1: + if (MCUSize == MCU<1, 1>) { + decodeN>(); + return; + } + break; + case 2: + if (MCUSize == MCU<2, 1>) { + decodeN>(); + return; + } + break; + case 3: + if (MCUSize == MCU<3, 1>) { + decodeN>(); + return; + } + break; + case 4: + if (MCUSize == MCU<4, 1>) { + decodeN>(); + return; } - } else /* trailingPixels != 0 */ { - // FIXME: using different function just for one tile likely causes - // i-cache misses and whatnot. Need to check how not splitting it into - // two different functions affects performance of the normal case. - switch (frame.cps) { - // Naturally can't happen for CPS=1. - case 2: - decodeN<2, /*WeirdWidth=*/true>(); - break; - case 3: - decodeN<3, /*WeirdWidth=*/true>(); - break; - case 4: - decodeN<4, /*WeirdWidth=*/true>(); - break; - default: - __builtin_unreachable(); + if (MCUSize == MCU<2, 2>) { + decodeN>(); + return; } + break; + default: + __builtin_unreachable(); } + __builtin_unreachable(); } } // namespace rawspeed diff --git a/src/librawspeed/decompressors/LJpegDecompressor.h b/src/librawspeed/decompressors/LJpegDecompressor.h index 44151a2d6..f42687c99 100644 --- a/src/librawspeed/decompressors/LJpegDecompressor.h +++ b/src/librawspeed/decompressors/LJpegDecompressor.h @@ -38,10 +38,6 @@ namespace rawspeed { class LJpegDecompressor final { public: - struct Frame { - const int cps; - const iPoint2D dim; - }; struct PerComponentRecipe { const PrefixCodeDecoder<>& ht; const uint16_t initPred; @@ -53,11 +49,12 @@ class LJpegDecompressor final { const iRectangle2D imgFrame; - const Frame frame; + const iPoint2D frame; + const iPoint2D MCUSize; const std::vector rec; - int fullBlocks = 0; - int trailingPixels = 0; + int fullCols = 0; + bool havePartialCol = false; template [[nodiscard]] std::array>, @@ -72,11 +69,12 @@ class LJpegDecompressor final { template [[nodiscard]] std::array getInitialPreds() const; - template void decodeN(); + template void decodeN(); public: - LJpegDecompressor(const RawImage& img, iRectangle2D imgFrame, Frame frame, - std::vector rec, ByteStream bs); + LJpegDecompressor(const RawImage& img, iRectangle2D imgFrame, iPoint2D frame, + iPoint2D MCUSize, std::vector rec, + ByteStream bs); void decode(); }; diff --git a/src/librawspeed/tiff/TiffTag.h b/src/librawspeed/tiff/TiffTag.h index 583b621f0..020c20856 100644 --- a/src/librawspeed/tiff/TiffTag.h +++ b/src/librawspeed/tiff/TiffTag.h @@ -127,7 +127,11 @@ enum class TiffTag { FUJIOLDWB = 0x2ff0, CANONCOLORDATA = 0x4001, - + SONYCURVE = 0x7010, + SONYRAWIMAGESIZE = 0x7038, + SONYOFFSET = 0x7200, + SONYLENGTH = 0x7201, + SONYKEY = 0x7221, SONYGRBGLEVELS = 0x7303, SONYRGGBLEVELS = 0x7313, @@ -336,10 +340,6 @@ enum class TiffTag { CALIBRATIONILLUMINANT1 = 0xC65A, // IFD0 CALIBRATIONILLUMINANT2 = 0xC65B, // IFD0 - SONY_CURVE = 28688, - SONY_OFFSET = 0x7200, - SONY_LENGTH = 0x7201, - SONY_KEY = 0x7221, // PRINT IMAGE MATCHING DATA PIMIFDPOINTER = 0xC4A5, diff --git a/src/utilities/rsbench/main.cpp b/src/utilities/rsbench/main.cpp index 3e211e2c6..d08f35e09 100644 --- a/src/utilities/rsbench/main.cpp +++ b/src/utilities/rsbench/main.cpp @@ -185,8 +185,7 @@ static inline void BM_RawSpeed(benchmark::State& state, Entry* entry, static void addBench(Entry* entry, std::string tName, int threads) { tName += std::to_string(threads); - auto* b = - benchmark::RegisterBenchmark(tName.c_str(), &BM_RawSpeed, entry, threads); + auto* b = benchmark::RegisterBenchmark(tName, &BM_RawSpeed, entry, threads); b->Unit(benchmark::kMillisecond); b->UseRealTime(); b->MeasureProcessCPUTime();