From b383e9ead00c0ec3578d5e0b94cbcdcbda322766 Mon Sep 17 00:00:00 2001 From: Philipp Lutz Date: Sat, 3 Jun 2023 21:50:24 +0200 Subject: [PATCH 01/15] ARW: Support new LJPEG compression on ILCE-7M4 and ILCE-7R5 * Support large-resolution ARW from ILCE-7RM5 * Generalize sonyArrange in LJPEG arrangement to support 1x2 Co-authored-by: Artemis Tosini --- src/librawspeed/decoders/ArwDecoder.cpp | 84 ++++++++++++++++++- src/librawspeed/decoders/ArwDecoder.h | 1 + .../decompressors/LJpegDecoder.cpp | 8 +- src/librawspeed/decompressors/LJpegDecoder.h | 3 +- .../decompressors/LJpegDecompressor.cpp | 43 ++++++++-- .../decompressors/LJpegDecompressor.h | 3 +- 6 files changed, 126 insertions(+), 16 deletions(-) diff --git a/src/librawspeed/decoders/ArwDecoder.cpp b/src/librawspeed/decoders/ArwDecoder.cpp index f20b03908..7365eb1a1 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,11 @@ RawImage ArwDecoder::decodeRawInternal() { return mRaw; } + if (7 == compression) { + DecodeLJpeg(raw); + return mRaw; + } + if (32767 != compression) ThrowRDE("Unsupported compression %i", compression); @@ -245,7 +252,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 +277,79 @@ 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 || 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 for schedule(static) + #endif + for (uint32_t tile = 0U; tile < 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* origin_entry = raw->getEntry(TiffTag::DEFAULTCROPORIGIN); + const TiffEntry* size_entry = raw->getEntry(TiffTag::DEFAULTCROPSIZE); + iRectangle2D crop(origin_entry->getU32(0), origin_entry->getU32(1), + 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) { 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..6cb8ccf51 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())); @@ -113,7 +114,8 @@ void LJpegDecoder::decodeScan() { LJpegDecompressor d( mRaw, iRectangle2D({(int)offX, (int)offY}, {(int)w, (int)h}), - LJpegDecompressor::Frame{N_COMP, iPoint2D(frame.w, frame.h)}, rec, input); + LJpegDecompressor::Frame{N_COMP, iPoint2D(frame.w, frame.h)}, rec, input, + interleaveRows); 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..bcc0e7454 100644 --- a/src/librawspeed/decompressors/LJpegDecompressor.cpp +++ b/src/librawspeed/decompressors/LJpegDecompressor.cpp @@ -40,9 +40,9 @@ namespace rawspeed { LJpegDecompressor::LJpegDecompressor(const RawImage& img, iRectangle2D imgFrame_, Frame frame_, std::vector rec_, - ByteStream bs) + ByteStream bs, bool interleaveRows_) : mRaw(img), input(bs), imgFrame(imgFrame_), frame(std::move(frame_)), - rec(std::move(rec_)) { + rec(std::move(rec_)), interleaveRows{interleaveRows_} { if (mRaw->getDataType() != RawImageType::UINT16) ThrowRDE("Unexpected data type (%u)", static_cast(mRaw->getDataType())); @@ -100,16 +100,19 @@ LJpegDecompressor::LJpegDecompressor(const RawImage& img, ThrowRDE("Got less pixels than the components per sample"); // How many output pixels are we expected to produce, as per DNG tiling? - const int tileRequiredWidth = (int)mRaw->getCpp() * imgFrame.dim.x; + const auto interleaveFactor = interleaveRows ? 2 : 1; + const int tileRequiredWidth = + (int)mRaw->getCpp() * imgFrame.dim.x * interleaveFactor; + // How many of these rows do we need? + const auto numRows = imgFrame.dim.y / interleaveFactor; // 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 || + frame.dim.x < blocksToConsume || frame.dim.y < numRows || (int64_t)frame.cps * frame.dim.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); + frame.cps * frame.dim.x, frame.dim.y, tileRequiredWidth, numRows); } // How many full pixel blocks will we produce? @@ -148,17 +151,20 @@ template void LJpegDecompressor::decodeN() { invariant(N_COMP > 0); invariant(N_COMP >= mRaw->getCpp()); invariant((N_COMP / mRaw->getCpp()) > 0); + invariant(((N_COMP & 1) == 0) | !interleaveRows); invariant(mRaw->dim.x >= N_COMP); invariant((mRaw->getCpp() * (mRaw->dim.x - imgFrame.pos.x)) >= N_COMP); + auto interleaveHeight = (interleaveRows ? 2 : 1); + auto interleaveWidth = N_COMP / interleaveHeight; + const CroppedArray2DRef img(mRaw->getU16DataAsUncroppedArray2DRef(), mRaw->getCpp() * imgFrame.pos.x, imgFrame.pos.y, mRaw->getCpp() * imgFrame.dim.x, imgFrame.dim.y); const auto ht = getPrefixCodeDecoders(); auto pred = getInitialPreds(); - uint16_t* predNext = pred.data(); BitPumpJPEG bitStream(input); @@ -173,13 +179,17 @@ template void LJpegDecompressor::decodeN() { invariant(imgFrame.pos.y + imgFrame.dim.y <= mRaw->dim.y); invariant(imgFrame.pos.x + imgFrame.dim.x <= mRaw->dim.x); + const auto numRows = imgFrame.dim.y / interleaveHeight; + // For y, we can simply stop decoding when we reached the border. - for (int row = 0; row < imgFrame.dim.y; ++row) { + for (int row = 0; row < numRows; ++row) { int col = 0; + /* copy_n(predNext, N_COMP, pred.data()); // the predictor for the next line is the start of this line predNext = &img(row, col); + */ // FIXME: predictor may have value outside of the uint16_t. // https://github.com/darktable-org/rawspeed/issues/175 @@ -190,7 +200,12 @@ template void LJpegDecompressor::decodeN() { pred[i] = uint16_t( pred[i] + ((const PrefixCodeDecoder<>&)(ht[i])).decodeDifference(bitStream)); - img(row, col + i) = pred[i]; + if (interleaveRows) { + img((row * interleaveHeight) + (i / interleaveHeight), + (col / interleaveWidth) + (i % interleaveWidth)) = pred[i]; + } else { + img(row, col + i) = pred[i]; + } } } @@ -223,6 +238,16 @@ template void LJpegDecompressor::decodeN() { for (int i = 0; i != N_COMP; ++i) ((const PrefixCodeDecoder<>&)(ht[i])).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 + if (interleaveRows) { + copy_n(&img(row * interleaveHeight, 0), interleaveWidth, pred.data()); + copy_n(&img(row * interleaveHeight + 1, 0), interleaveWidth, + pred.data() + interleaveWidth); + } else { + copy_n(&img(row, 0), N_COMP, pred.data()); + } } } diff --git a/src/librawspeed/decompressors/LJpegDecompressor.h b/src/librawspeed/decompressors/LJpegDecompressor.h index 44151a2d6..436f61583 100644 --- a/src/librawspeed/decompressors/LJpegDecompressor.h +++ b/src/librawspeed/decompressors/LJpegDecompressor.h @@ -58,6 +58,7 @@ class LJpegDecompressor final { int fullBlocks = 0; int trailingPixels = 0; + bool interleaveRows = false; template [[nodiscard]] std::array>, @@ -76,7 +77,7 @@ class LJpegDecompressor final { public: LJpegDecompressor(const RawImage& img, iRectangle2D imgFrame, Frame frame, - std::vector rec, ByteStream bs); + std::vector rec, ByteStream bs, bool interleaveRows = false); void decode(); }; From 25585e239e9fbed34ee56d39ea2a97e7595b3fe9 Mon Sep 17 00:00:00 2001 From: Philipp Lutz Date: Mon, 5 Jun 2023 19:48:34 +0200 Subject: [PATCH 02/15] Use Exif.SubImage1.0x7038 field for Sony lossless compression crop Recap: due to crop size roundup to multiples of tile size (512) Sony lossless files exhibit black areas if not further cropped down to actual pixel area, which is covered by the sensor. Exif.SubImage1.0x7038 seems to reliably provide the true crop size, whereas Exif.SubImage1.DefaultCropSize only crops to OOC jpeg size losing some pixel area --- src/librawspeed/decoders/ArwDecoder.cpp | 4 +++- src/librawspeed/tiff/TiffTag.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librawspeed/decoders/ArwDecoder.cpp b/src/librawspeed/decoders/ArwDecoder.cpp index 7365eb1a1..181060481 100644 --- a/src/librawspeed/decoders/ArwDecoder.cpp +++ b/src/librawspeed/decoders/ArwDecoder.cpp @@ -344,7 +344,9 @@ void ArwDecoder::DecodeLJpeg(const TiffIFD* raw) const { } const TiffEntry* origin_entry = raw->getEntry(TiffTag::DEFAULTCROPORIGIN); - const TiffEntry* size_entry = raw->getEntry(TiffTag::DEFAULTCROPSIZE); + const TiffEntry* size_entry = raw->hasEntry(TiffTag::SONYRAWIMAGESIZE) + ? raw->getEntry(TiffTag::SONYRAWIMAGESIZE) + : raw->getEntry(TiffTag::DEFAULTCROPSIZE); iRectangle2D crop(origin_entry->getU32(0), origin_entry->getU32(1), size_entry->getU32(0), size_entry->getU32(1)); mRaw->subFrame(crop); diff --git a/src/librawspeed/tiff/TiffTag.h b/src/librawspeed/tiff/TiffTag.h index 583b621f0..d1e79e338 100644 --- a/src/librawspeed/tiff/TiffTag.h +++ b/src/librawspeed/tiff/TiffTag.h @@ -128,6 +128,7 @@ enum class TiffTag { CANONCOLORDATA = 0x4001, + SONYRAWIMAGESIZE = 0x7038, SONYGRBGLEVELS = 0x7303, SONYRGGBLEVELS = 0x7313, From 1972397b4a6091e3f13fd17a00860560bf15c827 Mon Sep 17 00:00:00 2001 From: Philipp Lutz Date: Mon, 5 Jun 2023 19:49:20 +0200 Subject: [PATCH 03/15] Boyscout: make sony exif tag naming consistent --- src/librawspeed/decoders/ArwDecoder.cpp | 8 ++++---- src/librawspeed/tiff/TiffTag.h | 9 ++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/librawspeed/decoders/ArwDecoder.cpp b/src/librawspeed/decoders/ArwDecoder.cpp index 181060481..b5ea12365 100644 --- a/src/librawspeed/decoders/ArwDecoder.cpp +++ b/src/librawspeed/decoders/ArwDecoder.cpp @@ -204,7 +204,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++) @@ -509,11 +509,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/tiff/TiffTag.h b/src/librawspeed/tiff/TiffTag.h index d1e79e338..020c20856 100644 --- a/src/librawspeed/tiff/TiffTag.h +++ b/src/librawspeed/tiff/TiffTag.h @@ -127,8 +127,11 @@ enum class TiffTag { FUJIOLDWB = 0x2ff0, CANONCOLORDATA = 0x4001, - + SONYCURVE = 0x7010, SONYRAWIMAGESIZE = 0x7038, + SONYOFFSET = 0x7200, + SONYLENGTH = 0x7201, + SONYKEY = 0x7221, SONYGRBGLEVELS = 0x7303, SONYRGGBLEVELS = 0x7313, @@ -337,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, From 5f3fe8f377701e644989c52e262302a9ad5d28e8 Mon Sep 17 00:00:00 2001 From: Philipp Lutz Date: Tue, 6 Jun 2023 23:42:18 +0200 Subject: [PATCH 04/15] Do not apply crop from cameras.xml and set crop origin to 0,0 --- src/librawspeed/decoders/ArwDecoder.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librawspeed/decoders/ArwDecoder.cpp b/src/librawspeed/decoders/ArwDecoder.cpp index b5ea12365..9489c9d64 100644 --- a/src/librawspeed/decoders/ArwDecoder.cpp +++ b/src/librawspeed/decoders/ArwDecoder.cpp @@ -149,6 +149,8 @@ RawImage ArwDecoder::decodeRawInternal() { if (7 == compression) { DecodeLJpeg(raw); + // cropping of lossless compressed L files already done in Ljpeg decoder + applyCrop = false; return mRaw; } @@ -343,11 +345,10 @@ void ArwDecoder::DecodeLJpeg(const TiffIFD* raw) const { decoder.decode(tileX * tilew, tileY * tileh, tilew, tileh, false); } - const TiffEntry* origin_entry = raw->getEntry(TiffTag::DEFAULTCROPORIGIN); const TiffEntry* size_entry = raw->hasEntry(TiffTag::SONYRAWIMAGESIZE) ? raw->getEntry(TiffTag::SONYRAWIMAGESIZE) : raw->getEntry(TiffTag::DEFAULTCROPSIZE); - iRectangle2D crop(origin_entry->getU32(0), origin_entry->getU32(1), + iRectangle2D crop(0, 0, size_entry->getU32(0), size_entry->getU32(1)); mRaw->subFrame(crop); } From 5a46d384284dac24462ca264dc65c0487cc3a35f Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Wed, 7 Jun 2023 21:26:20 +0300 Subject: [PATCH 05/15] LJpegDecompressor::decodeN(): disable another assert that does not hold for square MCU's --- src/librawspeed/decompressors/LJpegDecompressor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librawspeed/decompressors/LJpegDecompressor.cpp b/src/librawspeed/decompressors/LJpegDecompressor.cpp index bcc0e7454..85d203f92 100644 --- a/src/librawspeed/decompressors/LJpegDecompressor.cpp +++ b/src/librawspeed/decompressors/LJpegDecompressor.cpp @@ -172,7 +172,7 @@ 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(frame.dim.y >= imgFrame.dim.y); // FIXME invariant((int64_t)frame.cps * frame.dim.x >= (int64_t)mRaw->getCpp() * imgFrame.dim.x); From 6163fd8c17e46b85a352633d805755aeec7bbc4c Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Thu, 8 Jun 2023 22:14:05 +0300 Subject: [PATCH 06/15] Apply clang-format --- src/librawspeed/decoders/ArwDecoder.cpp | 31 +++++++++---------- .../decompressors/LJpegDecompressor.h | 3 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/librawspeed/decoders/ArwDecoder.cpp b/src/librawspeed/decoders/ArwDecoder.cpp index 9489c9d64..972719eb3 100644 --- a/src/librawspeed/decoders/ArwDecoder.cpp +++ b/src/librawspeed/decoders/ArwDecoder.cpp @@ -330,26 +330,25 @@ void ArwDecoder::DecodeLJpeg(const TiffIFD* raw) const { } mRaw->createData(); - #ifdef HAVE_OPENMP - #pragma omp for schedule(static) - #endif - for (uint32_t tile = 0U; tile < 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); - } +#ifdef HAVE_OPENMP +#pragma omp for schedule(static) +#endif + for (uint32_t tile = 0U; tile < 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)); + iRectangle2D crop(0, 0, size_entry->getU32(0), size_entry->getU32(1)); mRaw->subFrame(crop); } diff --git a/src/librawspeed/decompressors/LJpegDecompressor.h b/src/librawspeed/decompressors/LJpegDecompressor.h index 436f61583..969310d20 100644 --- a/src/librawspeed/decompressors/LJpegDecompressor.h +++ b/src/librawspeed/decompressors/LJpegDecompressor.h @@ -77,7 +77,8 @@ class LJpegDecompressor final { public: LJpegDecompressor(const RawImage& img, iRectangle2D imgFrame, Frame frame, - std::vector rec, ByteStream bs, bool interleaveRows = false); + std::vector rec, ByteStream bs, + bool interleaveRows = false); void decode(); }; From 2c75dce5163c711a1e4a891a646be2f16581f6df Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Wed, 7 Jun 2023 21:31:08 +0300 Subject: [PATCH 07/15] ArwDecoder::DecodeLJpeg(): add missing `#pragma omp parallel` `#pragma omp for` is non-sensical on itself. --- src/librawspeed/decoders/ArwDecoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librawspeed/decoders/ArwDecoder.cpp b/src/librawspeed/decoders/ArwDecoder.cpp index 972719eb3..c9f7b69ff 100644 --- a/src/librawspeed/decoders/ArwDecoder.cpp +++ b/src/librawspeed/decoders/ArwDecoder.cpp @@ -331,7 +331,7 @@ void ArwDecoder::DecodeLJpeg(const TiffIFD* raw) const { mRaw->createData(); #ifdef HAVE_OPENMP -#pragma omp for schedule(static) +#pragma omp parallel for schedule(static) #endif for (uint32_t tile = 0U; tile < offsets->count; tile++) { const uint32_t tileX = tile % tilesX; From d18f1cf19d448f6bb20e7df28a34cfda713cc9a9 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Wed, 7 Jun 2023 21:38:40 +0300 Subject: [PATCH 08/15] ArwDecoder::DecodeLJpeg(): explicitly spell out OMP data sharing attributes --- src/librawspeed/decoders/ArwDecoder.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librawspeed/decoders/ArwDecoder.cpp b/src/librawspeed/decoders/ArwDecoder.cpp index c9f7b69ff..05f13b154 100644 --- a/src/librawspeed/decoders/ArwDecoder.cpp +++ b/src/librawspeed/decoders/ArwDecoder.cpp @@ -331,7 +331,8 @@ void ArwDecoder::DecodeLJpeg(const TiffIFD* raw) const { mRaw->createData(); #ifdef HAVE_OPENMP -#pragma omp parallel for schedule(static) +#pragma omp parallel for schedule(static) default(none) \ + shared(offsets, counts) firstprivate(tilesX, tilew, tileh) #endif for (uint32_t tile = 0U; tile < offsets->count; tile++) { const uint32_t tileX = tile % tilesX; From 21a77160e2922fb7ae735fd13f15314041c14afa Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Wed, 7 Jun 2023 21:44:34 +0300 Subject: [PATCH 09/15] ArwDecoder::DecodeLJpeg(): workaround false-positive UBSan w/ OMP Looks like UBSan sanitizes even the OpenMP-produced synthetic computations, and thus `rwDecoder.cpp:337:5: runtime error: unsigned integer overflow: 0 - 1 cannot be represented in type 'unsigned int'`. --- src/librawspeed/decoders/ArwDecoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librawspeed/decoders/ArwDecoder.cpp b/src/librawspeed/decoders/ArwDecoder.cpp index 05f13b154..deb27d99a 100644 --- a/src/librawspeed/decoders/ArwDecoder.cpp +++ b/src/librawspeed/decoders/ArwDecoder.cpp @@ -334,7 +334,7 @@ void ArwDecoder::DecodeLJpeg(const TiffIFD* raw) const { #pragma omp parallel for schedule(static) default(none) \ shared(offsets, counts) firstprivate(tilesX, tilew, tileh) #endif - for (uint32_t tile = 0U; tile < offsets->count; tile++) { + 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); From bccdeb57070af64349fedcb298cfbd7959e8a4a6 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Wed, 7 Jun 2023 21:59:20 +0300 Subject: [PATCH 10/15] ArwDecoder::DecodeLJpeg(): width is a multiple of 2 --- src/librawspeed/decoders/ArwDecoder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librawspeed/decoders/ArwDecoder.cpp b/src/librawspeed/decoders/ArwDecoder.cpp index deb27d99a..f692d3bc0 100644 --- a/src/librawspeed/decoders/ArwDecoder.cpp +++ b/src/librawspeed/decoders/ArwDecoder.cpp @@ -293,8 +293,8 @@ void ArwDecoder::DecodeLJpeg(const TiffIFD* raw) const { ThrowRDE("Unexpected bits per pixel: %u", bitPerPixel); } - if (width == 0 || height == 0 || height % 2 != 0 || width > 9728 || - height > 6656) + 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); From 11c4208b4741babab50ccc85fab05cd0253f1db6 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Wed, 7 Jun 2023 23:17:30 +0300 Subject: [PATCH 11/15] ArwDecoder::DecodeLJpeg(): pacify clang-tidy's readability-simplify-boolean-expr --- src/librawspeed/decoders/ArwDecoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librawspeed/decoders/ArwDecoder.cpp b/src/librawspeed/decoders/ArwDecoder.cpp index f692d3bc0..413cb14f3 100644 --- a/src/librawspeed/decoders/ArwDecoder.cpp +++ b/src/librawspeed/decoders/ArwDecoder.cpp @@ -302,7 +302,7 @@ void ArwDecoder::DecodeLJpeg(const TiffIFD* raw) const { const uint32_t tilew = raw->getEntry(TiffTag::TILEWIDTH)->getU32(); const uint32_t tileh = raw->getEntry(TiffTag::TILELENGTH)->getU32(); - if (!(tilew > 0 && tileh > 0)) + if (tilew <= 0 || tileh <= 0) ThrowRDE("Invalid tile size: (%u, %u)", tilew, tileh); assert(tilew > 0); From 03cbda7a7df3c2370052c36bb08f2a4983d01a32 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Thu, 8 Jun 2023 23:04:20 +0300 Subject: [PATCH 12/15] ArwDecoder: LJpeg: deal with interleaving ourselves. --- src/librawspeed/decoders/ArwDecoder.cpp | 53 ++++++++++++++++++++++--- src/librawspeed/decoders/ArwDecoder.h | 4 +- 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/librawspeed/decoders/ArwDecoder.cpp b/src/librawspeed/decoders/ArwDecoder.cpp index 413cb14f3..57a4cbde0 100644 --- a/src/librawspeed/decoders/ArwDecoder.cpp +++ b/src/librawspeed/decoders/ArwDecoder.cpp @@ -20,6 +20,7 @@ */ #include "decoders/ArwDecoder.h" +#include "MemorySanitizer.h" // for MSan #include "adt/NORangesSet.h" // for NORangesSet #include "adt/Point.h" // for iPoint2D #include "common/Common.h" // for roundDown @@ -279,7 +280,7 @@ void ArwDecoder::DecodeUncompressed(const TiffIFD* raw) const { } } -void ArwDecoder::DecodeLJpeg(const TiffIFD* raw) const { +void ArwDecoder::DecodeLJpeg(const TiffIFD* raw) { uint32_t width = raw->getEntry(TiffTag::IMAGEWIDTH)->getU32(); uint32_t height = raw->getEntry(TiffTag::IMAGELENGTH)->getU32(); uint32_t bitPerPixel = raw->getEntry(TiffTag::BITSPERSAMPLE)->getU32(); @@ -297,14 +298,17 @@ void ArwDecoder::DecodeLJpeg(const TiffIFD* raw) const { width > 9728 || height > 6656) ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height); - mRaw->dim = iPoint2D(width, height); + mRaw->dim = iPoint2D(2 * width, height / 2); - const uint32_t tilew = raw->getEntry(TiffTag::TILEWIDTH)->getU32(); - const uint32_t tileh = raw->getEntry(TiffTag::TILELENGTH)->getU32(); + uint32_t tilew = raw->getEntry(TiffTag::TILEWIDTH)->getU32(); + uint32_t tileh = raw->getEntry(TiffTag::TILELENGTH)->getU32(); - if (tilew <= 0 || tileh <= 0) + if (tilew <= 0 || tileh <= 0 || tileh % 2 != 0) ThrowRDE("Invalid tile size: (%u, %u)", tilew, tileh); + tileh /= 2; + tilew *= 2; + assert(tilew > 0); const uint32_t tilesX = roundUpDivision(mRaw->dim.x, tilew); if (!tilesX) @@ -342,10 +346,12 @@ void ArwDecoder::DecodeLJpeg(const TiffIFD* raw) const { LJpegDecoder decoder(ByteStream(DataBuffer(mFile.getSubView(offset, length), Endianness::little)), - mRaw, true); + mRaw); decoder.decode(tileX * tilew, tileY * tileh, tilew, tileh, false); } + PostProcessLJpeg(); + const TiffEntry* size_entry = raw->hasEntry(TiffTag::SONYRAWIMAGESIZE) ? raw->getEntry(TiffTag::SONYRAWIMAGESIZE) : raw->getEntry(TiffTag::DEFAULTCROPSIZE); @@ -353,6 +359,41 @@ void ArwDecoder::DecodeLJpeg(const TiffIFD* raw) const { mRaw->subFrame(crop); } +void ArwDecoder::PostProcessLJpeg() { + MSan::CheckMemIsInitialized(mRaw->getByteDataAsUncroppedArray2DRef()); + RawImage nonInterleavedRaw = mRaw; + + invariant(nonInterleavedRaw->dim.x % 4 == 0); + iPoint2D interleavedDims = {nonInterleavedRaw->dim.x / 2, + 2 * nonInterleavedRaw->dim.y}; + mRaw = RawImage::create(interleavedDims, RawImageType::UINT16, 1); + + const Array2DRef in = + nonInterleavedRaw->getU16DataAsUncroppedArray2DRef(); + const Array2DRef out = mRaw->getU16DataAsUncroppedArray2DRef(); + + constexpr iPoint2D inMCUSize = {4, 1}; + constexpr iPoint2D outMCUSize = {2, 2}; + +#ifdef HAVE_OPENMP +#pragma omp parallel for schedule(static) default(none) firstprivate(in, out) +#endif + for (int inRow = 0; inRow < in.height; ++inRow) { + invariant(in.width % inMCUSize.x == 0); + for (int MCUIdx = 0, numMCUsPerRow = in.width / inMCUSize.x; + MCUIdx < numMCUsPerRow; ++MCUIdx) { + for (int outMCURow = 0; outMCURow != outMCUSize.y; ++outMCURow) { + for (int outMCUСol = 0; outMCUСol != outMCUSize.x; ++outMCUСol) { + out(outMCUSize.y * inRow + outMCURow, + outMCUSize.x * MCUIdx + outMCUСol) = + in(inRow, + MCUIdx * inMCUSize.x + outMCUSize.x * outMCURow + outMCUСol); + } + } + } + } +} + void ArwDecoder::DecodeARW2(ByteStream input, uint32_t w, uint32_t h, uint32_t bpp) { diff --git a/src/librawspeed/decoders/ArwDecoder.h b/src/librawspeed/decoders/ArwDecoder.h index 7e6adf6b4..9adae856e 100644 --- a/src/librawspeed/decoders/ArwDecoder.h +++ b/src/librawspeed/decoders/ArwDecoder.h @@ -49,12 +49,12 @@ 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 DecodeLJpeg(const TiffIFD* raw); + void PostProcessLJpeg(); void DecodeUncompressed(const TiffIFD* raw) const; static void SonyDecrypt(const uint32_t* ibuf, uint32_t* obuf, uint32_t len, uint32_t key); void GetWB() const; - ByteStream in; int mShiftDownScale = 0; int mShiftDownScaleForExif = 0; }; From aa59c474da3042163e2471d68c7301cdceb0c62f Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Thu, 8 Jun 2023 23:05:09 +0300 Subject: [PATCH 13/15] Backout rest of `LJpegDecoder` / `LJpegDecompressor` changes. --- .../decompressors/LJpegDecoder.cpp | 8 ++-- src/librawspeed/decompressors/LJpegDecoder.h | 3 +- .../decompressors/LJpegDecompressor.cpp | 45 +++++-------------- .../decompressors/LJpegDecompressor.h | 4 +- 4 files changed, 15 insertions(+), 45 deletions(-) diff --git a/src/librawspeed/decompressors/LJpegDecoder.cpp b/src/librawspeed/decompressors/LJpegDecoder.cpp index 6cb8ccf51..8bf8b222d 100644 --- a/src/librawspeed/decompressors/LJpegDecoder.cpp +++ b/src/librawspeed/decompressors/LJpegDecoder.cpp @@ -36,9 +36,8 @@ using std::copy_n; namespace rawspeed { -LJpegDecoder::LJpegDecoder(ByteStream bs, const RawImage& img, - bool interleaveRows_) - : AbstractLJpegDecoder(bs, img), interleaveRows{interleaveRows_} { +LJpegDecoder::LJpegDecoder(ByteStream bs, const RawImage& img) + : AbstractLJpegDecoder(bs, img) { if (mRaw->getDataType() != RawImageType::UINT16) ThrowRDE("Unexpected data type (%u)", static_cast(mRaw->getDataType())); @@ -114,8 +113,7 @@ void LJpegDecoder::decodeScan() { LJpegDecompressor d( mRaw, iRectangle2D({(int)offX, (int)offY}, {(int)w, (int)h}), - LJpegDecompressor::Frame{N_COMP, iPoint2D(frame.w, frame.h)}, rec, input, - interleaveRows); + LJpegDecompressor::Frame{N_COMP, iPoint2D(frame.w, frame.h)}, rec, input); d.decode(); } diff --git a/src/librawspeed/decompressors/LJpegDecoder.h b/src/librawspeed/decompressors/LJpegDecoder.h index 4374e7c5c..9160e35e0 100644 --- a/src/librawspeed/decompressors/LJpegDecoder.h +++ b/src/librawspeed/decompressors/LJpegDecoder.h @@ -37,10 +37,9 @@ 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, bool interleaveRows = false); + LJpegDecoder(ByteStream bs, const RawImage& img); 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 85d203f92..090898f63 100644 --- a/src/librawspeed/decompressors/LJpegDecompressor.cpp +++ b/src/librawspeed/decompressors/LJpegDecompressor.cpp @@ -40,9 +40,9 @@ namespace rawspeed { LJpegDecompressor::LJpegDecompressor(const RawImage& img, iRectangle2D imgFrame_, Frame frame_, std::vector rec_, - ByteStream bs, bool interleaveRows_) + ByteStream bs) : mRaw(img), input(bs), imgFrame(imgFrame_), frame(std::move(frame_)), - rec(std::move(rec_)), interleaveRows{interleaveRows_} { + rec(std::move(rec_)) { if (mRaw->getDataType() != RawImageType::UINT16) ThrowRDE("Unexpected data type (%u)", static_cast(mRaw->getDataType())); @@ -100,19 +100,16 @@ LJpegDecompressor::LJpegDecompressor(const RawImage& img, ThrowRDE("Got less pixels than the components per sample"); // How many output pixels are we expected to produce, as per DNG tiling? - const auto interleaveFactor = interleaveRows ? 2 : 1; - const int tileRequiredWidth = - (int)mRaw->getCpp() * imgFrame.dim.x * interleaveFactor; - // How many of these rows do we need? - const auto numRows = imgFrame.dim.y / interleaveFactor; + const int tileRequiredWidth = (int)mRaw->getCpp() * imgFrame.dim.x; // 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 < numRows || + frame.dim.x < blocksToConsume || frame.dim.y < imgFrame.dim.y || (int64_t)frame.cps * frame.dim.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, numRows); + frame.cps * frame.dim.x, frame.dim.y, tileRequiredWidth, + imgFrame.dim.y); } // How many full pixel blocks will we produce? @@ -151,20 +148,17 @@ template void LJpegDecompressor::decodeN() { invariant(N_COMP > 0); invariant(N_COMP >= mRaw->getCpp()); invariant((N_COMP / mRaw->getCpp()) > 0); - invariant(((N_COMP & 1) == 0) | !interleaveRows); invariant(mRaw->dim.x >= N_COMP); invariant((mRaw->getCpp() * (mRaw->dim.x - imgFrame.pos.x)) >= N_COMP); - auto interleaveHeight = (interleaveRows ? 2 : 1); - auto interleaveWidth = N_COMP / interleaveHeight; - const CroppedArray2DRef img(mRaw->getU16DataAsUncroppedArray2DRef(), mRaw->getCpp() * imgFrame.pos.x, imgFrame.pos.y, mRaw->getCpp() * imgFrame.dim.x, imgFrame.dim.y); const auto ht = getPrefixCodeDecoders(); auto pred = getInitialPreds(); + uint16_t* predNext = pred.data(); BitPumpJPEG bitStream(input); @@ -172,24 +166,20 @@ 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); // FIXME + invariant(frame.dim.y >= imgFrame.dim.y); invariant((int64_t)frame.cps * frame.dim.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); - const auto numRows = imgFrame.dim.y / interleaveHeight; - // For y, we can simply stop decoding when we reached the border. - for (int row = 0; row < numRows; ++row) { + for (int row = 0; row < imgFrame.dim.y; ++row) { int col = 0; - /* copy_n(predNext, N_COMP, pred.data()); // the predictor for the next line is the start of this line predNext = &img(row, col); - */ // FIXME: predictor may have value outside of the uint16_t. // https://github.com/darktable-org/rawspeed/issues/175 @@ -200,12 +190,7 @@ template void LJpegDecompressor::decodeN() { pred[i] = uint16_t( pred[i] + ((const PrefixCodeDecoder<>&)(ht[i])).decodeDifference(bitStream)); - if (interleaveRows) { - img((row * interleaveHeight) + (i / interleaveHeight), - (col / interleaveWidth) + (i % interleaveWidth)) = pred[i]; - } else { - img(row, col + i) = pred[i]; - } + img(row, col + i) = pred[i]; } } @@ -238,16 +223,6 @@ template void LJpegDecompressor::decodeN() { for (int i = 0; i != N_COMP; ++i) ((const PrefixCodeDecoder<>&)(ht[i])).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 - if (interleaveRows) { - copy_n(&img(row * interleaveHeight, 0), interleaveWidth, pred.data()); - copy_n(&img(row * interleaveHeight + 1, 0), interleaveWidth, - pred.data() + interleaveWidth); - } else { - copy_n(&img(row, 0), N_COMP, pred.data()); - } } } diff --git a/src/librawspeed/decompressors/LJpegDecompressor.h b/src/librawspeed/decompressors/LJpegDecompressor.h index 969310d20..44151a2d6 100644 --- a/src/librawspeed/decompressors/LJpegDecompressor.h +++ b/src/librawspeed/decompressors/LJpegDecompressor.h @@ -58,7 +58,6 @@ class LJpegDecompressor final { int fullBlocks = 0; int trailingPixels = 0; - bool interleaveRows = false; template [[nodiscard]] std::array>, @@ -77,8 +76,7 @@ class LJpegDecompressor final { public: LJpegDecompressor(const RawImage& img, iRectangle2D imgFrame, Frame frame, - std::vector rec, ByteStream bs, - bool interleaveRows = false); + std::vector rec, ByteStream bs); void decode(); }; From d884d12ef611dd74b1dace33c90548ab85f4cb87 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Thu, 8 Jun 2023 23:19:12 +0300 Subject: [PATCH 14/15] Pacify GCC --- src/librawspeed/decoders/ArwDecoder.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librawspeed/decoders/ArwDecoder.cpp b/src/librawspeed/decoders/ArwDecoder.cpp index 57a4cbde0..8e167a98f 100644 --- a/src/librawspeed/decoders/ArwDecoder.cpp +++ b/src/librawspeed/decoders/ArwDecoder.cpp @@ -372,13 +372,13 @@ void ArwDecoder::PostProcessLJpeg() { nonInterleavedRaw->getU16DataAsUncroppedArray2DRef(); const Array2DRef out = mRaw->getU16DataAsUncroppedArray2DRef(); - constexpr iPoint2D inMCUSize = {4, 1}; - constexpr iPoint2D outMCUSize = {2, 2}; - #ifdef HAVE_OPENMP #pragma omp parallel for schedule(static) default(none) firstprivate(in, out) #endif for (int inRow = 0; inRow < in.height; ++inRow) { + static constexpr iPoint2D inMCUSize = {4, 1}; + static constexpr iPoint2D outMCUSize = {2, 2}; + invariant(in.width % inMCUSize.x == 0); for (int MCUIdx = 0, numMCUsPerRow = in.width / inMCUSize.x; MCUIdx < numMCUsPerRow; ++MCUIdx) { From 242017143fd2116413899090712ba1566727f377 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Thu, 8 Jun 2023 23:32:24 +0300 Subject: [PATCH 15/15] Backout `ArwDecoder::DecodeUncompressed()` change --- src/librawspeed/decoders/ArwDecoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librawspeed/decoders/ArwDecoder.cpp b/src/librawspeed/decoders/ArwDecoder.cpp index 8e167a98f..bdb5a79f1 100644 --- a/src/librawspeed/decoders/ArwDecoder.cpp +++ b/src/librawspeed/decoders/ArwDecoder.cpp @@ -255,7 +255,7 @@ void ArwDecoder::DecodeUncompressed(const TiffIFD* raw) const { mRaw->dim = iPoint2D(width, height); - if (width == 0 || height == 0 || width > 9728 || height > 6656) + if (width == 0 || height == 0 || width > 9600 || height > 6376) ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height); if (c2 == 0)