rawspeed
rawspeed copied to clipboard
LJpegDecompressor predictor mode 6 support
Comes up in Blackmagic cameras, Magic Lantern DNG's.
./Blackmagic/Pocket Cinema Camera/Blackmagic_Pocket_Cinema_Camera_1_2016-09-17_0053_C0022_000007.dng failed: ../src/librawspeed/decompressors/AbstractDngDecompressor.cpp:208: void rawspeed::AbstractDngDecompressor::decompress() const: Too many errors encountered. Giving up. First Error:
../src/librawspeed/decompressors/LJpegDecompressor.cpp:88: virtual void rawspeed::LJpegDecompressor::decodeScan(): Unsupported predictor mode: 6
./Blackmagic/URSA 4K/Blackmagic URSA_1_1999-12-31_2153_C0003_000001.dng failed: ../src/librawspeed/decompressors/AbstractDngDecompressor.cpp:208: void rawspeed::AbstractDngDecompressor::decompress() const: Too many errors encountered. Giving up. First Error:
../src/librawspeed/decompressors/LJpegDecompressor.cpp:88: virtual void rawspeed::LJpegDecompressor::decodeScan(): Unsupported predictor mode: 6
./Canon/EOS 5D Mark III/compress.dng failed: ../src/librawspeed/decompressors/AbstractDngDecompressor.cpp:208: void rawspeed::AbstractDngDecompressor::decompress() const: Too many errors encountered. Giving up. First Error:
../src/librawspeed/decompressors/LJpegDecompressor.cpp:88: virtual void rawspeed::LJpegDecompressor::decodeScan(): Unsupported predictor mode: 6
./Canon/EOS 60D/M14-1451_000085_cDNG_compressed.dng failed: ../src/librawspeed/decompressors/AbstractDngDecompressor.cpp:208: void rawspeed::AbstractDngDecompressor::decompress() const: Too many errors encountered. Giving up. First Error:
../src/librawspeed/decompressors/LJpegDecompressor.cpp:88: virtual void rawspeed::LJpegDecompressor::decodeScan(): Unsupported predictor mode: 6
Even w/ the predictor implemented, there is still some way to go - seems to be the BlackMagick TIFF tile tags vs LJpeg SOF3 frame geometry is a bit wonky/unexpected compared to "normal" CFA lossless DNGs?
[rawspeed] (Blackmagic - URSA 4K - 12bit (16_9).dng) C:/msys64/home/kmilos/darktable/src/external/rawspeed/src/librawspeed/decompressors/AbstractDngDecompressor.cpp:217: void rawspeed::AbstractDngDecompressor::decompress() const: Too many errors encountered. Giving up. First Error:
C:/msys64/home/kmilos/darktable/src/external/rawspeed/src/librawspeed/decompressors/LJpegDecompressor.cpp:112: virtual void rawspeed::LJpegDecompressor::decodeScan(): LJpeg frame (1008, 1096) is smaller than expected (504, 2192)
Yep, unlike Adobe's "normal" lossless mode that has an SOF3 w/ H x W/2 x 2ch and matching TIFF tiles of H x W after reshaping, the Blackmagic SOF3 in the URSA 4K really is FF D8 FF C3 00 0B 0C 04 48 03 F0 01 00 11 00
, i.e. 1096 x 1008 x 1ch, while the TIFF tags are
Exif.Image.TileWidth 504
Exif.Image.TileLength 2192
Not sure which one of them is wrong and how to reshape, could be that it is H/2 x 2W x 1 -> H x W? In any case this test/assumption breaks.
Did a quick test of manually changing the TIFF tags, and the results is not good (output image is sliced up incorrectly), so it really does seem the "special" reshaping needs to be done at the SOF3 decoding stage.
Yay, more Ljpeg fun - predictor 6 just popped up in DJI Mavic 3 Pro DNGs as well...
TileWidth : 4000
TileLength : 3000
w/
SOF3 (8000x1500): FF C3 00 0B 10 05 DC 1F 40 01 00 11 00
SOS: FF DA 00 08 01 00 00 06 00 00
Edit: This is the same 2W x H/2 scatter/gather as Blackmagic.
While the Sony ARW case was somewhat straightforward (we know a priori how to reshape the TIFF tiles, decompress, and then deinterleave back because it is the sole ARW lossless mode), it is not so for these Blackmagic/DJI/MLV CinemaDNGs - the tiling in the DngDecoder is done before any LJpeg parsing, and there is no other way to tell one needs the tile reshaping and subsequent deinterleaving compared to "traditional" DNGs.
So the ideal flow after refactoring should be:
- Parse LJpeg SOF3 first to get frame.h, frame.w, and frame.cps
- Ensure that frame.cps * frame.w * frame.h == tilew * tileh (* spp?)
- DngDecoder reshapes tilew = frame.cps * frame.w (/spp?), tileh = frame.h
- Only then get DngTilingDescription
- Decompress
- Deinterleave if reshaped previously
Right now, the DNG tiling (coming first) and LJpeg parsing are completely independent.
Apologies if i have asked this before, but do we have example DNG's with predictor=0, with such an LJpeg structure (that requires reshaping)?
predictor=0 is not really valid/supported, did you mean 6? If so, then, yes, we do have several samples on RPU.
Please also note that I have updated the diagram - I now believe the reshaping and deinterleaving works out to be the same as the Sony case, despite the MCU difference.
predictor=0 is not really valid/supported, did you mean 6? If so, then, yes, we do have several samples on RPU.
Err, i meant whatever we currently already support, i.e. predictor=1
.
i meant whatever we currently already support, i.e.
predictor=1
The known predictor=1 files (at least to me) are:
- Adobe lossless DNGs (MCU has 2 components, and we already support tilew = 2 * frame.w "reshaping" so to speak)
- various LinerRaw DNGs (trivial, as many components as color planes, no reshaping needed)
- now Sony ARWs (MCU has 4 components, we reshape to tilew*2 x tileh/2, then deinterlace)
All others seem to require either predictor 6 or 7 supported AFAIK...
So, chicken and egg it would seem ;) As mentioned above - I have managed to decompress successfully w/ my "dumb" predictor patch (and by fudging the tiles in TIFF metadata manually), but the image comes out interlaced of course.
@LebedevRI Note that the TIFF tile <-> JPEG SOF reshaping takes place for the lossy DNG mode as well, so ljpeg is probably not the place to address that in the abstraction hierarchy.
This is from the Blackmagic Pocket Cinema Camera 4K 3:1 lossy DNG:
TileWidth : 1032
TileLength : 2176
w/
SOF1 (lossy 2064x1088): FF C1 00 0B 0C 04 40 08 10 01 01 11 00
SOS: FF DA 00 08 01 01 00 00 3F 00
Ah, turns out the reshaping for Blackmagic is even simpler than I thought: it's still 2W x H/2, but instead of flattening 2x2 pixel CFA macroblock into 4x1, it is just deinterleaving entire 2 rows, so one just needs to decode it into an appropriate buffer and it's done! I updated the diagram accordingly.