RawSpeed
fast raw decoding library
Loading...
Searching...
No Matches
Rw2Decoder.cpp
Go to the documentation of this file.
1/*
2 RawSpeed - RAW file decoder.
3
4 Copyright (C) 2009-2014 Klaus Post
5 Copyright (C) 2014 Pedro CĂ´rte-Real
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20*/
21
22#include "decoders/Rw2Decoder.h"
23#include "adt/Array1DRef.h"
25#include "adt/Array2DRef.h"
26#include "adt/Point.h"
28#include "common/BayerPhase.h"
29#include "common/Common.h"
30#include "common/RawImage.h"
38#include "io/Buffer.h"
39#include "io/ByteStream.h"
40#include "io/Endianness.h"
41#include "metadata/Camera.h"
43#include "tiff/TiffEntry.h"
44#include "tiff/TiffIFD.h"
45#include "tiff/TiffTag.h"
46#include <algorithm>
47#include <array>
48#include <cassert>
49#include <cmath>
50#include <cstdint>
51#include <limits>
52#include <memory>
53#include <string>
54#include <vector>
55
56using std::fabs;
57
58namespace rawspeed {
59
60class CameraMetaData;
61
63 [[maybe_unused]] Buffer file) {
64 const auto id = rootIFD->getID();
65 const std::string& make = id.make;
66
67 // FIXME: magic
68
69 return make == "Panasonic" || make == "LEICA" || make == "LEICA CAMERA AG";
70}
71
72namespace {
73
75template <typename T>
77 std::vector<T>& output) {
78 ByteStream bs = ifd.getEntry(tag)->getData();
79 output.resize(bs.getU16());
80
81 // Note: Relying on ByteStream and its parent classes to prevent out-of-bounds
82 // reading.
83 for (T& v : output)
84 v = bs.get<T>();
85}
86
90 std::vector<uint32_t> stripByteOffsets;
91 std::vector<uint32_t> stripLineOffsets;
92 std::vector<uint32_t> stripBitLengths;
93 std::vector<uint16_t> stripWidths;
94 std::vector<uint16_t> stripHeights;
97
99
101 std::vector<uint16_t> shiftDown;
102
104
105 void validate() const;
106
108
109 explicit DecompressorV8Params(const TiffIFD& ifd);
110};
111
113 const unsigned totalStrips = horizontalStripCount * verticalStripCount;
114
115 // Check that we won't be going OOB on any of these strip lists
116 if (totalStrips > stripByteOffsets.size())
117 ThrowRDE("Strip byte offset list does not have enough entries for the "
118 "number of strips!");
119 if (totalStrips > stripWidths.size())
120 ThrowRDE("Strip widths list does not have enough entries for the number of "
121 "strips!");
122 if (totalStrips > stripHeights.size())
123 ThrowRDE("Strip heights list does not have enough entries for the number "
124 "of strips!");
125 if (totalStrips > stripLineOffsets.size())
126 ThrowRDE("Strip line offset list does not have enough entries for the "
127 "number of strips!");
128 if (totalStrips > stripBitLengths.size())
129 ThrowRDE("Strip bit length list does not have enough entries for the "
130 "number of strips!");
131
132 if (std::any_of(shiftDown.begin(), shiftDown.end(),
133 [](uint16_t x) { return x != 0; })) {
134 ThrowRDE("Non-zero shift down value encountered! Shift down decoding has "
135 "never been tested!");
136 }
137
138 if (gammaClipVal != std::numeric_limits<uint16_t>::max()) {
139 ThrowRDE("Got non-no-op gammaClipVal (%u). Not known to happen "
140 "in-the-wild. Please file a bug!",
142 }
143}
144
146 // NOLINTBEGIN(cppcoreguidelines-prefer-member-initializer)
151
161
162 // Get decoder's initial prediction value:
163 // Note, the positions of the green samples are swapped. This is intentional,
164 // the original implementation did this each swap redundantly during decoding
165 // of each tile.
174
176
178 // NOLINTEND(cppcoreguidelines-prefer-member-initializer)
179
180 validate();
181}
182
185void populateGammaLUT(const DecompressorV8Params& mParams, const TiffIFD& ifd) {
186 std::vector<uint16_t> mGammaLUT;
187
188 // Retrieve encoded gamma curve from tags.
189 std::vector<uint32_t> encodedGammaPoints;
190 std::vector<uint32_t> encodedGammaSlopes;
192 encodedGammaPoints);
194 encodedGammaSlopes);
195
196 // Determine if the points and slopes are all set to zero and 65536
197 // respectively. If so, no gamma function needs to be applied. This is
198 // currently true of all tested RW2 files.
199 const bool gamamPointsAreIdentity =
200 std::all_of(encodedGammaPoints.cbegin(), encodedGammaPoints.cend(),
201 [](const uint32_t p) { return p == 0U; });
202 const bool gammaSlopesAreIdentity =
203 std::all_of(encodedGammaSlopes.cbegin(), encodedGammaSlopes.cend(),
204 [](const uint32_t s) { return s == 65536U; });
205
206 if (!gamamPointsAreIdentity || !gammaSlopesAreIdentity) {
207 // Generate gamma LUT based on retrieved curve.
208 ThrowRDE("Non-identity gamma curve encountered. Never encountered in any "
209 "testing samples!");
210
211#pragma GCC diagnostic push
212#pragma GCC diagnostic ignored "-Wunreachable-code"
213 if (encodedGammaPoints.size() != 6 || encodedGammaSlopes.size() != 6) {
214 ThrowRDE("Gamma curve point and/or slope list is not the expected length "
215 "of 6");
216 }
217#pragma GCC diagnostic pop
218 }
219}
220
221std::vector<Array1DRef<const uint8_t>>
222getInputStrips(const DecompressorV8Params& mParams, Buffer mInputFile) {
223 std::vector<Array1DRef<const uint8_t>> mStrips;
224
225 const int totalStrips =
227
228 for (int stripIdx = 0; stripIdx < totalStrips; ++stripIdx) {
229 const uint32_t stripSize = (mParams.stripBitLengths[stripIdx] + 7) / 8;
230 const uint32_t stripOffset = mParams.stripByteOffsets[stripIdx];
231
232 // Note: Relying on Buffer to catch OOB access attempts
233 DataBuffer stripBuffer(mInputFile.getSubView(stripOffset, stripSize),
235 mStrips.emplace_back(stripBuffer.getAsArray1DRef());
236 }
237
238 return mStrips;
239}
240
241} // namespace
242
244 parseCFA();
246 ThrowRDE("Unexpected CFA, only RGGB is supported");
247
248 const DecompressorV8Params mParams(raw);
249 populateGammaLUT(mParams, raw);
250 const std::vector<Array1DRef<const uint8_t>> mStrips =
251 getInputStrips(mParams, mFile);
252
254 mRaw->dim, mParams.initialPrediction, getAsArray1DRef(mStrips),
255 getAsArray1DRef(mParams.stripLineOffsets),
256 getAsArray1DRef(mParams.stripWidths),
257 getAsArray1DRef(mParams.stripHeights),
259
261 mRaw->createData();
262 v8.decompress();
263 return mRaw;
264}
265
267
268 const TiffIFD* raw = nullptr;
269 bool isOldPanasonic =
270 !mRootIFD->hasEntryRecursive(TiffTag::PANASONIC_STRIPOFFSET);
271
272 if (!isOldPanasonic)
273 raw = mRootIFD->getIFDWithTag(TiffTag::PANASONIC_STRIPOFFSET);
274 else
275 raw = mRootIFD->getIFDWithTag(TiffTag::STRIPOFFSETS);
276
277 uint32_t height = raw->getEntry(static_cast<TiffTag>(3))->getU16();
278 uint32_t width = raw->getEntry(static_cast<TiffTag>(2))->getU16();
279
280 if (isOldPanasonic) {
281 if (width == 0 || height == 0 || width > 4330 || height > 2751)
282 ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
283
284 const TiffEntry* offsets = raw->getEntry(TiffTag::STRIPOFFSETS);
285
286 if (offsets->count != 1) {
287 ThrowRDE("Multiple Strips found: %u", offsets->count);
288 }
289 uint32_t offset = offsets->getU32();
290 if (!mFile.isValid(offset))
291 ThrowRDE("Invalid image data offset, cannot decode.");
292
293 mRaw->dim = iPoint2D(width, height);
294
295 uint32_t size = mFile.getSize() - offset;
296
297 if (size >= width * height * 2) {
298 // It's completely unpacked little-endian
300 ByteStream(DataBuffer(mFile.getSubView(offset), Endianness::little)),
301 mRaw, iRectangle2D({0, 0}, iPoint2D(width, height)), 16 * width / 8,
302 16, BitOrder::LSB);
303 mRaw->createData();
304 u.decode12BitRawUnpackedLeftAligned<Endianness::little>();
305 } else if (size >= width * height * 3 / 2) {
306 // It's a packed format
308 ByteStream(DataBuffer(mFile.getSubView(offset), Endianness::little)),
309 mRaw, iRectangle2D({0, 0}, iPoint2D(width, height)),
310 (12 * width / 8) + ((width + 2) / 10), 12, BitOrder::LSB);
311 mRaw->createData();
312 u.decode12BitRawWithControl<Endianness::little>();
313 } else {
314 uint32_t section_split_offset = 0;
316 mRaw,
317 ByteStream(DataBuffer(mFile.getSubView(offset), Endianness::little)),
318 hints.contains("zero_is_not_bad"), section_split_offset);
319 mRaw->createData();
320 p.decompress();
321 }
322 } else {
323 mRaw->dim = iPoint2D(width, height);
324
326
327 if (offsets->count != 1) {
328 ThrowRDE("Multiple Strips found: %u", offsets->count);
329 }
330
331 uint32_t offset = offsets->getU32();
332
333 ByteStream bs(DataBuffer(mFile.getSubView(offset), Endianness::little));
334
335 uint16_t bitsPerSample = 12;
337 bitsPerSample = raw->getEntry(TiffTag::PANASONIC_BITSPERSAMPLE)->getU16();
338
339 switch (uint16_t version =
341 case 4: {
342 uint32_t section_split_offset = 0x1FF8;
343 PanasonicV4Decompressor p(mRaw, bs, hints.contains("zero_is_not_bad"),
344 section_split_offset);
345 mRaw->createData();
346 p.decompress();
347 return mRaw;
348 }
349 case 5: {
350 PanasonicV5Decompressor v5(mRaw, bs, bitsPerSample);
351 mRaw->createData();
352 v5.decompress();
353 return mRaw;
354 }
355 case 6: {
356 if (bitsPerSample != 14 && bitsPerSample != 12)
357 ThrowRDE("Version %i: unexpected bits per sample: %i", version,
358 bitsPerSample);
359
360 PanasonicV6Decompressor v6(mRaw, bs, bitsPerSample);
361 mRaw->createData();
362 v6.decompress();
363 return mRaw;
364 }
365 case 7: {
366 if (bitsPerSample != 14)
367 ThrowRDE("Version %i: unexpected bits per sample: %i", version,
368 bitsPerSample);
370 mRaw->createData();
371 v7.decompress();
372 return mRaw;
373 }
374 case 8: {
375 // Known values are 12, 14, and 16. Other less than 16 should decompress
376 // fine.
377 if (bitsPerSample > 16)
378 ThrowRDE("Version %i: unexpected bits per sample: %i", version,
379 bitsPerSample);
380 return decodeRawV8(*raw);
381 }
382 default:
383 ThrowRDE("Version %i is unsupported", version);
384 }
385 }
386
387 return mRaw;
388}
389
391 auto id = mRootIFD->getID();
392 if (!checkCameraSupported(meta, id, guessMode()))
393 checkCameraSupported(meta, id, "");
394}
395
397 if (!mRootIFD->hasEntryRecursive(TiffTag::PANASONIC_CFAPATTERN))
398 ThrowRDE("No PANASONIC_CFAPATTERN entry found!");
399
400 const TiffEntry* CFA =
401 mRootIFD->getEntryRecursive(TiffTag::PANASONIC_CFAPATTERN);
402 if (CFA->type != TiffDataType::SHORT || CFA->count != 1) {
403 ThrowRDE("Bad PANASONIC_CFAPATTERN entry (type %u, count %u).",
404 static_cast<unsigned>(CFA->type), CFA->count);
405 }
406
407 switch (auto i = CFA->getU16()) {
408 using enum CFAColor;
409 case 1:
410 mRaw->cfa.setCFA(iPoint2D(2, 2), RED, GREEN, GREEN, BLUE);
411 break;
412 case 2:
413 mRaw->cfa.setCFA(iPoint2D(2, 2), GREEN, RED, BLUE, GREEN);
414 break;
415 case 3:
416 mRaw->cfa.setCFA(iPoint2D(2, 2), GREEN, BLUE, RED, GREEN);
417 break;
418 case 4:
419 mRaw->cfa.setCFA(iPoint2D(2, 2), BLUE, GREEN, GREEN, RED);
420 break;
421 default:
422 ThrowRDE("Unexpected CFA pattern: %u", i);
423 }
424}
425
427 return mRootIFD->hasEntryRecursive(TiffTag::PANASONIC_STRIPOFFSET)
429 : mRootIFD->getIFDWithTag(TiffTag::STRIPOFFSETS);
430}
431
433 parseCFA();
434
435 auto id = mRootIFD->getID();
436 std::string mode = guessMode();
437 int iso = 0;
438 if (mRootIFD->hasEntryRecursive(TiffTag::PANASONIC_ISO_SPEED))
439 iso = mRootIFD->getEntryRecursive(TiffTag::PANASONIC_ISO_SPEED)->getU32();
440
441 if (this->checkCameraSupported(meta, id, mode)) {
442 setMetaData(meta, id, mode, iso);
443 } else {
444 mRaw->metadata.mode = mode;
445 writeLog(DEBUG_PRIO::EXTRA, "Mode not found in DB: %s", mode.c_str());
446 setMetaData(meta, id, "", iso);
447 }
448
449 const TiffIFD* raw = getRaw();
450
451 // Read blacklevels
452 if (raw->hasEntry(static_cast<TiffTag>(0x1c)) &&
453 raw->hasEntry(static_cast<TiffTag>(0x1d)) &&
454 raw->hasEntry(static_cast<TiffTag>(0x1e))) {
455 auto blackLevelsNeedOffsetting = [&]() {
456 bool isOldPanasonic =
457 !mRootIFD->hasEntryRecursive(TiffTag::PANASONIC_STRIPOFFSET);
458 if (isOldPanasonic)
459 return true;
460 const uint16_t version =
462 // After version 4 the black levels appears to be correct.
463 return version <= 4;
464 };
465 const auto getBlack = [&raw, blackLevelsNeedOffsetting](TiffTag t) {
466 const int val = raw->getEntry(t)->getU16();
467 if (!blackLevelsNeedOffsetting())
468 return val;
469 // Continue adding 15 for older raw versions.
470 int out;
471 if (__builtin_sadd_overflow(val, 15, &out))
472 ThrowRDE("Integer overflow when calculating black level");
473 return out;
474 };
475
476 const int blackRed = getBlack(static_cast<TiffTag>(0x1c));
477 const int blackGreen = getBlack(static_cast<TiffTag>(0x1d));
478 const int blackBlue = getBlack(static_cast<TiffTag>(0x1e));
479
480 mRaw->blackLevelSeparate =
481 Array2DRef(mRaw->blackLevelSeparateStorage.data(), 2, 2);
482 auto blackLevelSeparate1D = *mRaw->blackLevelSeparate->getAsArray1DRef();
483 for (int i = 0; i < 2; i++) {
484 for (int j = 0; j < 2; j++) {
485 const int k = i + (2 * j);
486 const CFAColor c = mRaw->cfa.getColorAt(i, j);
487 switch (c) {
488 case CFAColor::RED:
489 blackLevelSeparate1D(k) = blackRed;
490 break;
491 case CFAColor::GREEN:
492 blackLevelSeparate1D(k) = blackGreen;
493 break;
494 case CFAColor::BLUE:
495 blackLevelSeparate1D(k) = blackBlue;
496 break;
497 default:
498 ThrowRDE("Unexpected CFA color %s.",
500 }
501 }
502 }
503 }
504
505 // Read WB levels
506 if (raw->hasEntry(static_cast<TiffTag>(0x0024)) &&
507 raw->hasEntry(static_cast<TiffTag>(0x0025)) &&
508 raw->hasEntry(static_cast<TiffTag>(0x0026))) {
509 std::array<float, 4> wbCoeffs = {};
510 wbCoeffs[0] = static_cast<float>(
511 raw->getEntry(static_cast<TiffTag>(0x0024))->getU16());
512 wbCoeffs[1] = static_cast<float>(
513 raw->getEntry(static_cast<TiffTag>(0x0025))->getU16());
514 wbCoeffs[2] = static_cast<float>(
515 raw->getEntry(static_cast<TiffTag>(0x0026))->getU16());
516 mRaw->metadata.wbCoeffs = wbCoeffs;
517 } else if (raw->hasEntry(static_cast<TiffTag>(0x0011)) &&
518 raw->hasEntry(static_cast<TiffTag>(0x0012))) {
519 std::array<float, 4> wbCoeffs = {};
520 wbCoeffs[0] = static_cast<float>(
521 raw->getEntry(static_cast<TiffTag>(0x0011))->getU16());
522 wbCoeffs[1] = 256.0F;
523 wbCoeffs[2] = static_cast<float>(
524 raw->getEntry(static_cast<TiffTag>(0x0012))->getU16());
525 mRaw->metadata.wbCoeffs = wbCoeffs;
526 }
527}
528
529std::string Rw2Decoder::guessMode() const {
530 float ratio = 3.0F / 2.0F; // Default
531
532 if (!mRaw->isAllocated())
533 return "";
534
535 ratio = static_cast<float>(mRaw->dim.x) / static_cast<float>(mRaw->dim.y);
536
537 float min_diff = fabs(ratio - (16.0F / 9.0F));
538 std::string closest_match = "16:9";
539
540 float t = fabs(ratio - (3.0F / 2.0F));
541 if (t < min_diff) {
542 closest_match = "3:2";
543 min_diff = t;
544 }
545
546 t = fabs(ratio - (4.0F / 3.0F));
547 if (t < min_diff) {
548 closest_match = "4:3";
549 min_diff = t;
550 }
551
552 t = fabs(ratio - 1.0F);
553 if (t < min_diff) {
554 closest_match = "1:1";
555 min_diff = t;
556 }
557 writeLog(DEBUG_PRIO::EXTRA, "Mode guess: '%s'", closest_match.c_str());
558 return closest_match;
559}
560
562 if (const TiffIFD* raw = getRaw();
564 raw->hasEntry(TiffTag::PANASONIC_SENSORTOPBORDER) &&
567 const uint16_t leftBorder =
568 raw->getEntry(TiffTag::PANASONIC_SENSORLEFTBORDER)->getU16();
569 const uint16_t topBorder =
570 raw->getEntry(TiffTag::PANASONIC_SENSORTOPBORDER)->getU16();
571 const uint16_t rightBorder =
572 raw->getEntry(TiffTag::PANASONIC_SENSORRIGHTBORDER)->getU16();
573 const uint16_t bottomBorder =
574 raw->getEntry(TiffTag::PANASONIC_SENSORBOTTOMBORDER)->getU16();
575 const uint16_t width = rightBorder - leftBorder;
576 const uint16_t height = bottomBorder - topBorder;
577 return {leftBorder, topBorder, width, height};
578 }
579 ThrowRDE("Cannot figure out vendor crop. Required entries were not found: "
580 "%X, %X, %X, %X",
581 static_cast<unsigned int>(TiffTag::PANASONIC_SENSORLEFTBORDER),
582 static_cast<unsigned int>(TiffTag::PANASONIC_SENSORTOPBORDER),
583 static_cast<unsigned int>(TiffTag::PANASONIC_SENSORRIGHTBORDER),
584 static_cast<unsigned int>(TiffTag::PANASONIC_SENSORBOTTOMBORDER));
585}
586
587} // namespace rawspeed
#define s
#define ThrowRDE(...)
dim x
Definition Common.cpp:50
bool checkCameraSupported(const CameraMetaData *meta, const TiffID &id, const std::string &mode)
void setMetaData(const CameraMetaData *meta, const TiffID &id, const std::string &mode, int iso_speed)
Array1DRef< const uint8_t > getAsArray1DRef() const
Definition Buffer.h:70
Buffer getSubView(size_type offset, size_type size_) const
Definition Buffer.h:78
static std::string colorToString(CFAColor c)
void decompress() const noexcept
std::array< uint16_t, 4 > Bayer2x2
Four values, one for each component of the sensor's color filter array.
void decompress() const
Run the decompressor on the provided raw image.
std::string guessMode() const
iRectangle2D getDefaultCrop() override
void decodeMetaDataInternal(const CameraMetaData *meta) override
void parseCFA() const
void checkSupportInternal(const CameraMetaData *meta) override
RawImage decodeRawV8(const TiffIFD &raw) const
static bool isAppropriateDecoder(const TiffRootIFD *rootIFD, Buffer file)
const TiffIFD * getRaw() const
RawImage decodeRawInternal() override
Definition TiffEntry.h:62
uint32_t getU32(uint32_t index=0) const
ByteStream getData() const
Definition TiffEntry.h:129
uint32_t count
Definition TiffEntry.h:84
uint16_t getU16(uint32_t index=0) const
TiffDataType type
Definition TiffEntry.h:83
bool RAWSPEED_READONLY hasEntry(TiffTag tag) const
Definition TiffIFD.h:119
TiffEntry * getEntry(TiffTag tag) const
Definition TiffIFD.cpp:313
TiffID getID() const
Definition TiffIFD.cpp:325
void populateGammaLUT(const DecompressorV8Params &mParams, const TiffIFD &ifd)
std::vector< Array1DRef< const uint8_t > > getInputStrips(const DecompressorV8Params &mParams, Buffer mInputFile)
void getPanasonicTiffVector(const TiffIFD &ifd, TiffTag tag, std::vector< T > &output)
Retrieve list of values from Panasonic TiffTag.
Optional< BayerPhase > getAsBayerPhase(const ColorFilterArray &CFA)
Definition BayerPhase.h:131
throw T(buf.data())
void writeLog(DEBUG_PRIO priority, const char *format,...)
Definition Common.cpp:37
Array2DRef(Array1DRef< T > data, int width, int height, int pitch) -> Array2DRef< T >
Array1DRef< const T > getAsArray1DRef(const std::vector< T > &vec)
@ PANASONIC_V8_STRIP_BYTE_OFFSETS
Definition TiffTag.h:405
@ PANASONIC_V8_NUMBER_OF_STRIPS_V
Definition TiffTag.h:404
@ PANASONIC_V8_STRIP_WIDTHS
Definition TiffTag.h:408
@ PANASONIC_V8_NUMBER_OF_STRIPS_H
Definition TiffTag.h:403
@ PANASONIC_V8_STRIP_LINE_OFFSETS
Definition TiffTag.h:406
@ PANASONIC_V8_HUF_SHIFT_DOWN
Definition TiffTag.h:402
@ PANASONIC_V8_INIT_PRED_GREEN1
Definition TiffTag.h:398
@ PANASONIC_V8_INIT_PRED_BLUE
Definition TiffTag.h:400
@ PANASONIC_V8_GAMMA_SLOPES
Definition TiffTag.h:394
@ PANASONIC_SENSORTOPBORDER
Definition TiffTag.h:371
@ PANASONIC_SENSORLEFTBORDER
Definition TiffTag.h:372
@ PANASONIC_V8_INIT_PRED_RED
Definition TiffTag.h:397
@ PANASONIC_SENSORBOTTOMBORDER
Definition TiffTag.h:373
@ PANASONIC_V8_INIT_PRED_GREEN2
Definition TiffTag.h:399
@ PANASONIC_V8_STRIP_DATA_SIZE
Definition TiffTag.h:407
@ PANASONIC_V8_STRIP_HEIGHTS
Definition TiffTag.h:409
@ PANASONIC_V8_GAMMA_POINTS
Definition TiffTag.h:395
@ PANASONIC_SENSORRIGHTBORDER
Definition TiffTag.h:374
std::string make
Definition TiffIFD.h:134
std::vector< uint16_t > shiftDown
Decoding shift down value. Appears to be unused.