RawSpeed
fast raw decoding library
Loading...
Searching...
No Matches
Cr2sRawInterpolator.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) 2015-2017 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#include "rawspeedconfig.h"
24#include "adt/Array2DRef.h"
25#include "adt/Bit.h"
27#include "adt/Invariant.h"
28#include "adt/Point.h"
29#include "common/Common.h"
30#include "common/RawImage.h"
32#include <array>
33#include <cstdint>
34
35namespace rawspeed {
36
38 int Y = 0;
39 int Cb = 0;
40 int Cr = 0;
41
42 static void LoadY(YCbCr* p, const CroppedArray1DRef<const uint16_t> in) {
43 invariant(p);
44 invariant(in.size() == 1);
45
46 p->Y = in(0);
47 }
48
50 invariant(p);
51 invariant(in.size() == 2);
52
53 p->Cb = in(0);
54 p->Cr = in(1);
55 }
56
57 static void CopyCbCr(YCbCr* p, const YCbCr& pSrc) {
58 invariant(p);
59
60 p->Cb = pSrc.Cb;
61 p->Cr = pSrc.Cr;
62 }
63
64 YCbCr() = default;
65
66 void signExtend() {
67 Cb -= 16384;
68 Cr -= 16384;
69 }
70
71 void applyHue(int hue_) {
72 Cb += hue_;
73 Cr += hue_;
74 }
75
76 void process(int hue_) {
77 signExtend();
78 applyHue(hue_);
79 }
80
81 void interpolateCbCr(const YCbCr& p0, const YCbCr& p2) {
82 // Y is already good, need to interpolate Cb and Cr
83 // FIXME: dcraw does +1 before >> 1
84 Cb = (p0.Cb + p2.Cb) >> 1;
85 Cr = (p0.Cr + p2.Cr) >> 1;
86 }
87
88 void interpolateCbCr(const YCbCr& p0, const YCbCr& p1, const YCbCr& p2,
89 const YCbCr& p3) {
90 // Y is already good, need to interpolate Cb and Cr
91 // FIXME: dcraw does +1 before >> 1
92 Cb = (p0.Cb + p1.Cb + p2.Cb + p3.Cb) >> 2;
93 Cr = (p0.Cr + p1.Cr + p2.Cr + p3.Cr) >> 2;
94 }
95};
96
97template <int version> void Cr2sRawInterpolator::interpolate_422_row(int row) {
98 const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());
99
100 constexpr int InputComponentsPerMCU = 4;
101 constexpr int PixelsPerMCU = 2;
102 constexpr int YsPerMCU = PixelsPerMCU;
103 constexpr int ComponentsPerPixel = 3;
104 constexpr int OutputComponentsPerMCU = ComponentsPerPixel * PixelsPerMCU;
105
106 invariant(input.width() % InputComponentsPerMCU == 0);
107 int numMCUs = input.width() / InputComponentsPerMCU;
108 invariant(numMCUs > 1);
109
110 using MCUTy = std::array<YCbCr, PixelsPerMCU>;
111
112 auto LoadMCU = [input_ = input, row](int MCUIdx) {
113 MCUTy MCU;
114 for (int YIdx = 0; YIdx < PixelsPerMCU; ++YIdx)
115 YCbCr::LoadY(&MCU[YIdx], input_[row].getCrop(
116 (InputComponentsPerMCU * MCUIdx) + YIdx, 1));
118 &MCU[0],
119 input_[row].getCrop((InputComponentsPerMCU * MCUIdx) + YsPerMCU, 2));
120 return MCU;
121 };
122 auto StoreMCU = [this, out, row](const MCUTy& MCU, int MCUIdx) {
123 for (int Pixel = 0; Pixel < PixelsPerMCU; ++Pixel) {
124 YUV_TO_RGB<version>(MCU[Pixel],
125 out[row].getCrop((OutputComponentsPerMCU * MCUIdx) +
126 (ComponentsPerPixel * Pixel),
127 3));
128 }
129 };
130
131 // The packed input format is:
132 // p0 p1 p0 p0 p2 p3 p2 p2
133 // [ Y1 Y2 Cb Cr ] [ Y1 Y2 Cb Cr ] ...
134 // in unpacked form that is:
135 // p0 p1 p2 p3
136 // [ Y1 Cb Cr ] [ Y2 ... ... ] [ Y1 Cb Cr ] [ Y2 ... ... ] ...
137 // i.e. even pixels are full, odd pixels need interpolation:
138 // p0 p1 p2 p3
139 // [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] ...
140 // for last (odd) pixel of the line, just keep Cb/Cr from previous pixel
141 // see http://lclevy.free.fr/cr2/#sraw
142
143 int MCUIdx;
144 // Process all MCU's except the last one.
145 for (MCUIdx = 0; MCUIdx < numMCUs - 1; ++MCUIdx) {
146 invariant(MCUIdx + 1 <= numMCUs);
147
148 // For 4:2:2, one MCU encodes 2 pixels, and odd pixels need interpolation,
149 // so we need to load three pixels, and thus we must load 2 MCU's.
150 std::array<MCUTy, 2> MCUs;
151 for (int SubMCUIdx = 0; static_cast<unsigned>(SubMCUIdx) < MCUs.size();
152 ++SubMCUIdx)
153 MCUs[SubMCUIdx] = LoadMCU(MCUIdx + SubMCUIdx);
154
155 // Process first pixel, which is full
156 MCUs[0][0].process(hue);
157 // Process third pixel, which is, again, full
158 MCUs[1][0].process(hue);
159 // Interpolate the middle pixel, for which only the Y was known.
160 MCUs[0][1].interpolateCbCr(MCUs[0][0], MCUs[1][0]);
161
162 // And finally, store the first MCU, i.e. first two pixels.
163 StoreMCU(MCUs[0], MCUIdx);
164 }
165
166 invariant(MCUIdx + 1 == numMCUs);
167
168 // Last two pixels, the packed input format is:
169 // p0 p1 p0 p0
170 // .. [ Y1 Y2 Cb Cr ]
171 // in unpacked form that is:
172 // p0 p1
173 // .. [ Y1 Cb Cr ] [ Y2 ... ... ]
174
175 MCUTy MCU = LoadMCU(MCUIdx);
176
177 MCU[0].process(hue);
178 YCbCr::CopyCbCr(&MCU[1], MCU[0]);
179
180 StoreMCU(MCU, MCUIdx);
181}
182
183template <int version> void Cr2sRawInterpolator::interpolate_422() {
184 const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());
185 invariant(out.width() > 0);
186 invariant(out.height() > 0);
187
188 // Benchmarking suggests that for real-world usage, it is not beneficial to
189 // parallelize this, and in fact leads to worse performance.
190 for (int row = 0; row < out.height(); row++)
192}
193
194template <int version> void Cr2sRawInterpolator::interpolate_420_row(int row) {
195 const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());
196
197 constexpr int X_S_F = 2;
198 constexpr int Y_S_F = 2;
199 constexpr int PixelsPerMCU = X_S_F * Y_S_F;
200 constexpr int InputComponentsPerMCU = 2 + PixelsPerMCU;
201
202 constexpr int YsPerMCU = PixelsPerMCU;
203 constexpr int ComponentsPerPixel = 3;
204 constexpr int OutputComponentsPerMCU = ComponentsPerPixel * PixelsPerMCU;
205
206 invariant(input.width() % InputComponentsPerMCU == 0);
207 int numMCUs = input.width() / InputComponentsPerMCU;
208 invariant(numMCUs > 1);
209
210 using MCUTy = std::array<std::array<YCbCr, X_S_F>, Y_S_F>;
211
212 auto LoadMCU = [input_ = input](int Row, int MCUIdx)
213 __attribute__((always_inline)) {
214 MCUTy MCU;
215 for (int MCURow = 0; MCURow < Y_S_F; ++MCURow) {
216 for (int MCUCol = 0; MCUCol < X_S_F; ++MCUCol) {
217 YCbCr::LoadY(&MCU[MCURow][MCUCol],
218 input_[Row].getCrop((InputComponentsPerMCU * MCUIdx) +
219 (X_S_F * MCURow) + MCUCol,
220 1));
221 }
222 }
224 &MCU[0][0],
225 input_[Row].getCrop((InputComponentsPerMCU * MCUIdx) + YsPerMCU, 2));
226 return MCU;
227 };
228 auto StoreMCU = [ this, out ](const MCUTy& MCU, int MCUIdx, int Row)
229 __attribute__((always_inline)) {
230 for (int MCURow = 0; MCURow < Y_S_F; ++MCURow) {
231 for (int MCUCol = 0; MCUCol < X_S_F; ++MCUCol) {
232 YUV_TO_RGB<version>(MCU[MCURow][MCUCol],
233 out[(2 * Row) + MCURow].getCrop(
234 ((OutputComponentsPerMCU * MCUIdx) / Y_S_F) +
235 (ComponentsPerPixel * MCUCol),
236 3));
237 }
238 }
239 };
240
241 invariant(row + 1 <= input.height());
242
243 // The packed input format is:
244 // p0 p1 p2 p3 p0 p0 p4 p5 p6 p7 p4 p4
245 // row 0: [ Y1 Y2 Y3 Y4 Cb Cr ] [ Y1 Y2 Y3 Y4 Cb Cr ] ...
246 // row 1: [ Y1 Y2 Y3 Y4 Cb Cr ] [ Y1 Y2 Y3 Y4 Cb Cr ] ...
247 // .. .. .. .. . . .. .. .. .. . .
248 // in unpacked form that is:
249 // p0 p1 p2 p3
250 // row 0: [ Y1 Cb Cr ] [ Y2 ... ... ] [ Y1 Cb Cr ] [ Y2 ... ... ] ...
251 // row 1: [ Y3 ... ... ] [ Y4 ... ... ] [ Y3 ... ... ] [ Y4 ... ... ] ...
252 // row 2: [ Y1 Cb Cr ] [ Y2 ... ... ] [ Y1 Cb Cr ] [ Y2 ... ... ] ...
253 // row 3: [ Y3 ... ... ] [ Y4 ... ... ] [ Y3 ... ... ] [ Y4 ... ... ] ...
254 // .. . . .. . . .. . . .. . .
255 // i.e. on even rows, even pixels are full, rest of pixels need interpolation
256 // first, on even rows, odd pixels are interpolated using 422 algo (marked *)
257 // p0 p1 p2 p3
258 // row 0: [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] ...
259 // row 1: [ Y3 ... ... ] [ Y4 ... ... ] [ Y3 ... ... ] [ Y4 ... ... ] ...
260 // row 2: [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] ...
261 // row 3: [ Y3 ... ... ] [ Y4 ... ... ] [ Y3 ... ... ] [ Y4 ... ... ] ...
262 // .. . . .. . . .. . .
263 // then, on odd rows, even pixels are interpolated (marked with #)
264 // p0 p1 p2 p3
265 // row 0: [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] ...
266 // row 1: [ Y3 Cb# Cr# ] [ Y4 ... ... ] [ Y3 Cb# Cr# ] [ Y4 ... ... ] ...
267 // row 2: [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] ...
268 // row 3: [ Y3 Cb# Cr# ] [ Y4 ... ... ] [ Y3 Cb# Cr# ] [ Y4 ... ... ] ...
269 // .. . . .. . . .. . .
270 // and finally, on odd rows, odd pixels are interpolated from * (marked $)
271 // p0 p1 p2 p3
272 // row 0: [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] ...
273 // row 1: [ Y3 Cb# Cr# ] [ Y4 Cb$ Cr$ ] [ Y3 Cb# Cr# ] [ Y4 Cb$ Cr$ ] ...
274 // row 2: [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] ...
275 // row 3: [ Y3 Cb# Cr# ] [ Y4 Cb$ Cr$ ] [ Y3 Cb# Cr# ] [ Y4 Cb$ Cr$ ] ...
276 // .. . . .. . . .. . .
277 // see http://lclevy.free.fr/cr2/#sraw
278
279 int MCUIdx;
280 for (MCUIdx = 0; MCUIdx < numMCUs - 1; ++MCUIdx) {
281 invariant(MCUIdx + 1 <= numMCUs);
282
283 // For 4:2:0, one MCU encodes 4 pixels (2x2), and odd pixels need
284 // interpolation, so we need to load eight pixels,
285 // and thus we must load 4 MCU's.
286 std::array<std::array<MCUTy, 2>, 2> MCUs;
287 for (int Row = 0; Row < 2; ++Row)
288 for (int Col = 0; Col < 2; ++Col)
289 MCUs[Row][Col] = LoadMCU(row + Row, MCUIdx + Col);
290
291 // Process first pixels of MCU's, which are full
292 for (int Row = 0; Row < 2; ++Row)
293 for (int Col = 0; Col < 2; ++Col)
294 MCUs[Row][Col][0][0].process(hue);
295
296 // Interpolate the middle pixel of first row.
297 MCUs[0][0][0][1].interpolateCbCr(MCUs[0][0][0][0], MCUs[0][1][0][0]);
298
299 // Interpolate the first pixel of second row.
300 MCUs[0][0][1][0].interpolateCbCr(MCUs[0][0][0][0], MCUs[1][0][0][0]);
301
302 // Interpolate the second pixel of second row.
303 MCUs[0][0][1][1].interpolateCbCr(MCUs[0][0][0][0], MCUs[0][1][0][0],
304 MCUs[1][0][0][0], MCUs[1][1][0][0]);
305
306 // FIXME: we should instead simply interpolate odd pixels on even rows
307 // and then even pixels on odd rows, as specified in the standard.
308 // for (int Row = 0; Row < 2; ++Row)
309 // MCUs[Row][0][0][1].interpolateCbCr(MCUs[Row][0][0][0],
310 // MCUs[Row][1][0][0]);
311 // for (int Col = 0; Col < 2; ++Col)
312 // MCUs[0][0][1][Col].interpolateCbCr(MCUs[0][0][0][Col],
313 // MCUs[1][0][0][Col]);
314
315 // And finally, store the first MCU, i.e. first two pixels on two rows.
316 StoreMCU(MCUs[0][0], MCUIdx, row);
317 }
318
319 invariant(MCUIdx + 1 == numMCUs);
320
321 // Last two pixels of the lines, the packed input format is:
322 // p0 p1 p2 p3 p0 p0
323 // row 0: ... [ Y1 Y2 Y3 Y4 Cb Cr ]
324 // row 1: ... [ Y1 Y2 Y3 Y4 Cb Cr ]
325 // .. .. .. .. . .
326 // in unpacked form that is:
327 // p0 p1
328 // row 0: ... [ Y1 Cb Cr ] [ Y2 ... ... ]
329 // row 1: ... [ Y3 ... ... ] [ Y4 ... ... ]
330 // row 2: ... [ Y1 Cb Cr ] [ Y2 ... ... ]
331 // row 3: ... [ Y3 ... ... ] [ Y4 ... ... ]
332 // .. . . .. . .
333
334 std::array<MCUTy, 2> MCUs;
335 for (int Row = 0; Row < 2; ++Row)
336 MCUs[Row] = LoadMCU(row + Row, MCUIdx);
337
338 for (int Row = 0; Row < 2; ++Row)
339 MCUs[Row][0][0].process(hue);
340
341 MCUs[0][1][0].interpolateCbCr(MCUs[0][0][0], MCUs[1][0][0]);
342
343 for (int Row = 0; Row < 2; ++Row)
344 YCbCr::CopyCbCr(&MCUs[0][Row][1], MCUs[0][Row][0]);
345
346 StoreMCU(MCUs[0], MCUIdx, row);
347}
348
349template <int version> void Cr2sRawInterpolator::interpolate_420() {
350 const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());
351
352 constexpr int X_S_F = 2;
353 constexpr int Y_S_F = 2;
354 constexpr int PixelsPerMCU = X_S_F * Y_S_F;
355 constexpr int InputComponentsPerMCU = 2 + PixelsPerMCU;
356
357 constexpr int YsPerMCU = PixelsPerMCU;
358 constexpr int ComponentsPerPixel = 3;
359 constexpr int OutputComponentsPerMCU = ComponentsPerPixel * PixelsPerMCU;
360
361 invariant(input.width() % InputComponentsPerMCU == 0);
362 int numMCUs = input.width() / InputComponentsPerMCU;
363 invariant(numMCUs > 1);
364
365 using MCUTy = std::array<std::array<YCbCr, X_S_F>, Y_S_F>;
366
367 auto LoadMCU = [input_ = input](int Row, int MCUIdx)
368 __attribute__((always_inline)) {
369 MCUTy MCU;
370 for (int MCURow = 0; MCURow < Y_S_F; ++MCURow) {
371 for (int MCUCol = 0; MCUCol < X_S_F; ++MCUCol) {
372 YCbCr::LoadY(&MCU[MCURow][MCUCol],
373 input_[Row].getCrop((InputComponentsPerMCU * MCUIdx) +
374 (X_S_F * MCURow) + MCUCol,
375 1));
376 }
377 }
379 &MCU[0][0],
380 input_[Row].getCrop((InputComponentsPerMCU * MCUIdx) + YsPerMCU, 2));
381 return MCU;
382 };
383 auto StoreMCU = [ this, out ](const MCUTy& MCU, int MCUIdx, int Row)
384 __attribute__((always_inline)) {
385 for (int MCURow = 0; MCURow < Y_S_F; ++MCURow) {
386 for (int MCUCol = 0; MCUCol < X_S_F; ++MCUCol) {
387 YUV_TO_RGB<version>(MCU[MCURow][MCUCol],
388 out[(2 * Row) + MCURow].getCrop(
389 ((OutputComponentsPerMCU * MCUIdx) / Y_S_F) +
390 (ComponentsPerPixel * MCUCol),
391 3));
392 }
393 }
394 };
395
396 int row = 0;
397#ifdef HAVE_OPENMP
398#pragma omp parallel for default(none) schedule(static) \
399 num_threads(rawspeed_get_number_of_processor_cores()) firstprivate(out) \
400 lastprivate(row)
401#endif
402 for (row = 0; row < input.height() - 1; ++row)
404
405 invariant(row + 1 == input.height());
406
407 // Last two lines, the packed input format is:
408 // p0 p1 p2 p3 p0 p0 p4 p5 p6 p7 p4 p4
409 // .. .. .. .. . . .. .. .. .. . .
410 // row 0: [ Y1 Y2 Y3 Y4 Cb Cr ] [ Y1 Y2 Y3 Y4 Cb Cr ] ...
411 // in unpacked form that is:
412 // p0 p1 p2 p3
413 // .. . . .. . . .. . . .. . .
414 // row 0: [ Y1 Cb Cr ] [ Y2 ... ... ] [ Y1 Cb Cr ] [ Y2 ... ... ] ...
415 // row 1: [ Y3 ... ... ] [ Y4 ... ... ] [ Y3 ... ... ] [ Y4 ... ... ] ...
416
417 int MCUIdx;
418 for (MCUIdx = 0; MCUIdx < numMCUs - 1; ++MCUIdx) {
419 invariant(MCUIdx + 1 < numMCUs);
420
421 // For 4:2:0, one MCU encodes 4 pixels (2x2), and odd pixels need
422 // interpolation, so we need to load eight pixels,
423 // and thus we must load 4 MCU's.
424 std::array<std::array<MCUTy, 2>, 1> MCUs;
425 for (int Row = 0; Row < 1; ++Row)
426 for (int Col = 0; Col < 2; ++Col)
427 MCUs[Row][Col] = LoadMCU(row + Row, MCUIdx + Col);
428
429 // Process first pixels of MCU's, which are full
430 for (int Row = 0; Row < 1; ++Row)
431 for (int Col = 0; Col < 2; ++Col)
432 MCUs[Row][Col][0][0].process(hue);
433
434 // Interpolate the middle pixel of first row.
435 MCUs[0][0][0][1].interpolateCbCr(MCUs[0][0][0][0], MCUs[0][1][0][0]);
436
437 // Copy Cb/Cr to the first two pixels of second row from the two pixels
438 // of first row.
439 for (int Col = 0; Col < 2; ++Col)
440 YCbCr::CopyCbCr(&MCUs[0][0][1][Col], MCUs[0][0][0][Col]);
441
442 // And finally, store the first MCU, i.e. first two pixels on two rows.
443 StoreMCU(MCUs[0][0], MCUIdx, row);
444 }
445
446 invariant(MCUIdx + 1 == numMCUs);
447
448 // Last two pixels of last two lines, the packed input format is:
449 // p0 p1 p2 p3 p0 p0
450 // .. .. .. .. . .
451 // row 0: ... [ Y1 Y2 Y3 Y4 Cb Cr ]
452 // in unpacked form that is:
453 // p0 p1
454 // .. . . .. . .
455 // row 0: ... [ Y1 Cb Cr ] [ Y2 ... ... ]
456 // row 1: ... [ Y3 ... ... ] [ Y4 ... ... ]
457
458 MCUTy MCU = LoadMCU(row, MCUIdx);
459
460 MCU[0][0].process(hue);
461
462 // Distribute the same Cb/Cr to all four pixels.
463 for (int Row = 0; Row < 2; ++Row)
464 for (int Col = 0; Col < 2; ++Col)
465 YCbCr::CopyCbCr(&MCU[Row][Col], MCU[0][0]);
466
467 StoreMCU(MCU, MCUIdx, row);
468}
469
471 int r, int g, int b) {
472 invariant(out.size() == 3);
473 out(0) = clampBits(r >> 8, 16);
474 out(1) = clampBits(g >> 8, 16);
475 out(2) = clampBits(b >> 8, 16);
476}
477
478template </* int version */>
479/* Algorithm found in EOS 40D */
480inline void
483 int r = sraw_coeffs[0] * (p.Y + p.Cr - 512);
484 int g = sraw_coeffs[1] * (p.Y + ((-778 * p.Cb - (p.Cr * 2048)) >> 12) - 512);
485 int b = sraw_coeffs[2] * (p.Y + (p.Cb - 512));
486 STORE_RGB(out, r, g, b);
487}
488
489template </* int version */>
490inline void
493 int r = sraw_coeffs[0] * (p.Y + ((50 * p.Cb + 22929 * p.Cr) >> 12));
494 int g = sraw_coeffs[1] * (p.Y + ((-5640 * p.Cb - 11751 * p.Cr) >> 12));
495 int b = sraw_coeffs[2] * (p.Y + ((29040 * p.Cb - 101 * p.Cr) >> 12));
496 STORE_RGB(out, r, g, b);
497}
498
499template </* int version */>
500/* Algorithm found in EOS 5d Mk III */
501inline void
504 int r = sraw_coeffs[0] * (p.Y + p.Cr);
505 int g = sraw_coeffs[1] * (p.Y + ((-778 * p.Cb - (p.Cr * 2048)) >> 12));
506 int b = sraw_coeffs[2] * (p.Y + p.Cb);
507 STORE_RGB(out, r, g, b);
508}
509
510// Interpolate and convert sRaw data.
512 invariant(version >= 0 && version <= 2);
513
514 const auto& subSampling = mRaw->metadata.subsampling;
515 if (subSampling.y == 1 && subSampling.x == 2) {
516 switch (version) {
517 case 0:
519 break;
520 case 1:
522 break;
523 case 2:
525 break;
526 default:
527 __builtin_unreachable();
528 }
529 } else if (subSampling.y == 2 && subSampling.x == 2) {
530 switch (version) {
531 // no known sraws with "version 0"
532 case 1:
534 break;
535 case 2:
537 break;
538 default:
539 __builtin_unreachable();
540 }
541 } else {
542 ThrowRDE("Unknown subsampling: (%i; %i)", subSampling.x, subSampling.y);
543 }
544}
545
546} // namespace rawspeed
#define invariant(expr)
Definition Invariant.h:27
#define ThrowRDE(...)
int RAWSPEED_READONLY height() const
int RAWSPEED_READONLY width() const
static void STORE_RGB(CroppedArray1DRef< uint16_t > out, int r, int g, int b)
const Array2DRef< const uint16_t > input
void YUV_TO_RGB(const YCbCr &p, CroppedArray1DRef< uint16_t > out)
int RAWSPEED_READONLY size() const
__attribute__((noinline)) __attribute__((visibility("default"))) JPEGStuffedByteStreamGenerator
constexpr auto RAWSPEED_READNONE clampBits(T value, unsigned int nBits)
Definition Bit.h:75
static void LoadY(YCbCr *p, const CroppedArray1DRef< const uint16_t > in)
static void CopyCbCr(YCbCr *p, const YCbCr &pSrc)
static void LoadCbCr(YCbCr *p, const CroppedArray1DRef< const uint16_t > in)
void interpolateCbCr(const YCbCr &p0, const YCbCr &p2)
void interpolateCbCr(const YCbCr &p0, const YCbCr &p1, const YCbCr &p2, const YCbCr &p3)