RawSpeed
fast raw decoding library
Loading...
Searching...
No Matches
PrefixCodeLUTDecoder.h
Go to the documentation of this file.
1/*
2 RawSpeed - RAW file decoder.
3
4 Copyright (C) 2017 Axel Waggershauser
5 Copyright (C) 2017-2018 Roman Lebedev
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#pragma once
23
24#include "adt/Bit.h"
25#include "adt/Casts.h"
26#include "adt/Invariant.h"
29#include <cassert>
30#include <cstddef>
31#include <cstdint>
32#include <tuple>
33#include <type_traits>
34#include <vector>
35
36/*
37 * The following code is inspired by the IJG JPEG library.
38 *
39 * Copyright (C) 1991, 1992, Thomas G. Lane.
40 * Part of the Independent JPEG Group's software.
41 * See the file Copyright for more details.
42 *
43 * Copyright (c) 1993 Brian C. Smith, The Regents of the University
44 * of California
45 * All rights reserved.
46 *
47 * Copyright (c) 1994 Kongji Huang and Brian C. Smith.
48 * Cornell University
49 * All rights reserved.
50 *
51 * Permission to use, copy, modify, and distribute this software and its
52 * documentation for any purpose, without fee, and without written agreement is
53 * hereby granted, provided that the above copyright notice and the following
54 * two paragraphs appear in all copies of this software.
55 *
56 * IN NO EVENT SHALL CORNELL UNIVERSITY BE LIABLE TO ANY PARTY FOR
57 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
58 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF CORNELL
59 * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60 *
61 * CORNELL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
62 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
63 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
64 * ON AN "AS IS" BASIS, AND CORNELL UNIVERSITY HAS NO OBLIGATION TO
65 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
66 */
67
68namespace rawspeed {
69
70template <typename CodeTag, typename BackendPrefixCodeDecoder>
72public:
73 using Tag = CodeTag;
75 using Traits = typename Base::Traits;
76
77 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
78 using Base::Base;
79
80private:
81 // lookup table containing 3 fields: payload:16|flag:8|len:8
82 // The payload may be the fully decoded diff or the length of the diff.
83 // The len field contains the number of bits, this lookup consumed.
84 // A lookup value of 0 means the code was too big to fit into the table.
85 // The optimal LookupDepth is also likely to depend on the CPU architecture.
86 static constexpr unsigned PayloadShift = 9;
87 static constexpr unsigned FlagMask = 0x100;
88 static constexpr unsigned LenMask = 0xff;
89 static constexpr unsigned LookupDepth = 11;
91 using LUTUnsignedEntryTy = std::make_unsigned_t<LUTEntryTy>;
92 std::vector<LUTEntryTy> decodeLookup;
93
94public:
95 void setup(bool fullDecode_, bool fixDNGBug16_) {
96 Base::setup(fullDecode_, fixDNGBug16_);
97
98 // Generate lookup table for fast decoding lookup.
99 // See definition of decodeLookup above
100 decodeLookup.resize(1 << LookupDepth);
101 for (size_t i = 0; i < Base::code.symbols.size(); i++) {
102 uint8_t code_l = Base::code.symbols[i].code_len;
103 if (code_l > static_cast<int>(LookupDepth))
104 break;
105
106 auto ll = implicit_cast<uint16_t>(Base::code.symbols[i].code
107 << (LookupDepth - code_l));
108 auto ul =
109 implicit_cast<uint16_t>(ll | ((1 << (LookupDepth - code_l)) - 1));
110 static_assert(Traits::MaxCodeValueLenghtBits <=
112 LUTUnsignedEntryTy diff_l = Base::code.codeValues[i];
113 for (uint16_t c = ll; c <= ul; c++) {
114 if (!(c < decodeLookup.size()))
115 ThrowRDE("Corrupt Huffman");
116
117 if (!FlagMask || !Base::isFullDecode() || code_l > LookupDepth ||
118 (code_l + diff_l > LookupDepth && diff_l != 16)) {
119 // lookup bit depth is too small to fit both the encoded length
120 // and the final difference value.
121 // -> store only the length and do a normal sign extension later
122 invariant(!Base::isFullDecode() || diff_l > 0);
123 decodeLookup[c] = diff_l << PayloadShift | code_l;
124
125 if (!Base::isFullDecode())
127 } else {
128 // Lookup bit depth is sufficient to encode the final value.
129 decodeLookup[c] = FlagMask | code_l;
130 if (diff_l != 16 || Base::handleDNGBug16())
131 decodeLookup[c] += diff_l;
132
133 if (diff_l) {
135 if (diff_l != 16) {
136 diff = extractHighBits(c, code_l + diff_l,
137 /*effectiveBitwidth=*/LookupDepth);
138 diff &= ((1 << diff_l) - 1);
139 } else {
140 diff = LUTUnsignedEntryTy(-32768);
141 }
142 decodeLookup[c] |= static_cast<LUTEntryTy>(
143 static_cast<LUTUnsignedEntryTy>(Base::extend(diff, diff_l))
144 << PayloadShift);
145 }
146 }
147 }
148 }
149 }
150
151 template <typename BIT_STREAM>
152 __attribute__((always_inline)) int decodeCodeValue(BIT_STREAM& bs) const {
153 static_assert(
155 "This BitStreamer specialization is not marked as usable here");
157 return decode<BIT_STREAM, false>(bs);
158 }
159
160 template <typename BIT_STREAM>
161 __attribute__((always_inline)) int decodeDifference(BIT_STREAM& bs) const {
162 static_assert(
164 "This BitStreamer specialization is not marked as usable here");
166 return decode<BIT_STREAM, true>(bs);
167 }
168
169 // The bool template paraeter is to enable two versions:
170 // one returning only the length of the of diff bits (see Hasselblad),
171 // one to return the fully decoded diff.
172 // All ifs depending on this bool will be optimized out by the compiler
173 template <typename BIT_STREAM, bool FULL_DECODE>
174 __attribute__((always_inline)) int decode(BIT_STREAM& bs) const {
175 static_assert(
177 "This BitStreamer specialization is not marked as usable here");
178 invariant(FULL_DECODE == Base::isFullDecode());
179 bs.fill(32);
180
181 typename Base::CodeSymbol partial;
182 partial.code_len = LookupDepth;
184 bs.peekBitsNoFill(partial.code_len));
185
186 assert(partial.code < decodeLookup.size());
187 auto lutEntry = static_cast<unsigned>(decodeLookup[partial.code]);
188 int payload = static_cast<int>(lutEntry) >> PayloadShift;
189 int len = lutEntry & LenMask;
190
191 // How far did reading of those LookupDepth bits *actually* move us forward?
192 bs.skipBitsNoFill(len);
193
194 // If the flag bit is set, then we have already skipped all the len bits
195 // we needed to skip, and payload is the answer we were looking for.
196 if (lutEntry & FlagMask)
197 return payload;
198
199 typename Traits::CodeValueTy codeValue;
200 if (lutEntry) {
201 // If the flag is not set, but the entry is not empty,
202 // the payload is the code value for this symbol.
203 partial.code_len = implicit_cast<uint8_t>(len);
205 invariant(!FULL_DECODE || codeValue /*aka diff_l*/ > 0);
206 } else {
207 // No match in the lookup table, because either the code is longer
208 // than LookupDepth or the input is corrupt. Need to read more bits...
209 invariant(len == 0);
210 bs.skipBitsNoFill(partial.code_len);
211 std::tie(partial, codeValue) =
213 }
214
215 return Base::template processSymbol<BIT_STREAM, FULL_DECODE>(bs, partial,
216 codeValue);
217 }
218};
219
220} // namespace rawspeed
#define invariant(expr)
Definition Invariant.h:27
#define ThrowRDE(...)
assert(dim.area() >=area)
int processSymbol(BIT_STREAM &bs, CodeSymbol symbol, typename Traits::CodeValueTy codeValue) const
static int RAWSPEED_READNONE extend(uint32_t diff, uint32_t len)
__attribute__((always_inline)) int decodeDifference(BIT_STREAM &bs) const
__attribute__((always_inline)) int decodeCodeValue(BIT_STREAM &bs) const
void setup(bool fullDecode_, bool fixDNGBug16_)
__attribute__((always_inline)) int decode(BIT_STREAM &bs) const
std::pair< typename Base::CodeSymbol, int > finishReadingPartialSymbol(BIT_STREAM &bs, typename Base::CodeSymbol partial) const
Traits::CodeValueTy decodeCodeValue(BIT_STREAM &bs) const
AbstractPrefixCodeDecoder< CodeTag > Base
void setup(bool fullDecode_, bool fixDNGBug16_)
constexpr RAWSPEED_READNONE Ttgt implicit_cast(Tsrc value)
Definition Casts.h:32
constexpr unsigned RAWSPEED_READNONE bitwidth(T unused={})
Definition Bit.h:43
constexpr RAWSPEED_READNONE T extractHighBits(T value, unsigned nBits, unsigned effectiveBitwidth=bitwidth< T >())
Definition Bit.h:120