Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
3ee4910
LJpegDecoder: check that frame/tile areas match, not dimensions
LebedevRI Mar 19, 2024
63f7170
LJpegDecoder: Maximal output tile size should be a multiple of LJpeg …
LebedevRI Mar 25, 2024
97c82e3
LJpegDecoder: compute MCU layout from tile size and ljpeg frame size
LebedevRI Mar 19, 2024
01470cc
LJpegDecoder: extract `jpegFrameDim` helper variable
LebedevRI Mar 19, 2024
bce1bee
LJpegDecompressor: extract `cps` variable from `frame`
LebedevRI Mar 25, 2024
00ef6d6
LJpegDecoder: plumb `MCUSize` into `LJpegDecompressor`
LebedevRI Mar 25, 2024
debd42d
LJpegDecompressor: rewrite checks in ctor for MCU size
LebedevRI Mar 19, 2024
dfdbb30
LJpegDecompressor: we do not expect to support row-partial MCU's
LebedevRI Mar 25, 2024
087d5c6
LJpegDecompressor: template `decodeN()` on `MCUSize`
LebedevRI Mar 25, 2024
c64abc5
LJpegDecompressor: template `decodeRowN()` on `MCUSize`
LebedevRI Mar 25, 2024
f6214c3
LJpegDecompressor: `s/numRowsPerRestartInterval/numLJpegRowsPerRestar…
LebedevRI Mar 25, 2024
627ae6b
LJpegDecompressor: `s/rowOfRestartInterval/ljpegRowOfRestartInterval/`
LebedevRI Mar 25, 2024
08270f7
LJpegDecompressor: `s/row/ljpegRow/`
LebedevRI Mar 25, 2024
a5392fc
LJpegDecompressor: correctly calculate `numRestartIntervals`
LebedevRI Mar 25, 2024
16599fb
LJpegDecompressor: correctly calculate output row
LebedevRI Mar 25, 2024
a87d59c
LJpegDecompressor: `s/fullBlocks/numFullMCUs/`
LebedevRI Mar 26, 2024
43dea6c
LJpegDecompressor::decodeRowN(): iterate over mcu index, not col
LebedevRI Mar 26, 2024
acac68f
LJpegDecompressor: s/block/mcu/
LebedevRI Mar 26, 2024
af901e7
LJpegDecompressor: take `outStripe`, not `outRow`
LebedevRI Mar 26, 2024
ad03fff
LJpegDecompressor: actually produce a stripe
LebedevRI Mar 26, 2024
b6da886
LJpegDecompressor: rewrite predictor reloading
LebedevRI Mar 26, 2024
dfff2ae
LJpegDecompressor: extract `outTile` in the non-edge-pixel code
LebedevRI Mar 26, 2024
9f89219
LJpegDecompressor: drop incorrect invariant
LebedevRI Mar 26, 2024
e2ff718
LJpegDecompressor: support `{2,2}` MCU's
LebedevRI Mar 26, 2024
7d97477
ArwDecoder: LJpeg decompressor supports `{2,2}` MCU's, drop workaround
LebedevRI Mar 26, 2024
53dbe15
LJpegDecompressor: don't inline `decodeN()` into `decode()`
LebedevRI Mar 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions fuzz/librawspeed/decompressors/LJpegDecompressor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,12 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {

rawspeed::RawImage mRaw(CreateRawImage(bs));

const int N_COMP = bs.getI32();
const int MCU_w = bs.getI32();
const int MCU_h = 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)};
rawspeed::iPoint2D(MCU_w, MCU_h), rawspeed::iPoint2D(frame_w, frame_h)};

const unsigned num_recips = bs.getU32();

Expand Down Expand Up @@ -86,11 +87,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
return {*hts[i], initPred[i]};
});

const int numRowsPerRestartInterval = bs.getI32();
const int numLJpegRowsPerRestartInterval = bs.getI32();

rawspeed::LJpegDecompressor d(
mRaw, rawspeed::iRectangle2D(mRaw->dim.x, mRaw->dim.y), frame, rec,
numRowsPerRestartInterval,
numLJpegRowsPerRestartInterval,
bs.getSubStream(/*offset=*/0).peekRemainingBuffer().getAsArray1DRef());
mRaw->createData();
(void)d.decode();
Expand Down
2 changes: 1 addition & 1 deletion src/librawspeed/adt/Point.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class iPoint2D final {
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;
}

Expand Down
43 changes: 1 addition & 42 deletions src/librawspeed/decoders/ArwDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
*/

#include "decoders/ArwDecoder.h"
#include "MemorySanitizer.h"
#include "adt/Array1DRef.h"
#include "adt/Array2DRef.h"
#include "adt/Casts.h"
Expand Down Expand Up @@ -318,17 +317,14 @@ void ArwDecoder::DecodeLJpeg(const TiffIFD* raw) {
width > 9728 || height > 6656)
ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);

mRaw->dim = iPoint2D(2 * width, height / 2);
mRaw->dim = iPoint2D(width, height);

auto tilew = uint64_t(raw->getEntry(TiffTag::TILEWIDTH)->getU32());
uint32_t tileh = raw->getEntry(TiffTag::TILELENGTH)->getU32();

if (tilew <= 0 || tileh <= 0 || tileh % 2 != 0)
ThrowRDE("Invalid tile size: (%" PRIu64 ", %u)", tilew, tileh);

tileh /= 2;
tilew *= 2;

assert(tilew > 0);
const auto tilesX =
implicit_cast<uint32_t>(roundUpDivision(mRaw->dim.x, tilew));
Expand Down Expand Up @@ -409,48 +405,11 @@ void ArwDecoder::DecodeLJpeg(const TiffIFD* raw) {
firstErr.c_str());
}

PostProcessLJpeg();

const TiffEntry* size_entry = raw->getEntry(TiffTag::SONYRAWIMAGESIZE);
iRectangle2D crop(0, 0, size_entry->getU32(0), size_entry->getU32(1));
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<const uint16_t> in =
nonInterleavedRaw->getU16DataAsUncroppedArray2DRef();
const Array2DRef<uint16_t> out = mRaw->getU16DataAsUncroppedArray2DRef();

#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) {
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) {

Expand Down
1 change: 0 additions & 1 deletion src/librawspeed/decoders/ArwDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ class ArwDecoder final : public AbstractTiffDecoder {
RawImage decodeSRF();
void DecodeARW2(ByteStream input, uint32_t w, uint32_t h, uint32_t bpp);
void DecodeLJpeg(const TiffIFD* raw);
void PostProcessLJpeg();
void DecodeUncompressed(const TiffIFD* raw) const;
static void SonyDecrypt(Array1DRef<const uint8_t> ibuf,
Array1DRef<uint8_t> obuf, int len, uint32_t key);
Expand Down
29 changes: 19 additions & 10 deletions src/librawspeed/decompressors/LJpegDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,26 +125,35 @@ Buffer::size_type LJpegDecoder::decodeScan() {
const iRectangle2D imgFrame = {
{static_cast<int>(offX), static_cast<int>(offY)},
{static_cast<int>(w), static_cast<int>(h)}};
const LJpegDecompressor::Frame jpegFrame = {N_COMP,
iPoint2D(frame.w, frame.h)};
const auto jpegFrameDim = iPoint2D(frame.w, frame.h);

if (iPoint2D(mRaw->getCpp() * maxDim.x, maxDim.y) !=
iPoint2D(N_COMP * frame.w, frame.h))
ThrowRDE("LJpeg frame does not match maximal tile size");
auto maxRes = iPoint2D(mRaw->getCpp() * maxDim.x, maxDim.y);
if (maxRes.area() != N_COMP * jpegFrameDim.area())
ThrowRDE("LJpeg frame area does not match maximal tile area");

int numRowsPerRestartInterval;
if (maxRes.x % jpegFrameDim.x != 0 || maxRes.y % jpegFrameDim.y != 0)
ThrowRDE("Maximal output tile size is not a multiple of LJpeg frame size");

auto MCUSize = iPoint2D{maxRes.x / jpegFrameDim.x, maxRes.y / jpegFrameDim.y};
if (MCUSize.area() != implicit_cast<uint64_t>(N_COMP))
ThrowRDE("Unexpected MCU size, does not match LJpeg component count");

const LJpegDecompressor::Frame jpegFrame = {MCUSize, jpegFrameDim};

int numLJpegRowsPerRestartInterval;
if (numMCUsPerRestartInterval == 0) {
// Restart interval not enabled, so all of the rows
// are contained in the first (implicit) restart interval.
numRowsPerRestartInterval = jpegFrame.dim.y;
numLJpegRowsPerRestartInterval = jpegFrameDim.y;
} else {
const int numMCUsPerRow = jpegFrame.dim.x;
const int numMCUsPerRow = jpegFrameDim.x;
if (numMCUsPerRestartInterval % numMCUsPerRow != 0)
ThrowRDE("Restart interval is not a multiple of frame row size");
numRowsPerRestartInterval = numMCUsPerRestartInterval / numMCUsPerRow;
numLJpegRowsPerRestartInterval = numMCUsPerRestartInterval / numMCUsPerRow;
}

LJpegDecompressor d(mRaw, imgFrame, jpegFrame, rec, numRowsPerRestartInterval,
LJpegDecompressor d(mRaw, imgFrame, jpegFrame, rec,
numLJpegRowsPerRestartInterval,
input.peekRemainingBuffer().getAsArray1DRef());
return d.decode();
}
Expand Down
Loading