/src/opencv/3rdparty/openexr/IlmImf/ImfDwaCompressor.cpp
Line | Count | Source |
1 | | /////////////////////////////////////////////////////////////////////////// |
2 | | // |
3 | | // Copyright (c) 2009-2014 DreamWorks Animation LLC. |
4 | | // |
5 | | // All rights reserved. |
6 | | // |
7 | | // Redistribution and use in source and binary forms, with or without |
8 | | // modification, are permitted provided that the following conditions are |
9 | | // met: |
10 | | // * Redistributions of source code must retain the above copyright |
11 | | // notice, this list of conditions and the following disclaimer. |
12 | | // * Redistributions in binary form must reproduce the above |
13 | | // copyright notice, this list of conditions and the following disclaimer |
14 | | // in the documentation and/or other materials provided with the |
15 | | // distribution. |
16 | | // * Neither the name of DreamWorks Animation nor the names of |
17 | | // its contributors may be used to endorse or promote products derived |
18 | | // from this software without specific prior written permission. |
19 | | // |
20 | | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
21 | | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
22 | | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
23 | | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
24 | | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
25 | | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
26 | | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
27 | | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
28 | | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
29 | | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
30 | | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31 | | // |
32 | | /////////////////////////////////////////////////////////////////////////// |
33 | | |
34 | | //--------------------------------------------------- |
35 | | // |
36 | | // class DwaCompressor -- Store lossy RGB data by quantizing |
37 | | // DCT components. |
38 | | // |
39 | | // First, we try and figure out what compression strategy to take |
40 | | // based in channel name. For RGB channels, we want a lossy method |
41 | | // described below. But, if we have alpha, we should do something |
42 | | // different (and probably using RLE). If we have depth, or velocity, |
43 | | // or something else, just fall back to ZIP. The rules for deciding |
44 | | // which strategy to use are setup in initializeDefaultChannelRules(). |
45 | | // When writing a file, the relevant rules needed to decode are written |
46 | | // into the start of the data block, making a self-contained file. |
47 | | // If initializeDefaultChannelRules() doesn't quite suite your naming |
48 | | // conventions, you can adjust the rules without breaking decoder |
49 | | // compatability. |
50 | | // |
51 | | // If we're going to lossy compress R, G, or B channels, it's easier |
52 | | // to toss bits in a more perceptual uniform space. One could argue |
53 | | // at length as to what constitutes perceptually uniform, expecially |
54 | | // when storing either scene/input/focal plane referred and output referred |
55 | | // data. |
56 | | // |
57 | | // We'll compromise. For values <= 1, we use a traditional power function |
58 | | // (without any of that straight-line business at the bottom). For values > 1, |
59 | | // we want something more like a log function, since power functions blow |
60 | | // up. At 1, we want a smooth blend between the functions. So, we use a |
61 | | // piecewise function that does just that - see dwaLookups.cpp for |
62 | | // a little more detail. |
63 | | // |
64 | | // Also, if we find that we have R, G, and B channels from the same layer, |
65 | | // we can get a bit more compression efficiency by transforming to a Y'CbCr |
66 | | // space. We use the 709 transform, but with Cb,Cr = 0 for an input of |
67 | | // (0, 0, 0), instead of the traditional Cb,Cr = .5. Shifting the zero point |
68 | | // makes no sense with large range data. Transforms are done to from |
69 | | // the perceptual space data, not the linear-light space data (R'G'B' -> |
70 | | // (Y'CbCr, not RGB -> YCbCr). |
71 | | // |
72 | | // Next, we forward DCT the data. This is done with a floating |
73 | | // point DCT, as we don't really have control over the src range. The |
74 | | // resulting values are dropped to half-float precision. |
75 | | // |
76 | | // Now, we need to quantize. Quantization departs from the usual way |
77 | | // of dividing and rounding. Instead, we start with some floating |
78 | | // point "base-error" value. From this, we can derive quantization |
79 | | // error for each DCT component. Take the standard JPEG quantization |
80 | | // tables and normalize them by the smallest value. Then, multiply |
81 | | // the normalized quant tables by our base-error value. This gives |
82 | | // a range of errors for each DCT component. |
83 | | // |
84 | | // For each DCT component, we want to find a quantized value that |
85 | | // is within +- the per-component error. Pick the quantized value |
86 | | // that has the fewest bits set in its' binary representation. |
87 | | // Brute-forcing the search would make for extremly inefficient |
88 | | // compression. Fortunatly, we can precompute a table to assist |
89 | | // with this search. |
90 | | // |
91 | | // For each 16-bit float value, there are at most 15 other values with |
92 | | // fewer bits set. We can precompute these values in a compact form, since |
93 | | // many source values have far fewer that 15 possible quantized values. |
94 | | // Now, instead of searching the entire range +- the component error, |
95 | | // we can just search at most 15 quantization candidates. The search can |
96 | | // be accelerated a bit more by sorting the candidates by the |
97 | | // number of bits set, in increasing order. Then, the search can stop |
98 | | // once a candidate is found w/i the per-component quantization |
99 | | // error range. |
100 | | // |
101 | | // The quantization strategy has the side-benefit that there is no |
102 | | // de-quantization step upon decode, so we don't bother recording |
103 | | // the quantization table. |
104 | | // |
105 | | // Ok. So we now have quantized values. Time for entropy coding. We |
106 | | // can use either static Huffman or zlib/DEFLATE. The static Huffman |
107 | | // is more efficient at compacting data, but can have a greater |
108 | | // overhead, especially for smaller tile/strip sizes. |
109 | | // |
110 | | // There is some additional fun, like ZIP compressing the DC components |
111 | | // instead of Huffman/zlib, which helps make things slightly smaller. |
112 | | // |
113 | | // Compression level is controlled by setting an int/float/double attribute |
114 | | // on the header named "dwaCompressionLevel". This is a thinly veiled name for |
115 | | // the "base-error" value mentioned above. The "base-error" is just |
116 | | // dwaCompressionLevel / 100000. The default value of 45.0 is generally |
117 | | // pretty good at generating "visually lossless" values at reasonable |
118 | | // data rates. Setting dwaCompressionLevel to 0 should result in no additional |
119 | | // quantization at the quantization stage (though there may be |
120 | | // quantization in practice at the CSC/DCT steps). But if you really |
121 | | // want lossless compression, there are pleanty of other choices |
122 | | // of compressors ;) |
123 | | // |
124 | | // When dealing with FLOAT source buffers, we first quantize the source |
125 | | // to HALF and continue down as we would for HALF source. |
126 | | // |
127 | | //--------------------------------------------------- |
128 | | |
129 | | |
130 | | #include "ImfDwaCompressor.h" |
131 | | #include "ImfDwaCompressorSimd.h" |
132 | | |
133 | | #include "ImfChannelList.h" |
134 | | #include "ImfStandardAttributes.h" |
135 | | #include "ImfHeader.h" |
136 | | #include "ImfHuf.h" |
137 | | #include "ImfInt64.h" |
138 | | #include "ImfIntAttribute.h" |
139 | | #include "ImfIO.h" |
140 | | #include "ImfMisc.h" |
141 | | #include "ImfNamespace.h" |
142 | | #include "ImfRle.h" |
143 | | #include "ImfSimd.h" |
144 | | #include "ImfSystemSpecific.h" |
145 | | #include "ImfXdr.h" |
146 | | #include "ImfZip.h" |
147 | | |
148 | | #include "ImathFun.h" |
149 | | #include "ImathBox.h" |
150 | | #include "ImathVec.h" |
151 | | #include "half.h" |
152 | | #include "halfLimits.h" |
153 | | |
154 | | #include "dwaLookups.h" |
155 | | |
156 | | #include <vector> |
157 | | #include <string> |
158 | | #include <cctype> |
159 | | #include <cassert> |
160 | | #include <algorithm> |
161 | | |
162 | | // Windows specific addition to prevent the indirect import of the redefined min/max macros |
163 | | #if defined _WIN32 || defined _WIN64 |
164 | | #ifdef NOMINMAX |
165 | | #undef NOMINMAX |
166 | | #endif |
167 | | #define NOMINMAX |
168 | | #endif |
169 | | #include <zlib.h> |
170 | | |
171 | | |
172 | | OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER |
173 | | |
174 | | |
175 | | namespace { |
176 | | |
177 | | // |
178 | | // Function pointer to dispatch to an approprate |
179 | | // convertFloatToHalf64_* impl, based on runtime cpu checking. |
180 | | // Should be initialized in DwaCompressor::initializeFuncs() |
181 | | // |
182 | | |
183 | | void (*convertFloatToHalf64)(unsigned short*, float*) = |
184 | | convertFloatToHalf64_scalar; |
185 | | |
186 | | // |
187 | | // Function pointer for dispatching a fromHalfZigZag_ impl |
188 | | // |
189 | | |
190 | | void (*fromHalfZigZag)(unsigned short*, float*) = |
191 | | fromHalfZigZag_scalar; |
192 | | |
193 | | // |
194 | | // Dispatch the inverse DCT on an 8x8 block, where the last |
195 | | // n rows can be all zeros. The n=0 case converts the full block. |
196 | | // |
197 | | void (*dctInverse8x8_0)(float*) = dctInverse8x8_scalar<0>; |
198 | | void (*dctInverse8x8_1)(float*) = dctInverse8x8_scalar<1>; |
199 | | void (*dctInverse8x8_2)(float*) = dctInverse8x8_scalar<2>; |
200 | | void (*dctInverse8x8_3)(float*) = dctInverse8x8_scalar<3>; |
201 | | void (*dctInverse8x8_4)(float*) = dctInverse8x8_scalar<4>; |
202 | | void (*dctInverse8x8_5)(float*) = dctInverse8x8_scalar<5>; |
203 | | void (*dctInverse8x8_6)(float*) = dctInverse8x8_scalar<6>; |
204 | | void (*dctInverse8x8_7)(float*) = dctInverse8x8_scalar<7>; |
205 | | |
206 | | } // namespace |
207 | | |
208 | | |
209 | | struct DwaCompressor::ChannelData |
210 | | { |
211 | | std::string name; |
212 | | CompressorScheme compression; |
213 | | int xSampling; |
214 | | int ySampling; |
215 | | PixelType type; |
216 | | bool pLinear; |
217 | | |
218 | | int width; |
219 | | int height; |
220 | | |
221 | | // |
222 | | // Incoming and outgoing data is scanline interleaved, and it's much |
223 | | // easier to operate on contiguous data. Assuming the planare unc |
224 | | // buffer is to hold RLE data, we need to rearrange to make bytes |
225 | | // adjacent. |
226 | | // |
227 | | |
228 | | char *planarUncBuffer; |
229 | | char *planarUncBufferEnd; |
230 | | |
231 | | char *planarUncRle[4]; |
232 | | char *planarUncRleEnd[4]; |
233 | | |
234 | | PixelType planarUncType; |
235 | | int planarUncSize; |
236 | | }; |
237 | | |
238 | | |
239 | | struct DwaCompressor::CscChannelSet |
240 | | { |
241 | | int idx[3]; |
242 | | }; |
243 | | |
244 | | |
245 | | struct DwaCompressor::Classifier |
246 | | { |
247 | | Classifier (std::string suffix, |
248 | | CompressorScheme scheme, |
249 | | PixelType type, |
250 | | int cscIdx, |
251 | | bool caseInsensitive): |
252 | 0 | _suffix(suffix), |
253 | 0 | _scheme(scheme), |
254 | 0 | _type(type), |
255 | 0 | _cscIdx(cscIdx), |
256 | 0 | _caseInsensitive(caseInsensitive) |
257 | 0 | { |
258 | 0 | if (caseInsensitive) |
259 | 0 | std::transform(_suffix.begin(), _suffix.end(), _suffix.begin(), tolower); |
260 | 0 | } |
261 | | |
262 | | Classifier (const char *&ptr, int size) |
263 | 0 | { |
264 | 0 | if (size <= 0) |
265 | 0 | throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data" |
266 | 0 | " (truncated rule)."); |
267 | | |
268 | 0 | { |
269 | 0 | char suffix[Name::SIZE]; |
270 | 0 | memset (suffix, 0, Name::SIZE); |
271 | 0 | Xdr::read<CharPtrIO> (ptr, std::min(size, Name::SIZE-1), suffix); |
272 | 0 | _suffix = std::string(suffix); |
273 | 0 | } |
274 | |
|
275 | 0 | if (size < _suffix.length() + 1 + 2*Xdr::size<char>()) |
276 | 0 | throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data" |
277 | 0 | " (truncated rule)."); |
278 | | |
279 | 0 | char value; |
280 | 0 | Xdr::read<CharPtrIO> (ptr, value); |
281 | |
|
282 | 0 | _cscIdx = (int)(value >> 4) - 1; |
283 | 0 | if (_cscIdx < -1 || _cscIdx >= 3) |
284 | 0 | throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data" |
285 | 0 | " (corrupt cscIdx rule)."); |
286 | | |
287 | 0 | _scheme = (CompressorScheme)((value >> 2) & 3); |
288 | 0 | if (_scheme < 0 || _scheme >= NUM_COMPRESSOR_SCHEMES) |
289 | 0 | throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data" |
290 | 0 | " (corrupt scheme rule)."); |
291 | | |
292 | 0 | _caseInsensitive = (value & 1 ? true : false); |
293 | |
|
294 | 0 | Xdr::read<CharPtrIO> (ptr, value); |
295 | 0 | if (value < 0 || value >= NUM_PIXELTYPES) |
296 | 0 | throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data" |
297 | 0 | " (corrupt rule)."); |
298 | 0 | _type = (PixelType)value; |
299 | 0 | } |
300 | | |
301 | | bool match (const std::string &suffix, const PixelType type) const |
302 | 0 | { |
303 | 0 | if (_type != type) return false; |
304 | | |
305 | 0 | if (_caseInsensitive) |
306 | 0 | { |
307 | 0 | std::string tmp(suffix); |
308 | 0 | std::transform(tmp.begin(), tmp.end(), tmp.begin(), tolower); |
309 | 0 | return tmp == _suffix; |
310 | 0 | } |
311 | | |
312 | 0 | return suffix == _suffix; |
313 | 0 | } |
314 | | |
315 | | size_t size () const |
316 | 0 | { |
317 | | // string length + \0 |
318 | 0 | size_t sizeBytes = _suffix.length() + 1; |
319 | | |
320 | | // 1 byte for scheme / cscIdx / caseInsensitive, and 1 byte for type |
321 | 0 | sizeBytes += 2 * Xdr::size<char>(); |
322 | |
|
323 | 0 | return sizeBytes; |
324 | 0 | } |
325 | | |
326 | | void write (char *&ptr) const |
327 | 0 | { |
328 | 0 | Xdr::write<CharPtrIO> (ptr, _suffix.c_str()); |
329 | | |
330 | | // Encode _cscIdx (-1-3) in the upper 4 bits, |
331 | | // _scheme (0-2) in the next 2 bits |
332 | | // _caseInsen in the bottom bit |
333 | 0 | unsigned char value = 0; |
334 | 0 | value |= ((unsigned char)(_cscIdx+1) & 15) << 4; |
335 | 0 | value |= ((unsigned char)_scheme & 3) << 2; |
336 | 0 | value |= (unsigned char)_caseInsensitive & 1; |
337 | |
|
338 | 0 | Xdr::write<CharPtrIO> (ptr, value); |
339 | 0 | Xdr::write<CharPtrIO> (ptr, (unsigned char)_type); |
340 | 0 | } |
341 | | |
342 | | std::string _suffix; |
343 | | CompressorScheme _scheme; |
344 | | PixelType _type; |
345 | | int _cscIdx; |
346 | | bool _caseInsensitive; |
347 | | }; |
348 | | |
349 | | |
350 | | // |
351 | | // Base class for the LOSSY_DCT decoder classes |
352 | | // |
353 | | |
354 | | class DwaCompressor::LossyDctDecoderBase |
355 | | { |
356 | | public: |
357 | | |
358 | | LossyDctDecoderBase |
359 | | (char *packedAc, |
360 | | char *packedDc, |
361 | | const unsigned short *toLinear, |
362 | | int width, |
363 | | int height); |
364 | | |
365 | | virtual ~LossyDctDecoderBase (); |
366 | | |
367 | | void execute(); |
368 | | |
369 | | // |
370 | | // These return number of items, not bytes. Each item |
371 | | // is an unsigned short |
372 | | // |
373 | | |
374 | 0 | int numAcValuesEncoded() const { return _packedAcCount; } |
375 | 0 | int numDcValuesEncoded() const { return _packedDcCount; } |
376 | | |
377 | | protected: |
378 | | |
379 | | // |
380 | | // Un-RLE the packed AC components into |
381 | | // a half buffer. The half block should |
382 | | // be the full 8x8 block (in zig-zag order |
383 | | // still), not the first AC component. |
384 | | // |
385 | | // currAcComp is advanced as bytes are decoded. |
386 | | // |
387 | | // This returns the index of the last non-zero |
388 | | // value in the buffer - with the index into zig zag |
389 | | // order data. If we return 0, we have DC only data. |
390 | | // |
391 | | |
392 | | int unRleAc (unsigned short *&currAcComp, |
393 | | unsigned short *halfZigBlock); |
394 | | |
395 | | |
396 | | // |
397 | | // if NATIVE and XDR are really the same values, we can |
398 | | // skip some processing and speed things along |
399 | | // |
400 | | |
401 | | bool _isNativeXdr; |
402 | | |
403 | | |
404 | | // |
405 | | // Counts of how many items have been packed into the |
406 | | // AC and DC buffers |
407 | | // |
408 | | |
409 | | int _packedAcCount; |
410 | | int _packedDcCount; |
411 | | |
412 | | |
413 | | // |
414 | | // AC and DC buffers to pack |
415 | | // |
416 | | |
417 | | char *_packedAc; |
418 | | char *_packedDc; |
419 | | |
420 | | |
421 | | // |
422 | | // half -> half LUT to transform from nonlinear to linear |
423 | | // |
424 | | |
425 | | const unsigned short *_toLinear; |
426 | | |
427 | | |
428 | | // |
429 | | // image dimensions |
430 | | // |
431 | | |
432 | | int _width; |
433 | | int _height; |
434 | | |
435 | | |
436 | | // |
437 | | // Pointers to the start of each scanlines, to be filled on decode |
438 | | // Generally, these will be filled by the subclasses. |
439 | | // |
440 | | |
441 | | std::vector< std::vector<char *> > _rowPtrs; |
442 | | |
443 | | |
444 | | // |
445 | | // The type of each data that _rowPtrs[i] is referring. Layout |
446 | | // is in the same order as _rowPtrs[]. |
447 | | // |
448 | | |
449 | | std::vector<PixelType> _type; |
450 | | std::vector<SimdAlignedBuffer64f> _dctData; |
451 | | }; |
452 | | |
453 | | |
454 | | // |
455 | | // Used to decode a single channel of LOSSY_DCT data. |
456 | | // |
457 | | |
458 | | class DwaCompressor::LossyDctDecoder: public LossyDctDecoderBase |
459 | | { |
460 | | public: |
461 | | |
462 | | // |
463 | | // toLinear is a half-float LUT to convert the encoded values |
464 | | // back to linear light. If you want to skip this step, pass |
465 | | // in NULL here. |
466 | | // |
467 | | |
468 | | LossyDctDecoder |
469 | | (std::vector<char *> &rowPtrs, |
470 | | char *packedAc, |
471 | | char *packedDc, |
472 | | const unsigned short *toLinear, |
473 | | int width, |
474 | | int height, |
475 | | PixelType type) |
476 | | : |
477 | 0 | LossyDctDecoderBase(packedAc, packedDc, toLinear, width, height) |
478 | 0 | { |
479 | 0 | _rowPtrs.push_back(rowPtrs); |
480 | 0 | _type.push_back(type); |
481 | 0 | } |
482 | | |
483 | 0 | virtual ~LossyDctDecoder () {} |
484 | | }; |
485 | | |
486 | | |
487 | | // |
488 | | // Used to decode 3 channels of LOSSY_DCT data that |
489 | | // are grouped together and color space converted. |
490 | | // |
491 | | |
492 | | class DwaCompressor::LossyDctDecoderCsc: public LossyDctDecoderBase |
493 | | { |
494 | | public: |
495 | | |
496 | | // |
497 | | // toLinear is a half-float LUT to convert the encoded values |
498 | | // back to linear light. If you want to skip this step, pass |
499 | | // in NULL here. |
500 | | // |
501 | | |
502 | | LossyDctDecoderCsc |
503 | | (std::vector<char *> &rowPtrsR, |
504 | | std::vector<char *> &rowPtrsG, |
505 | | std::vector<char *> &rowPtrsB, |
506 | | char *packedAc, |
507 | | char *packedDc, |
508 | | const unsigned short *toLinear, |
509 | | int width, |
510 | | int height, |
511 | | PixelType typeR, |
512 | | PixelType typeG, |
513 | | PixelType typeB) |
514 | | : |
515 | 0 | LossyDctDecoderBase(packedAc, packedDc, toLinear, width, height) |
516 | 0 | { |
517 | 0 | _rowPtrs.push_back(rowPtrsR); |
518 | 0 | _rowPtrs.push_back(rowPtrsG); |
519 | 0 | _rowPtrs.push_back(rowPtrsB); |
520 | 0 | _type.push_back(typeR); |
521 | 0 | _type.push_back(typeG); |
522 | 0 | _type.push_back(typeB); |
523 | 0 | } |
524 | | |
525 | 0 | virtual ~LossyDctDecoderCsc () {} |
526 | | }; |
527 | | |
528 | | |
529 | | // |
530 | | // Base class for encoding using the lossy DCT scheme |
531 | | // |
532 | | |
533 | | class DwaCompressor::LossyDctEncoderBase |
534 | | { |
535 | | public: |
536 | | |
537 | | LossyDctEncoderBase |
538 | | (float quantBaseError, |
539 | | char *packedAc, |
540 | | char *packedDc, |
541 | | const unsigned short *toNonlinear, |
542 | | int width, |
543 | | int height); |
544 | | |
545 | | virtual ~LossyDctEncoderBase (); |
546 | | |
547 | | void execute (); |
548 | | |
549 | | // |
550 | | // These return number of items, not bytes. Each item |
551 | | // is an unsigned short |
552 | | // |
553 | | |
554 | 0 | int numAcValuesEncoded () const {return _numAcComp;} |
555 | 0 | int numDcValuesEncoded () const {return _numDcComp;} |
556 | | |
557 | | protected: |
558 | | |
559 | | void toZigZag (half *dst, half *src); |
560 | | int countSetBits (unsigned short src); |
561 | | half quantize (half src, float errorTolerance); |
562 | | void rleAc (half *block, unsigned short *&acPtr); |
563 | | |
564 | | float _quantBaseError; |
565 | | |
566 | | int _width, |
567 | | _height; |
568 | | const unsigned short *_toNonlinear; |
569 | | |
570 | | int _numAcComp, |
571 | | _numDcComp; |
572 | | |
573 | | std::vector< std::vector<const char *> > _rowPtrs; |
574 | | std::vector<PixelType> _type; |
575 | | std::vector<SimdAlignedBuffer64f> _dctData; |
576 | | |
577 | | |
578 | | // |
579 | | // Pointers to the buffers where AC and DC |
580 | | // DCT components should be packed for |
581 | | // lossless compression downstream |
582 | | // |
583 | | |
584 | | char *_packedAc; |
585 | | char *_packedDc; |
586 | | |
587 | | |
588 | | // |
589 | | // Our "quantization tables" - the example JPEG tables, |
590 | | // normalized so that the smallest value in each is 1.0. |
591 | | // This gives us a relationship between error in DCT |
592 | | // components |
593 | | // |
594 | | |
595 | | float _quantTableY[64]; |
596 | | float _quantTableCbCr[64]; |
597 | | }; |
598 | | |
599 | | |
600 | | |
601 | | // |
602 | | // Single channel lossy DCT encoder |
603 | | // |
604 | | |
605 | | class DwaCompressor::LossyDctEncoder: public LossyDctEncoderBase |
606 | | { |
607 | | public: |
608 | | |
609 | | LossyDctEncoder |
610 | | (float quantBaseError, |
611 | | std::vector<const char *> &rowPtrs, |
612 | | char *packedAc, |
613 | | char *packedDc, |
614 | | const unsigned short *toNonlinear, |
615 | | int width, |
616 | | int height, |
617 | | PixelType type) |
618 | | : |
619 | 0 | LossyDctEncoderBase |
620 | 0 | (quantBaseError, packedAc, packedDc, toNonlinear, width, height) |
621 | 0 | { |
622 | 0 | _rowPtrs.push_back(rowPtrs); |
623 | 0 | _type.push_back(type); |
624 | 0 | } |
625 | | |
626 | 0 | virtual ~LossyDctEncoder () {} |
627 | | }; |
628 | | |
629 | | |
630 | | // |
631 | | // RGB channel lossy DCT encoder |
632 | | // |
633 | | |
634 | | class DwaCompressor::LossyDctEncoderCsc: public LossyDctEncoderBase |
635 | | { |
636 | | public: |
637 | | |
638 | | LossyDctEncoderCsc |
639 | | (float quantBaseError, |
640 | | std::vector<const char *> &rowPtrsR, |
641 | | std::vector<const char *> &rowPtrsG, |
642 | | std::vector<const char *> &rowPtrsB, |
643 | | char *packedAc, |
644 | | char *packedDc, |
645 | | const unsigned short *toNonlinear, |
646 | | int width, |
647 | | int height, |
648 | | PixelType typeR, |
649 | | PixelType typeG, |
650 | | PixelType typeB) |
651 | | : |
652 | 0 | LossyDctEncoderBase |
653 | 0 | (quantBaseError, packedAc, packedDc, toNonlinear, width, height) |
654 | 0 | { |
655 | 0 | _type.push_back(typeR); |
656 | 0 | _type.push_back(typeG); |
657 | 0 | _type.push_back(typeB); |
658 | |
|
659 | 0 | _rowPtrs.push_back(rowPtrsR); |
660 | 0 | _rowPtrs.push_back(rowPtrsG); |
661 | 0 | _rowPtrs.push_back(rowPtrsB); |
662 | 0 | } |
663 | | |
664 | 0 | virtual ~LossyDctEncoderCsc () {} |
665 | | }; |
666 | | |
667 | | |
668 | | // ============================================================== |
669 | | // |
670 | | // LossyDctDecoderBase |
671 | | // |
672 | | // -------------------------------------------------------------- |
673 | | |
674 | | DwaCompressor::LossyDctDecoderBase::LossyDctDecoderBase |
675 | | (char *packedAc, |
676 | | char *packedDc, |
677 | | const unsigned short *toLinear, |
678 | | int width, |
679 | | int height) |
680 | | : |
681 | 0 | _isNativeXdr(false), |
682 | 0 | _packedAcCount(0), |
683 | 0 | _packedDcCount(0), |
684 | 0 | _packedAc(packedAc), |
685 | 0 | _packedDc(packedDc), |
686 | 0 | _toLinear(toLinear), |
687 | 0 | _width(width), |
688 | 0 | _height(height) |
689 | 0 | { |
690 | 0 | if (_toLinear == 0) |
691 | 0 | _toLinear = get_dwaCompressorNoOp(); |
692 | |
|
693 | 0 | _isNativeXdr = GLOBAL_SYSTEM_LITTLE_ENDIAN; |
694 | 0 | } |
695 | | |
696 | | |
697 | 0 | DwaCompressor::LossyDctDecoderBase::~LossyDctDecoderBase () {} |
698 | | |
699 | | |
700 | | void |
701 | | DwaCompressor::LossyDctDecoderBase::execute () |
702 | 0 | { |
703 | 0 | int numComp = _rowPtrs.size(); |
704 | 0 | int lastNonZero = 0; |
705 | 0 | int numBlocksX = (int) ceil ((float)_width / 8.0f); |
706 | 0 | int numBlocksY = (int) ceil ((float)_height / 8.0f); |
707 | 0 | int leftoverX = _width - (numBlocksX-1) * 8; |
708 | 0 | int leftoverY = _height - (numBlocksY-1) * 8; |
709 | |
|
710 | 0 | int numFullBlocksX = (int)floor ((float)_width / 8.0f); |
711 | |
|
712 | 0 | unsigned short tmpShortNative = 0; |
713 | 0 | unsigned short tmpShortXdr = 0; |
714 | 0 | const char *tmpConstCharPtr = 0; |
715 | |
|
716 | 0 | unsigned short *currAcComp = (unsigned short *)_packedAc; |
717 | 0 | std::vector<unsigned short *> currDcComp (_rowPtrs.size()); |
718 | 0 | std::vector<SimdAlignedBuffer64us> halfZigBlock (_rowPtrs.size()); |
719 | |
|
720 | 0 | if (_type.size() != _rowPtrs.size()) |
721 | 0 | throw IEX_NAMESPACE::BaseExc ("Row pointers and types mismatch in count"); |
722 | | |
723 | 0 | if ((_rowPtrs.size() != 3) && (_rowPtrs.size() != 1)) |
724 | 0 | throw IEX_NAMESPACE::NoImplExc ("Only 1 and 3 channel encoding is supported"); |
725 | | |
726 | 0 | _dctData.resize(numComp); |
727 | | |
728 | | // |
729 | | // Allocate a temp aligned buffer to hold a rows worth of full |
730 | | // 8x8 half-float blocks |
731 | | // |
732 | |
|
733 | 0 | unsigned char *rowBlockHandle = new unsigned char |
734 | 0 | [numComp * numBlocksX * 64 * sizeof(unsigned short) + _SSE_ALIGNMENT]; |
735 | |
|
736 | 0 | unsigned short *rowBlock[3]; |
737 | |
|
738 | 0 | rowBlock[0] = (unsigned short*)rowBlockHandle; |
739 | |
|
740 | 0 | for (int i = 0; i < _SSE_ALIGNMENT; ++i) |
741 | 0 | { |
742 | 0 | if (((size_t)(rowBlockHandle + i) & _SSE_ALIGNMENT_MASK) == 0) |
743 | 0 | rowBlock[0] = (unsigned short *)(rowBlockHandle + i); |
744 | 0 | } |
745 | |
|
746 | 0 | for (int comp = 1; comp < numComp; ++comp) |
747 | 0 | rowBlock[comp] = rowBlock[comp - 1] + numBlocksX * 64; |
748 | | |
749 | | // |
750 | | // Pack DC components together by common plane, so we can get |
751 | | // a little more out of differencing them. We'll always have |
752 | | // one component per block, so we can computed offsets. |
753 | | // |
754 | |
|
755 | 0 | currDcComp[0] = (unsigned short *)_packedDc; |
756 | |
|
757 | 0 | for (unsigned int comp = 1; comp < numComp; ++comp) |
758 | 0 | currDcComp[comp] = currDcComp[comp - 1] + numBlocksX * numBlocksY; |
759 | |
|
760 | 0 | for (int blocky = 0; blocky < numBlocksY; ++blocky) |
761 | 0 | { |
762 | 0 | int maxY = 8; |
763 | |
|
764 | 0 | if (blocky == numBlocksY-1) |
765 | 0 | maxY = leftoverY; |
766 | |
|
767 | 0 | int maxX = 8; |
768 | |
|
769 | 0 | for (int blockx = 0; blockx < numBlocksX; ++blockx) |
770 | 0 | { |
771 | 0 | if (blockx == numBlocksX-1) |
772 | 0 | maxX = leftoverX; |
773 | | |
774 | | // |
775 | | // If we can detect that the block is constant values |
776 | | // (all components only have DC values, and all AC is 0), |
777 | | // we can do everything only on 1 value, instead of all |
778 | | // 64. |
779 | | // |
780 | | // This won't really help for regular images, but it is |
781 | | // meant more for layers with large swaths of black |
782 | | // |
783 | |
|
784 | 0 | bool blockIsConstant = true; |
785 | |
|
786 | 0 | for (unsigned int comp = 0; comp < numComp; ++comp) |
787 | 0 | { |
788 | | |
789 | | // |
790 | | // DC component is stored separately |
791 | | // |
792 | |
|
793 | 0 | #ifdef IMF_HAVE_SSE2 |
794 | 0 | { |
795 | 0 | __m128i *dst = (__m128i*)halfZigBlock[comp]._buffer; |
796 | |
|
797 | 0 | dst[7] = _mm_setzero_si128(); |
798 | 0 | dst[6] = _mm_setzero_si128(); |
799 | 0 | dst[5] = _mm_setzero_si128(); |
800 | 0 | dst[4] = _mm_setzero_si128(); |
801 | 0 | dst[3] = _mm_setzero_si128(); |
802 | 0 | dst[2] = _mm_setzero_si128(); |
803 | 0 | dst[1] = _mm_setzero_si128(); |
804 | 0 | dst[0] = _mm_insert_epi16 |
805 | 0 | (_mm_setzero_si128(), *currDcComp[comp]++, 0); |
806 | 0 | } |
807 | | #else /* IMF_HAVE_SSE2 */ |
808 | | |
809 | | memset (halfZigBlock[comp]._buffer, 0, 64 * 2); |
810 | | halfZigBlock[comp]._buffer[0] = *currDcComp[comp]++; |
811 | | |
812 | | #endif /* IMF_HAVE_SSE2 */ |
813 | |
|
814 | 0 | _packedDcCount++; |
815 | | |
816 | | // |
817 | | // UnRLE the AC. This will modify currAcComp |
818 | | // |
819 | |
|
820 | 0 | lastNonZero = unRleAc (currAcComp, halfZigBlock[comp]._buffer); |
821 | | |
822 | | // |
823 | | // Convert from XDR to NATIVE |
824 | | // |
825 | |
|
826 | 0 | if (!_isNativeXdr) |
827 | 0 | { |
828 | 0 | for (int i = 0; i < 64; ++i) |
829 | 0 | { |
830 | 0 | tmpShortXdr = halfZigBlock[comp]._buffer[i]; |
831 | 0 | tmpConstCharPtr = (const char *)&tmpShortXdr; |
832 | |
|
833 | 0 | Xdr::read<CharPtrIO> (tmpConstCharPtr, tmpShortNative); |
834 | |
|
835 | 0 | halfZigBlock[comp]._buffer[i] = tmpShortNative; |
836 | 0 | } |
837 | 0 | } |
838 | |
|
839 | 0 | if (lastNonZero == 0) |
840 | 0 | { |
841 | | // |
842 | | // DC only case - AC components are all 0 |
843 | | // |
844 | |
|
845 | 0 | half h; |
846 | |
|
847 | 0 | h.setBits (halfZigBlock[comp]._buffer[0]); |
848 | 0 | _dctData[comp]._buffer[0] = (float)h; |
849 | |
|
850 | 0 | dctInverse8x8DcOnly (_dctData[comp]._buffer); |
851 | 0 | } |
852 | 0 | else |
853 | 0 | { |
854 | | // |
855 | | // We have some AC components that are non-zero. |
856 | | // Can't use the 'constant block' optimization |
857 | | // |
858 | |
|
859 | 0 | blockIsConstant = false; |
860 | | |
861 | | // |
862 | | // Un-Zig zag |
863 | | // |
864 | |
|
865 | 0 | (*fromHalfZigZag) |
866 | 0 | (halfZigBlock[comp]._buffer, _dctData[comp]._buffer); |
867 | | |
868 | | // |
869 | | // Zig-Zag indices in normal layout are as follows: |
870 | | // |
871 | | // 0 1 5 6 14 15 27 28 |
872 | | // 2 4 7 13 16 26 29 42 |
873 | | // 3 8 12 17 25 30 41 43 |
874 | | // 9 11 18 24 31 40 44 53 |
875 | | // 10 19 23 32 39 45 52 54 |
876 | | // 20 22 33 38 46 51 55 60 |
877 | | // 21 34 37 47 50 56 59 61 |
878 | | // 35 36 48 49 57 58 62 63 |
879 | | // |
880 | | // If lastNonZero is less than the first item on |
881 | | // each row, we know that the whole row is zero and |
882 | | // can be skipped in the row-oriented part of the |
883 | | // iDCT. |
884 | | // |
885 | | // The unrolled logic here is: |
886 | | // |
887 | | // if lastNonZero < rowStartIdx[i], |
888 | | // zeroedRows = rowsEmpty[i] |
889 | | // |
890 | | // where: |
891 | | // |
892 | | // const int rowStartIdx[] = {2, 3, 9, 10, 20, 21, 35}; |
893 | | // const int rowsEmpty[] = {7, 6, 5, 4, 3, 2, 1}; |
894 | | // |
895 | |
|
896 | 0 | if (lastNonZero < 2) |
897 | 0 | dctInverse8x8_7(_dctData[comp]._buffer); |
898 | 0 | else if (lastNonZero < 3) |
899 | 0 | dctInverse8x8_6(_dctData[comp]._buffer); |
900 | 0 | else if (lastNonZero < 9) |
901 | 0 | dctInverse8x8_5(_dctData[comp]._buffer); |
902 | 0 | else if (lastNonZero < 10) |
903 | 0 | dctInverse8x8_4(_dctData[comp]._buffer); |
904 | 0 | else if (lastNonZero < 20) |
905 | 0 | dctInverse8x8_3(_dctData[comp]._buffer); |
906 | 0 | else if (lastNonZero < 21) |
907 | 0 | dctInverse8x8_2(_dctData[comp]._buffer); |
908 | 0 | else if (lastNonZero < 35) |
909 | 0 | dctInverse8x8_1(_dctData[comp]._buffer); |
910 | 0 | else |
911 | 0 | dctInverse8x8_0(_dctData[comp]._buffer); |
912 | 0 | } |
913 | 0 | } |
914 | | |
915 | | // |
916 | | // Perform the CSC |
917 | | // |
918 | |
|
919 | 0 | if (numComp == 3) |
920 | 0 | { |
921 | 0 | if (!blockIsConstant) |
922 | 0 | { |
923 | 0 | csc709Inverse64 (_dctData[0]._buffer, |
924 | 0 | _dctData[1]._buffer, |
925 | 0 | _dctData[2]._buffer); |
926 | |
|
927 | 0 | } |
928 | 0 | else |
929 | 0 | { |
930 | 0 | csc709Inverse (_dctData[0]._buffer[0], |
931 | 0 | _dctData[1]._buffer[0], |
932 | 0 | _dctData[2]._buffer[0]); |
933 | 0 | } |
934 | 0 | } |
935 | | |
936 | | // |
937 | | // Float -> Half conversion. |
938 | | // |
939 | | // If the block has a constant value, just convert the first pixel. |
940 | | // |
941 | |
|
942 | 0 | for (unsigned int comp = 0; comp < numComp; ++comp) |
943 | 0 | { |
944 | 0 | if (!blockIsConstant) |
945 | 0 | { |
946 | 0 | (*convertFloatToHalf64) |
947 | 0 | (&rowBlock[comp][blockx*64], _dctData[comp]._buffer); |
948 | 0 | } |
949 | 0 | else |
950 | 0 | { |
951 | 0 | #ifdef IMF_HAVE_SSE2 |
952 | |
|
953 | 0 | __m128i *dst = (__m128i*)&rowBlock[comp][blockx*64]; |
954 | |
|
955 | 0 | dst[0] = _mm_set1_epi16 |
956 | 0 | (((half)_dctData[comp]._buffer[0]).bits()); |
957 | |
|
958 | 0 | dst[1] = dst[0]; |
959 | 0 | dst[2] = dst[0]; |
960 | 0 | dst[3] = dst[0]; |
961 | 0 | dst[4] = dst[0]; |
962 | 0 | dst[5] = dst[0]; |
963 | 0 | dst[6] = dst[0]; |
964 | 0 | dst[7] = dst[0]; |
965 | |
|
966 | | #else /* IMF_HAVE_SSE2 */ |
967 | | |
968 | | unsigned short *dst = &rowBlock[comp][blockx*64]; |
969 | | |
970 | | dst[0] = ((half)_dctData[comp]._buffer[0]).bits(); |
971 | | |
972 | | for (int i = 1; i < 64; ++i) |
973 | | { |
974 | | dst[i] = dst[0]; |
975 | | } |
976 | | |
977 | | #endif /* IMF_HAVE_SSE2 */ |
978 | 0 | } // blockIsConstant |
979 | 0 | } // comp |
980 | 0 | } // blockx |
981 | | |
982 | | // |
983 | | // At this point, we have half-float nonlinear value blocked |
984 | | // in rowBlock[][]. We need to unblock the data, transfer |
985 | | // back to linear, and write the results in the _rowPtrs[]. |
986 | | // |
987 | | // There is a fast-path for aligned rows, which helps |
988 | | // things a little. Since this fast path is only valid |
989 | | // for full 8-element wide blocks, the partial x blocks |
990 | | // are broken into a separate loop below. |
991 | | // |
992 | | // At the moment, the fast path requires: |
993 | | // * sse support |
994 | | // * aligned row pointers |
995 | | // * full 8-element wide blocks |
996 | | // |
997 | |
|
998 | 0 | for (int comp = 0; comp < numComp; ++comp) |
999 | 0 | { |
1000 | | // |
1001 | | // Test if we can use the fast path |
1002 | | // |
1003 | |
|
1004 | 0 | #ifdef IMF_HAVE_SSE2 |
1005 | |
|
1006 | 0 | bool fastPath = true; |
1007 | |
|
1008 | 0 | for (int y = 8 * blocky; y < 8 * blocky + maxY; ++y) |
1009 | 0 | { |
1010 | 0 | if ((size_t)_rowPtrs[comp][y] & _SSE_ALIGNMENT_MASK) |
1011 | 0 | fastPath = false; |
1012 | 0 | } |
1013 | |
|
1014 | 0 | if (fastPath) |
1015 | 0 | { |
1016 | | // |
1017 | | // Handle all the full X blocks, in a fast path with sse2 and |
1018 | | // aligned row pointers |
1019 | | // |
1020 | |
|
1021 | 0 | for (int y=8*blocky; y<8*blocky+maxY; ++y) |
1022 | 0 | { |
1023 | 0 | __m128i *dst = (__m128i *)_rowPtrs[comp][y]; |
1024 | 0 | __m128i *src = (__m128i *)&rowBlock[comp][(y & 0x7) * 8]; |
1025 | | |
1026 | |
|
1027 | 0 | for (int blockx = 0; blockx < numFullBlocksX; ++blockx) |
1028 | 0 | { |
1029 | | // |
1030 | | // These may need some twiddling. |
1031 | | // Run with multiples of 8 |
1032 | | // |
1033 | |
|
1034 | 0 | _mm_prefetch ((char *)(src + 16), _MM_HINT_NTA); |
1035 | |
|
1036 | 0 | unsigned short i0 = _mm_extract_epi16 (*src, 0); |
1037 | 0 | unsigned short i1 = _mm_extract_epi16 (*src, 1); |
1038 | 0 | unsigned short i2 = _mm_extract_epi16 (*src, 2); |
1039 | 0 | unsigned short i3 = _mm_extract_epi16 (*src, 3); |
1040 | |
|
1041 | 0 | unsigned short i4 = _mm_extract_epi16 (*src, 4); |
1042 | 0 | unsigned short i5 = _mm_extract_epi16 (*src, 5); |
1043 | 0 | unsigned short i6 = _mm_extract_epi16 (*src, 6); |
1044 | 0 | unsigned short i7 = _mm_extract_epi16 (*src, 7); |
1045 | |
|
1046 | 0 | i0 = _toLinear[i0]; |
1047 | 0 | i1 = _toLinear[i1]; |
1048 | 0 | i2 = _toLinear[i2]; |
1049 | 0 | i3 = _toLinear[i3]; |
1050 | |
|
1051 | 0 | i4 = _toLinear[i4]; |
1052 | 0 | i5 = _toLinear[i5]; |
1053 | 0 | i6 = _toLinear[i6]; |
1054 | 0 | i7 = _toLinear[i7]; |
1055 | |
|
1056 | 0 | *dst = _mm_insert_epi16 (_mm_setzero_si128(), i0, 0); |
1057 | 0 | *dst = _mm_insert_epi16 (*dst, i1, 1); |
1058 | 0 | *dst = _mm_insert_epi16 (*dst, i2, 2); |
1059 | 0 | *dst = _mm_insert_epi16 (*dst, i3, 3); |
1060 | |
|
1061 | 0 | *dst = _mm_insert_epi16 (*dst, i4, 4); |
1062 | 0 | *dst = _mm_insert_epi16 (*dst, i5, 5); |
1063 | 0 | *dst = _mm_insert_epi16 (*dst, i6, 6); |
1064 | 0 | *dst = _mm_insert_epi16 (*dst, i7, 7); |
1065 | |
|
1066 | 0 | src += 8; |
1067 | 0 | dst++; |
1068 | 0 | } |
1069 | 0 | } |
1070 | 0 | } |
1071 | 0 | else |
1072 | 0 | { |
1073 | |
|
1074 | 0 | #endif /* IMF_HAVE_SSE2 */ |
1075 | | |
1076 | | // |
1077 | | // Basic scalar kinda slow path for handling the full X blocks |
1078 | | // |
1079 | |
|
1080 | 0 | for (int y = 8 * blocky; y < 8 * blocky + maxY; ++y) |
1081 | 0 | { |
1082 | 0 | unsigned short *dst = (unsigned short *)_rowPtrs[comp][y]; |
1083 | |
|
1084 | 0 | for (int blockx = 0; blockx < numFullBlocksX; ++blockx) |
1085 | 0 | { |
1086 | 0 | unsigned short *src = |
1087 | 0 | &rowBlock[comp][blockx * 64 + ((y & 0x7) * 8)]; |
1088 | |
|
1089 | 0 | dst[0] = _toLinear[src[0]]; |
1090 | 0 | dst[1] = _toLinear[src[1]]; |
1091 | 0 | dst[2] = _toLinear[src[2]]; |
1092 | 0 | dst[3] = _toLinear[src[3]]; |
1093 | |
|
1094 | 0 | dst[4] = _toLinear[src[4]]; |
1095 | 0 | dst[5] = _toLinear[src[5]]; |
1096 | 0 | dst[6] = _toLinear[src[6]]; |
1097 | 0 | dst[7] = _toLinear[src[7]]; |
1098 | |
|
1099 | 0 | dst += 8; |
1100 | 0 | } |
1101 | 0 | } |
1102 | |
|
1103 | 0 | #ifdef IMF_HAVE_SSE2 |
1104 | |
|
1105 | 0 | } |
1106 | |
|
1107 | 0 | #endif /* IMF_HAVE_SSE2 */ |
1108 | | |
1109 | | // |
1110 | | // If we have partial X blocks, deal with all those now |
1111 | | // Since this should be minimal work, there currently |
1112 | | // is only one path that should work for everyone. |
1113 | | // |
1114 | |
|
1115 | 0 | if (numFullBlocksX != numBlocksX) |
1116 | 0 | { |
1117 | 0 | for (int y = 8 * blocky; y < 8 * blocky + maxY; ++y) |
1118 | 0 | { |
1119 | 0 | unsigned short *src = (unsigned short *) |
1120 | 0 | &rowBlock[comp][numFullBlocksX * 64 + ((y & 0x7) * 8)]; |
1121 | |
|
1122 | 0 | unsigned short *dst = (unsigned short *)_rowPtrs[comp][y]; |
1123 | |
|
1124 | 0 | dst += 8 * numFullBlocksX; |
1125 | |
|
1126 | 0 | for (int x = 0; x < maxX; ++x) |
1127 | 0 | { |
1128 | 0 | *dst++ = _toLinear[*src++]; |
1129 | 0 | } |
1130 | 0 | } |
1131 | 0 | } |
1132 | 0 | } // comp |
1133 | 0 | } // blocky |
1134 | | |
1135 | | // |
1136 | | // Walk over all the channels that are of type FLOAT. |
1137 | | // Convert from HALF XDR back to FLOAT XDR. |
1138 | | // |
1139 | |
|
1140 | 0 | for (unsigned int chan = 0; chan < numComp; ++chan) |
1141 | 0 | { |
1142 | |
|
1143 | 0 | if (_type[chan] != FLOAT) |
1144 | 0 | continue; |
1145 | | |
1146 | 0 | std::vector<unsigned short> halfXdr (_width); |
1147 | |
|
1148 | 0 | for (int y=0; y<_height; ++y) |
1149 | 0 | { |
1150 | 0 | char *floatXdrPtr = _rowPtrs[chan][y]; |
1151 | |
|
1152 | 0 | memcpy(&halfXdr[0], floatXdrPtr, _width*sizeof(unsigned short)); |
1153 | |
|
1154 | 0 | const char *halfXdrPtr = (const char *)(&halfXdr[0]); |
1155 | |
|
1156 | 0 | for (int x=0; x<_width; ++x) |
1157 | 0 | { |
1158 | 0 | half tmpHalf; |
1159 | |
|
1160 | 0 | Xdr::read<CharPtrIO> (halfXdrPtr, tmpHalf); |
1161 | 0 | Xdr::write<CharPtrIO> (floatXdrPtr, (float)tmpHalf); |
1162 | | |
1163 | | // |
1164 | | // Xdr::write and Xdr::read will advance the ptrs |
1165 | | // |
1166 | 0 | } |
1167 | 0 | } |
1168 | 0 | } |
1169 | |
|
1170 | 0 | delete[] rowBlockHandle; |
1171 | 0 | } |
1172 | | |
1173 | | |
1174 | | // |
1175 | | // Un-RLE the packed AC components into |
1176 | | // a half buffer. The half block should |
1177 | | // be the full 8x8 block (in zig-zag order |
1178 | | // still), not the first AC component. |
1179 | | // |
1180 | | // currAcComp is advanced as bytes are decoded. |
1181 | | // |
1182 | | // This returns the index of the last non-zero |
1183 | | // value in the buffer - with the index into zig zag |
1184 | | // order data. If we return 0, we have DC only data. |
1185 | | // |
1186 | | // This is assuminging that halfZigBlock is zero'ed |
1187 | | // prior to calling |
1188 | | // |
1189 | | |
1190 | | int |
1191 | | DwaCompressor::LossyDctDecoderBase::unRleAc |
1192 | | (unsigned short *&currAcComp, |
1193 | | unsigned short *halfZigBlock) |
1194 | 0 | { |
1195 | | // |
1196 | | // Un-RLE the RLE'd blocks. If we find an item whose |
1197 | | // high byte is 0xff, then insert the number of 0's |
1198 | | // as indicated by the low byte. |
1199 | | // |
1200 | | // Otherwise, just copy the number verbaitm. |
1201 | | // |
1202 | |
|
1203 | 0 | int lastNonZero = 0; |
1204 | 0 | int dctComp = 1; |
1205 | | |
1206 | | // |
1207 | | // Start with a zero'ed block, so we don't have to |
1208 | | // write when we hit a run symbol |
1209 | | // |
1210 | |
|
1211 | 0 | while (dctComp < 64) |
1212 | 0 | { |
1213 | 0 | if (*currAcComp == 0xff00) |
1214 | 0 | { |
1215 | | // |
1216 | | // End of block |
1217 | | // |
1218 | |
|
1219 | 0 | dctComp = 64; |
1220 | |
|
1221 | 0 | } |
1222 | 0 | else if ((*currAcComp) >> 8 == 0xff) |
1223 | 0 | { |
1224 | | // |
1225 | | // Run detected! Insert 0's. |
1226 | | // |
1227 | | // Since the block has been zeroed, just advance the ptr |
1228 | | // |
1229 | |
|
1230 | 0 | dctComp += (*currAcComp) & 0xff; |
1231 | 0 | } |
1232 | 0 | else |
1233 | 0 | { |
1234 | | // |
1235 | | // Not a run, just copy over the value |
1236 | | // |
1237 | |
|
1238 | 0 | lastNonZero = dctComp; |
1239 | 0 | halfZigBlock[dctComp] = *currAcComp; |
1240 | |
|
1241 | 0 | dctComp++; |
1242 | 0 | } |
1243 | |
|
1244 | 0 | _packedAcCount++; |
1245 | 0 | currAcComp++; |
1246 | 0 | } |
1247 | |
|
1248 | 0 | return lastNonZero; |
1249 | 0 | } |
1250 | | |
1251 | | |
1252 | | // ============================================================== |
1253 | | // |
1254 | | // LossyDctEncoderBase |
1255 | | // |
1256 | | // -------------------------------------------------------------- |
1257 | | |
1258 | | DwaCompressor::LossyDctEncoderBase::LossyDctEncoderBase |
1259 | | (float quantBaseError, |
1260 | | char *packedAc, |
1261 | | char *packedDc, |
1262 | | const unsigned short *toNonlinear, |
1263 | | int width, |
1264 | | int height) |
1265 | | : |
1266 | 0 | _quantBaseError(quantBaseError), |
1267 | 0 | _width(width), |
1268 | 0 | _height(height), |
1269 | 0 | _toNonlinear(toNonlinear), |
1270 | 0 | _numAcComp(0), |
1271 | 0 | _numDcComp(0), |
1272 | 0 | _packedAc(packedAc), |
1273 | 0 | _packedDc(packedDc) |
1274 | 0 | { |
1275 | | // |
1276 | | // Here, we take the generic JPEG quantization tables and |
1277 | | // normalize them by the smallest component in each table. |
1278 | | // This gives us a relationship amongst the DCT components, |
1279 | | // in terms of how sensitive each component is to |
1280 | | // error. |
1281 | | // |
1282 | | // A higher normalized value means we can quantize more, |
1283 | | // and a small normalized value means we can quantize less. |
1284 | | // |
1285 | | // Eventually, we will want an acceptable quantization |
1286 | | // error range for each component. We find this by |
1287 | | // multiplying some user-specified level (_quantBaseError) |
1288 | | // by the normalized table (_quantTableY, _quantTableCbCr) to |
1289 | | // find the acceptable quantization error range. |
1290 | | // |
1291 | | // The quantization table is not needed for decoding, and |
1292 | | // is not transmitted. So, if you want to get really fancy, |
1293 | | // you could derive some content-dependent quantization |
1294 | | // table, and the decoder would not need to be changed. But, |
1295 | | // for now, we'll just use statice quantization tables. |
1296 | | // |
1297 | |
|
1298 | 0 | int jpegQuantTableY[] = |
1299 | 0 | { |
1300 | 0 | 16, 11, 10, 16, 24, 40, 51, 61, |
1301 | 0 | 12, 12, 14, 19, 26, 58, 60, 55, |
1302 | 0 | 14, 13, 16, 24, 40, 57, 69, 56, |
1303 | 0 | 14, 17, 22, 29, 51, 87, 80, 62, |
1304 | 0 | 18, 22, 37, 56, 68, 109, 103, 77, |
1305 | 0 | 24, 35, 55, 64, 81, 104, 113, 92, |
1306 | 0 | 49, 64, 78, 87, 103, 121, 120, 101, |
1307 | 0 | 72, 92, 95, 98, 112, 100, 103, 99 |
1308 | 0 | }; |
1309 | |
|
1310 | 0 | int jpegQuantTableYMin = 10; |
1311 | |
|
1312 | 0 | int jpegQuantTableCbCr[] = |
1313 | 0 | { |
1314 | 0 | 17, 18, 24, 47, 99, 99, 99, 99, |
1315 | 0 | 18, 21, 26, 66, 99, 99, 99, 99, |
1316 | 0 | 24, 26, 56, 99, 99, 99, 99, 99, |
1317 | 0 | 47, 66, 99, 99, 99, 99, 99, 99, |
1318 | 0 | 99, 99, 99, 99, 99, 99, 99, 99, |
1319 | 0 | 99, 99, 99, 99, 99, 99, 99, 99, |
1320 | 0 | 99, 99, 99, 99, 99, 99, 99, 99, |
1321 | 0 | 99, 99, 99, 99, 99, 99, 99, 99 |
1322 | 0 | }; |
1323 | |
|
1324 | 0 | int jpegQuantTableCbCrMin = 17; |
1325 | |
|
1326 | 0 | for (int idx = 0; idx < 64; ++idx) |
1327 | 0 | { |
1328 | 0 | _quantTableY[idx] = static_cast<float> (jpegQuantTableY[idx]) / |
1329 | 0 | static_cast<float> (jpegQuantTableYMin); |
1330 | |
|
1331 | 0 | _quantTableCbCr[idx] = static_cast<float> (jpegQuantTableCbCr[idx]) / |
1332 | 0 | static_cast<float> (jpegQuantTableCbCrMin); |
1333 | 0 | } |
1334 | | |
1335 | 0 | if (_quantBaseError < 0) |
1336 | 0 | quantBaseError = 0; |
1337 | 0 | } |
1338 | | |
1339 | | |
1340 | | DwaCompressor::LossyDctEncoderBase::~LossyDctEncoderBase () |
1341 | 0 | { |
1342 | 0 | } |
1343 | | |
1344 | | |
1345 | | // |
1346 | | // Given three channels of source data, encoding by first applying |
1347 | | // a color space conversion to a YCbCr space. Otherwise, if we only |
1348 | | // have one channel, just encode it as is. |
1349 | | // |
1350 | | // Other numbers of channels are somewhat unexpected at this point, |
1351 | | // and will throw an exception. |
1352 | | // |
1353 | | |
1354 | | void |
1355 | | DwaCompressor::LossyDctEncoderBase::execute () |
1356 | 0 | { |
1357 | 0 | int numBlocksX = (int)ceil ((float)_width / 8.0f); |
1358 | 0 | int numBlocksY = (int)ceil ((float)_height/ 8.0f); |
1359 | |
|
1360 | 0 | half halfZigCoef[64]; |
1361 | 0 | half halfCoef[64]; |
1362 | |
|
1363 | 0 | std::vector<unsigned short *> currDcComp (_rowPtrs.size()); |
1364 | 0 | unsigned short *currAcComp = (unsigned short *)_packedAc; |
1365 | |
|
1366 | 0 | _dctData.resize (_rowPtrs.size()); |
1367 | 0 | _numAcComp = 0; |
1368 | 0 | _numDcComp = 0; |
1369 | | |
1370 | 0 | assert (_type.size() == _rowPtrs.size()); |
1371 | 0 | assert ((_rowPtrs.size() == 3) || (_rowPtrs.size() == 1)); |
1372 | | |
1373 | | // |
1374 | | // Allocate a temp half buffer to quantize into for |
1375 | | // any FLOAT source channels. |
1376 | | // |
1377 | |
|
1378 | 0 | int tmpHalfBufferElements = 0; |
1379 | |
|
1380 | 0 | for (unsigned int chan = 0; chan < _rowPtrs.size(); ++chan) |
1381 | 0 | if (_type[chan] == FLOAT) |
1382 | 0 | tmpHalfBufferElements += _width * _height; |
1383 | |
|
1384 | 0 | std::vector<unsigned short> tmpHalfBuffer (tmpHalfBufferElements); |
1385 | |
|
1386 | 0 | char *tmpHalfBufferPtr = 0; |
1387 | |
|
1388 | 0 | if (tmpHalfBufferElements) |
1389 | 0 | tmpHalfBufferPtr = (char *)&tmpHalfBuffer[0]; |
1390 | | |
1391 | | // |
1392 | | // Run over all the float scanlines, quantizing, |
1393 | | // and re-assigning _rowPtr[y]. We need to translate |
1394 | | // FLOAT XDR to HALF XDR. |
1395 | | // |
1396 | |
|
1397 | 0 | for (unsigned int chan = 0; chan < _rowPtrs.size(); ++chan) |
1398 | 0 | { |
1399 | 0 | if (_type[chan] != FLOAT) |
1400 | 0 | continue; |
1401 | | |
1402 | 0 | for (int y = 0; y < _height; ++y) |
1403 | 0 | { |
1404 | 0 | float src = 0; |
1405 | 0 | const char *srcXdr = _rowPtrs[chan][y]; |
1406 | 0 | char *dstXdr = tmpHalfBufferPtr; |
1407 | | |
1408 | 0 | for (int x = 0; x < _width; ++x) |
1409 | 0 | { |
1410 | |
|
1411 | 0 | Xdr::read<CharPtrIO> (srcXdr, src); |
1412 | | |
1413 | | // |
1414 | | // Clamp to half ranges, instead of just casting. This |
1415 | | // avoids introducing Infs which end up getting zeroed later |
1416 | | // |
1417 | 0 | src = std::max ( |
1418 | 0 | std::min ((float) std::numeric_limits<half>::max(), src), |
1419 | 0 | (float)-std::numeric_limits<half>::max()); |
1420 | |
|
1421 | 0 | Xdr::write<CharPtrIO> (dstXdr, ((half)src).bits()); |
1422 | | |
1423 | | // |
1424 | | // Xdr::read and Xdr::write will advance the ptr |
1425 | | // |
1426 | 0 | } |
1427 | |
|
1428 | 0 | _rowPtrs[chan][y] = (const char *)tmpHalfBufferPtr; |
1429 | 0 | tmpHalfBufferPtr += _width * sizeof (unsigned short); |
1430 | 0 | } |
1431 | 0 | } |
1432 | | |
1433 | | // |
1434 | | // Pack DC components together by common plane, so we can get |
1435 | | // a little more out of differencing them. We'll always have |
1436 | | // one component per block, so we can computed offsets. |
1437 | | // |
1438 | |
|
1439 | 0 | currDcComp[0] = (unsigned short *)_packedDc; |
1440 | |
|
1441 | 0 | for (unsigned int chan = 1; chan < _rowPtrs.size(); ++chan) |
1442 | 0 | currDcComp[chan] = currDcComp[chan-1] + numBlocksX * numBlocksY; |
1443 | |
|
1444 | 0 | for (int blocky = 0; blocky < numBlocksY; ++blocky) |
1445 | 0 | { |
1446 | 0 | for (int blockx = 0; blockx < numBlocksX; ++blockx) |
1447 | 0 | { |
1448 | 0 | half h; |
1449 | 0 | unsigned short tmpShortXdr, tmpShortNative; |
1450 | 0 | char *tmpCharPtr; |
1451 | |
|
1452 | 0 | for (unsigned int chan = 0; chan < _rowPtrs.size(); ++chan) |
1453 | 0 | { |
1454 | | // |
1455 | | // Break the source into 8x8 blocks. If we don't |
1456 | | // fit at the edges, mirror. |
1457 | | // |
1458 | | // Also, convert from linear to nonlinear representation. |
1459 | | // Our source is assumed to be XDR, and we need to convert |
1460 | | // to NATIVE prior to converting to float. |
1461 | | // |
1462 | | // If we're converting linear -> nonlinear, assume that the |
1463 | | // XDR -> NATIVE conversion is built into the lookup. Otherwise, |
1464 | | // we'll need to explicitly do it. |
1465 | | // |
1466 | |
|
1467 | 0 | for (int y = 0; y < 8; ++y) |
1468 | 0 | { |
1469 | 0 | for (int x = 0; x < 8; ++x) |
1470 | 0 | { |
1471 | 0 | int vx = 8 * blockx + x; |
1472 | 0 | int vy = 8 * blocky + y; |
1473 | |
|
1474 | 0 | if (vx >= _width) |
1475 | 0 | vx = _width - (vx - (_width - 1)); |
1476 | | |
1477 | 0 | if (vx < 0) vx = _width-1; |
1478 | |
|
1479 | 0 | if (vy >=_height) |
1480 | 0 | vy = _height - (vy - (_height - 1)); |
1481 | |
|
1482 | 0 | if (vy < 0) vy = _height-1; |
1483 | | |
1484 | 0 | tmpShortXdr = |
1485 | 0 | ((const unsigned short *)(_rowPtrs[chan])[vy])[vx]; |
1486 | |
|
1487 | 0 | if (_toNonlinear) |
1488 | 0 | { |
1489 | 0 | h.setBits (_toNonlinear[tmpShortXdr]); |
1490 | 0 | } |
1491 | 0 | else |
1492 | 0 | { |
1493 | 0 | const char *tmpConstCharPtr = |
1494 | 0 | (const char *)(&tmpShortXdr); |
1495 | |
|
1496 | 0 | Xdr::read<CharPtrIO> |
1497 | 0 | (tmpConstCharPtr, tmpShortNative); |
1498 | |
|
1499 | 0 | h.setBits(tmpShortNative); |
1500 | 0 | } |
1501 | |
|
1502 | 0 | _dctData[chan]._buffer[y * 8 + x] = (float)h; |
1503 | 0 | } // x |
1504 | 0 | } // y |
1505 | 0 | } // chan |
1506 | | |
1507 | | // |
1508 | | // Color space conversion |
1509 | | // |
1510 | |
|
1511 | 0 | if (_rowPtrs.size() == 3) |
1512 | 0 | { |
1513 | 0 | csc709Forward64 (_dctData[0]._buffer, |
1514 | 0 | _dctData[1]._buffer, |
1515 | 0 | _dctData[2]._buffer); |
1516 | 0 | } |
1517 | |
|
1518 | 0 | for (unsigned int chan = 0; chan < _rowPtrs.size(); ++chan) |
1519 | 0 | { |
1520 | | // |
1521 | | // Forward DCT |
1522 | | // |
1523 | |
|
1524 | 0 | dctForward8x8(_dctData[chan]._buffer); |
1525 | | |
1526 | | // |
1527 | | // Quantize to half, and zigzag |
1528 | | // |
1529 | |
|
1530 | 0 | if (chan == 0) |
1531 | 0 | { |
1532 | 0 | for (int i = 0; i < 64; ++i) |
1533 | 0 | { |
1534 | 0 | halfCoef[i] = |
1535 | 0 | quantize ((half)_dctData[chan]._buffer[i], |
1536 | 0 | _quantBaseError*_quantTableY[i]); |
1537 | 0 | } |
1538 | 0 | } |
1539 | 0 | else |
1540 | 0 | { |
1541 | 0 | for (int i = 0; i < 64; ++i) |
1542 | 0 | { |
1543 | 0 | halfCoef[i] = |
1544 | 0 | quantize ((half)_dctData[chan]._buffer[i], |
1545 | 0 | _quantBaseError*_quantTableCbCr[i]); |
1546 | 0 | } |
1547 | 0 | } |
1548 | |
|
1549 | 0 | toZigZag (halfZigCoef, halfCoef); |
1550 | | |
1551 | | // |
1552 | | // Convert from NATIVE back to XDR, before we write out |
1553 | | // |
1554 | |
|
1555 | 0 | for (int i = 0; i < 64; ++i) |
1556 | 0 | { |
1557 | 0 | tmpCharPtr = (char *)&tmpShortXdr; |
1558 | 0 | Xdr::write<CharPtrIO>(tmpCharPtr, halfZigCoef[i].bits()); |
1559 | 0 | halfZigCoef[i].setBits(tmpShortXdr); |
1560 | 0 | } |
1561 | | |
1562 | | // |
1563 | | // Save the DC component separately, to be compressed on |
1564 | | // its own. |
1565 | | // |
1566 | |
|
1567 | 0 | *currDcComp[chan]++ = halfZigCoef[0].bits(); |
1568 | 0 | _numDcComp++; |
1569 | | |
1570 | | // |
1571 | | // Then RLE the AC components (which will record the count |
1572 | | // of the resulting number of items) |
1573 | | // |
1574 | |
|
1575 | 0 | rleAc (halfZigCoef, currAcComp); |
1576 | 0 | } // chan |
1577 | 0 | } // blockx |
1578 | 0 | } // blocky |
1579 | 0 | } |
1580 | | |
1581 | | |
1582 | | // |
1583 | | // Reorder from zig-zag order to normal ordering |
1584 | | // |
1585 | | |
1586 | | void |
1587 | | DwaCompressor::LossyDctEncoderBase::toZigZag (half *dst, half *src) |
1588 | 0 | { |
1589 | 0 | const int remap[] = |
1590 | 0 | { |
1591 | 0 | 0, |
1592 | 0 | 1, 8, |
1593 | 0 | 16, 9, 2, |
1594 | 0 | 3, 10, 17, 24, |
1595 | 0 | 32, 25, 18, 11, 4, |
1596 | 0 | 5, 12, 19, 26, 33, 40, |
1597 | 0 | 48, 41, 34, 27, 20, 13, 6, |
1598 | 0 | 7, 14, 21, 28, 35, 42, 49, 56, |
1599 | 0 | 57, 50, 43, 36, 29, 22, 15, |
1600 | 0 | 23, 30, 37, 44, 51, 58, |
1601 | 0 | 59, 52, 45, 38, 31, |
1602 | 0 | 39, 46, 53, 60, |
1603 | 0 | 61, 54, 47, |
1604 | 0 | 55, 62, |
1605 | 0 | 63 |
1606 | 0 | }; |
1607 | |
|
1608 | 0 | for (int i=0; i<64; ++i) |
1609 | 0 | dst[i] = src[remap[i]]; |
1610 | 0 | } |
1611 | | |
1612 | | |
1613 | | // |
1614 | | // Precomputing the bit count runs faster than using |
1615 | | // the builtin instruction, at least in one case.. |
1616 | | // |
1617 | | // Precomputing 8-bits is no slower than 16-bits, |
1618 | | // and saves a fair bit of overhead.. |
1619 | | // |
1620 | | |
1621 | | int |
1622 | | DwaCompressor::LossyDctEncoderBase::countSetBits (unsigned short src) |
1623 | 0 | { |
1624 | 0 | static const unsigned short numBitsSet[256] = |
1625 | 0 | { |
1626 | 0 | 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, |
1627 | 0 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, |
1628 | 0 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, |
1629 | 0 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
1630 | 0 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, |
1631 | 0 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
1632 | 0 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
1633 | 0 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, |
1634 | 0 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, |
1635 | 0 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
1636 | 0 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
1637 | 0 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, |
1638 | 0 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
1639 | 0 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, |
1640 | 0 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, |
1641 | 0 | 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 |
1642 | 0 | }; |
1643 | |
|
1644 | 0 | return numBitsSet[src & 0xff] + numBitsSet[src >> 8]; |
1645 | 0 | } |
1646 | | |
1647 | | |
1648 | | // |
1649 | | // Take a DCT coefficient, as well as an acceptable error. Search |
1650 | | // nearby values within the error tolerance, that have fewer |
1651 | | // bits set. |
1652 | | // |
1653 | | // The list of candidates has been pre-computed and sorted |
1654 | | // in order of increasing numbers of bits set. This way, we |
1655 | | // can stop searching as soon as we find a candidate that |
1656 | | // is within the error tolerance. |
1657 | | // |
1658 | | |
1659 | | half |
1660 | | DwaCompressor::LossyDctEncoderBase::quantize (half src, float errorTolerance) |
1661 | 0 | { |
1662 | 0 | half tmp; |
1663 | 0 | float srcFloat = (float)src; |
1664 | 0 | int numSetBits = countSetBits(src.bits()); |
1665 | 0 | const unsigned short *closest = get_dwaClosest(src.bits()); |
1666 | |
|
1667 | 0 | for (int targetNumSetBits = numSetBits - 1; |
1668 | 0 | targetNumSetBits >= 0; |
1669 | 0 | --targetNumSetBits) |
1670 | 0 | { |
1671 | 0 | tmp.setBits (*closest); |
1672 | |
|
1673 | 0 | if (fabs ((float)tmp - srcFloat) < errorTolerance) |
1674 | 0 | return tmp; |
1675 | | |
1676 | 0 | closest++; |
1677 | 0 | } |
1678 | | |
1679 | 0 | return src; |
1680 | 0 | } |
1681 | | |
1682 | | |
1683 | | // |
1684 | | // RLE the zig-zag of the AC components + copy over |
1685 | | // into another tmp buffer |
1686 | | // |
1687 | | // Try to do a simple RLE scheme to reduce run's of 0's. This |
1688 | | // differs from the jpeg EOB case, since EOB just indicates that |
1689 | | // the rest of the block is zero. In our case, we have lots of |
1690 | | // NaN symbols, which shouldn't be allowed to occur in DCT |
1691 | | // coefficents - so we'll use them for encoding runs. |
1692 | | // |
1693 | | // If the high byte is 0xff, then we have a run of 0's, of length |
1694 | | // given by the low byte. For example, 0xff03 would be a run |
1695 | | // of 3 0's, starting at the current location. |
1696 | | // |
1697 | | // block is our block of 64 coefficients |
1698 | | // acPtr a pointer to back the RLE'd values into. |
1699 | | // |
1700 | | // This will advance the counter, _numAcComp. |
1701 | | // |
1702 | | |
1703 | | void |
1704 | | DwaCompressor::LossyDctEncoderBase::rleAc |
1705 | | (half *block, |
1706 | | unsigned short *&acPtr) |
1707 | 0 | { |
1708 | 0 | int dctComp = 1; |
1709 | 0 | unsigned short rleSymbol = 0x0; |
1710 | |
|
1711 | 0 | while (dctComp < 64) |
1712 | 0 | { |
1713 | 0 | int runLen = 1; |
1714 | | |
1715 | | // |
1716 | | // If we don't have a 0, output verbatim |
1717 | | // |
1718 | |
|
1719 | 0 | if (block[dctComp].bits() != rleSymbol) |
1720 | 0 | { |
1721 | 0 | *acPtr++ = block[dctComp].bits(); |
1722 | 0 | _numAcComp++; |
1723 | |
|
1724 | 0 | dctComp += runLen; |
1725 | 0 | continue; |
1726 | 0 | } |
1727 | | |
1728 | | // |
1729 | | // We're sitting on a 0, so see how big the run is. |
1730 | | // |
1731 | | |
1732 | 0 | while ((dctComp+runLen < 64) && |
1733 | 0 | (block[dctComp+runLen].bits() == rleSymbol)) |
1734 | 0 | { |
1735 | 0 | runLen++; |
1736 | 0 | } |
1737 | | |
1738 | | // |
1739 | | // If the run len is too small, just output verbatim |
1740 | | // otherwise output our run token |
1741 | | // |
1742 | | // Originally, we wouldn't have a separate symbol for |
1743 | | // "end of block". But in some experimentation, it looks |
1744 | | // like using 0xff00 for "end of block" can save a bit |
1745 | | // of space. |
1746 | | // |
1747 | |
|
1748 | 0 | if (runLen == 1) |
1749 | 0 | { |
1750 | 0 | runLen = 1; |
1751 | 0 | *acPtr++ = block[dctComp].bits(); |
1752 | 0 | _numAcComp++; |
1753 | | |
1754 | | // |
1755 | | // Using 0xff00 for "end of block" |
1756 | | // |
1757 | 0 | } |
1758 | 0 | else if (runLen + dctComp == 64) |
1759 | 0 | { |
1760 | | // |
1761 | | // Signal EOB |
1762 | | // |
1763 | |
|
1764 | 0 | *acPtr++ = 0xff00; |
1765 | 0 | _numAcComp++; |
1766 | 0 | } |
1767 | 0 | else |
1768 | 0 | { |
1769 | | // |
1770 | | // Signal normal run |
1771 | | // |
1772 | |
|
1773 | 0 | *acPtr++ = 0xff00 | runLen; |
1774 | 0 | _numAcComp++; |
1775 | 0 | } |
1776 | | |
1777 | | // |
1778 | | // Advance by runLen |
1779 | | // |
1780 | |
|
1781 | 0 | dctComp += runLen; |
1782 | 0 | } |
1783 | 0 | } |
1784 | | |
1785 | | |
1786 | | // ============================================================== |
1787 | | // |
1788 | | // DwaCompressor |
1789 | | // |
1790 | | // -------------------------------------------------------------- |
1791 | | |
1792 | | // |
1793 | | // DwaCompressor() |
1794 | | // |
1795 | | |
1796 | | DwaCompressor::DwaCompressor |
1797 | | (const Header &hdr, |
1798 | | int maxScanLineSize, |
1799 | | int numScanLines, |
1800 | | AcCompression acCompression) |
1801 | | : |
1802 | 0 | Compressor(hdr), |
1803 | 0 | _acCompression(acCompression), |
1804 | 0 | _maxScanLineSize(maxScanLineSize), |
1805 | 0 | _numScanLines(numScanLines), |
1806 | 0 | _channels(hdr.channels()), |
1807 | 0 | _packedAcBuffer(0), |
1808 | 0 | _packedAcBufferSize(0), |
1809 | 0 | _packedDcBuffer(0), |
1810 | 0 | _packedDcBufferSize(0), |
1811 | 0 | _rleBuffer(0), |
1812 | 0 | _rleBufferSize(0), |
1813 | 0 | _outBuffer(0), |
1814 | 0 | _outBufferSize(0), |
1815 | 0 | _zip(0), |
1816 | 0 | _dwaCompressionLevel(45.0) |
1817 | 0 | { |
1818 | 0 | _min[0] = hdr.dataWindow().min.x; |
1819 | 0 | _min[1] = hdr.dataWindow().min.y; |
1820 | 0 | _max[0] = hdr.dataWindow().max.x; |
1821 | 0 | _max[1] = hdr.dataWindow().max.y; |
1822 | |
|
1823 | 0 | for (int i=0; i < NUM_COMPRESSOR_SCHEMES; ++i) |
1824 | 0 | { |
1825 | 0 | _planarUncBuffer[i] = 0; |
1826 | 0 | _planarUncBufferSize[i] = 0; |
1827 | 0 | } |
1828 | | |
1829 | | // |
1830 | | // Check the header for a quality attribute |
1831 | | // |
1832 | |
|
1833 | 0 | if (hasDwaCompressionLevel (hdr)) |
1834 | 0 | _dwaCompressionLevel = dwaCompressionLevel (hdr); |
1835 | 0 | } |
1836 | | |
1837 | | |
1838 | | DwaCompressor::~DwaCompressor() |
1839 | 0 | { |
1840 | 0 | delete[] _packedAcBuffer; |
1841 | 0 | delete[] _packedDcBuffer; |
1842 | 0 | delete[] _rleBuffer; |
1843 | 0 | delete[] _outBuffer; |
1844 | 0 | delete _zip; |
1845 | |
|
1846 | 0 | for (int i=0; i<NUM_COMPRESSOR_SCHEMES; ++i) |
1847 | 0 | delete[] _planarUncBuffer[i]; |
1848 | 0 | } |
1849 | | |
1850 | | |
1851 | | int |
1852 | | DwaCompressor::numScanLines() const |
1853 | 0 | { |
1854 | 0 | return _numScanLines; |
1855 | 0 | } |
1856 | | |
1857 | | |
1858 | | OPENEXR_IMF_NAMESPACE::Compressor::Format |
1859 | | DwaCompressor::format() const |
1860 | 0 | { |
1861 | 0 | if (GLOBAL_SYSTEM_LITTLE_ENDIAN) |
1862 | 0 | return NATIVE; |
1863 | 0 | else |
1864 | 0 | return XDR; |
1865 | 0 | } |
1866 | | |
1867 | | |
1868 | | int |
1869 | | DwaCompressor::compress |
1870 | | (const char *inPtr, |
1871 | | int inSize, |
1872 | | int minY, |
1873 | | const char *&outPtr) |
1874 | 0 | { |
1875 | 0 | return compress |
1876 | 0 | (inPtr, |
1877 | 0 | inSize, |
1878 | 0 | IMATH_NAMESPACE::Box2i (IMATH_NAMESPACE::V2i (_min[0], minY), |
1879 | 0 | IMATH_NAMESPACE::V2i (_max[0], minY + numScanLines() - 1)), |
1880 | 0 | outPtr); |
1881 | 0 | } |
1882 | | |
1883 | | |
1884 | | int |
1885 | | DwaCompressor::compressTile |
1886 | | (const char *inPtr, |
1887 | | int inSize, |
1888 | | IMATH_NAMESPACE::Box2i range, |
1889 | | const char *&outPtr) |
1890 | 0 | { |
1891 | 0 | return compress (inPtr, inSize, range, outPtr); |
1892 | 0 | } |
1893 | | |
1894 | | |
1895 | | int |
1896 | | DwaCompressor::compress |
1897 | | (const char *inPtr, |
1898 | | int inSize, |
1899 | | IMATH_NAMESPACE::Box2i range, |
1900 | | const char *&outPtr) |
1901 | 0 | { |
1902 | 0 | const char *inDataPtr = inPtr; |
1903 | 0 | char *packedAcEnd = 0; |
1904 | 0 | char *packedDcEnd = 0; |
1905 | 0 | int fileVersion = 2; // Starting with 2, we write the channel |
1906 | | // classification rules into the file |
1907 | |
|
1908 | 0 | if (fileVersion < 2) |
1909 | 0 | initializeLegacyChannelRules(); |
1910 | 0 | else |
1911 | 0 | initializeDefaultChannelRules(); |
1912 | |
|
1913 | 0 | size_t outBufferSize = 0; |
1914 | 0 | initializeBuffers(outBufferSize); |
1915 | |
|
1916 | 0 | unsigned short channelRuleSize = 0; |
1917 | 0 | std::vector<Classifier> channelRules; |
1918 | 0 | if (fileVersion >= 2) |
1919 | 0 | { |
1920 | 0 | relevantChannelRules(channelRules); |
1921 | |
|
1922 | 0 | channelRuleSize = Xdr::size<unsigned short>(); |
1923 | 0 | for (size_t i = 0; i < channelRules.size(); ++i) |
1924 | 0 | channelRuleSize += channelRules[i].size(); |
1925 | 0 | } |
1926 | | |
1927 | | // |
1928 | | // Remember to allocate _outBuffer, if we haven't done so already. |
1929 | | // |
1930 | |
|
1931 | 0 | outBufferSize += channelRuleSize; |
1932 | 0 | if (outBufferSize > _outBufferSize) |
1933 | 0 | { |
1934 | 0 | _outBufferSize = outBufferSize; |
1935 | 0 | if (_outBuffer != 0) |
1936 | 0 | delete[] _outBuffer; |
1937 | 0 | _outBuffer = new char[outBufferSize]; |
1938 | 0 | } |
1939 | |
|
1940 | 0 | char *outDataPtr = &_outBuffer[NUM_SIZES_SINGLE * sizeof(OPENEXR_IMF_NAMESPACE::Int64) + |
1941 | 0 | channelRuleSize]; |
1942 | | |
1943 | | // |
1944 | | // We might not be dealing with any color data, in which |
1945 | | // case the AC buffer size will be 0, and deferencing |
1946 | | // a vector will not be a good thing to do. |
1947 | | // |
1948 | |
|
1949 | 0 | if (_packedAcBuffer) |
1950 | 0 | packedAcEnd = _packedAcBuffer; |
1951 | |
|
1952 | 0 | if (_packedDcBuffer) |
1953 | 0 | packedDcEnd = _packedDcBuffer; |
1954 | |
|
1955 | 0 | #define OBIDX(x) (Int64 *)&_outBuffer[x * sizeof (Int64)] |
1956 | |
|
1957 | 0 | Int64 *version = OBIDX (VERSION); |
1958 | 0 | Int64 *unknownUncompressedSize = OBIDX (UNKNOWN_UNCOMPRESSED_SIZE); |
1959 | 0 | Int64 *unknownCompressedSize = OBIDX (UNKNOWN_COMPRESSED_SIZE); |
1960 | 0 | Int64 *acCompressedSize = OBIDX (AC_COMPRESSED_SIZE); |
1961 | 0 | Int64 *dcCompressedSize = OBIDX (DC_COMPRESSED_SIZE); |
1962 | 0 | Int64 *rleCompressedSize = OBIDX (RLE_COMPRESSED_SIZE); |
1963 | 0 | Int64 *rleUncompressedSize = OBIDX (RLE_UNCOMPRESSED_SIZE); |
1964 | 0 | Int64 *rleRawSize = OBIDX (RLE_RAW_SIZE); |
1965 | |
|
1966 | 0 | Int64 *totalAcUncompressedCount = OBIDX (AC_UNCOMPRESSED_COUNT); |
1967 | 0 | Int64 *totalDcUncompressedCount = OBIDX (DC_UNCOMPRESSED_COUNT); |
1968 | |
|
1969 | 0 | Int64 *acCompression = OBIDX (AC_COMPRESSION); |
1970 | |
|
1971 | 0 | int minX = range.min.x; |
1972 | 0 | int maxX = std::min(range.max.x, _max[0]); |
1973 | 0 | int minY = range.min.y; |
1974 | 0 | int maxY = std::min(range.max.y, _max[1]); |
1975 | | |
1976 | | // |
1977 | | // Zero all the numbers in the chunk header |
1978 | | // |
1979 | |
|
1980 | 0 | memset (_outBuffer, 0, NUM_SIZES_SINGLE * sizeof (Int64)); |
1981 | | |
1982 | | // |
1983 | | // Setup the AC compression strategy and the version in the data block, |
1984 | | // then write the relevant channel classification rules if needed |
1985 | | // |
1986 | 0 | *version = fileVersion; |
1987 | 0 | *acCompression = _acCompression; |
1988 | |
|
1989 | 0 | setupChannelData (minX, minY, maxX, maxY); |
1990 | |
|
1991 | 0 | if (fileVersion >= 2) |
1992 | 0 | { |
1993 | 0 | char *writePtr = &_outBuffer[NUM_SIZES_SINGLE * sizeof(OPENEXR_IMF_NAMESPACE::Int64)]; |
1994 | 0 | Xdr::write<CharPtrIO> (writePtr, channelRuleSize); |
1995 | | |
1996 | 0 | for (size_t i = 0; i < channelRules.size(); ++i) |
1997 | 0 | channelRules[i].write(writePtr); |
1998 | 0 | } |
1999 | | |
2000 | | // |
2001 | | // Determine the start of each row in the input buffer |
2002 | | // Channels are interleaved by scanline |
2003 | | // |
2004 | |
|
2005 | 0 | std::vector<bool> encodedChannels (_channelData.size()); |
2006 | 0 | std::vector< std::vector<const char *> > rowPtrs (_channelData.size()); |
2007 | |
|
2008 | 0 | for (unsigned int chan = 0; chan < _channelData.size(); ++chan) |
2009 | 0 | encodedChannels[chan] = false; |
2010 | |
|
2011 | 0 | inDataPtr = inPtr; |
2012 | |
|
2013 | 0 | for (int y = minY; y <= maxY; ++y) |
2014 | 0 | { |
2015 | 0 | for (unsigned int chan = 0; chan < _channelData.size(); ++chan) |
2016 | 0 | { |
2017 | |
|
2018 | 0 | ChannelData *cd = &_channelData[chan]; |
2019 | |
|
2020 | 0 | if (IMATH_NAMESPACE::modp(y, cd->ySampling) != 0) |
2021 | 0 | continue; |
2022 | | |
2023 | 0 | rowPtrs[chan].push_back(inDataPtr); |
2024 | 0 | inDataPtr += cd->width * OPENEXR_IMF_NAMESPACE::pixelTypeSize(cd->type); |
2025 | 0 | } |
2026 | 0 | } |
2027 | |
|
2028 | 0 | inDataPtr = inPtr; |
2029 | | |
2030 | | // |
2031 | | // Make a pass over all our CSC sets and try to encode them first |
2032 | | // |
2033 | |
|
2034 | 0 | for (unsigned int csc = 0; csc < _cscSets.size(); ++csc) |
2035 | 0 | { |
2036 | |
|
2037 | 0 | LossyDctEncoderCsc encoder |
2038 | 0 | (_dwaCompressionLevel / 100000.f, |
2039 | 0 | rowPtrs[_cscSets[csc].idx[0]], |
2040 | 0 | rowPtrs[_cscSets[csc].idx[1]], |
2041 | 0 | rowPtrs[_cscSets[csc].idx[2]], |
2042 | 0 | packedAcEnd, |
2043 | 0 | packedDcEnd, |
2044 | 0 | get_dwaCompressorToNonlinear(), |
2045 | 0 | _channelData[_cscSets[csc].idx[0]].width, |
2046 | 0 | _channelData[_cscSets[csc].idx[0]].height, |
2047 | 0 | _channelData[_cscSets[csc].idx[0]].type, |
2048 | 0 | _channelData[_cscSets[csc].idx[1]].type, |
2049 | 0 | _channelData[_cscSets[csc].idx[2]].type); |
2050 | |
|
2051 | 0 | encoder.execute(); |
2052 | |
|
2053 | 0 | *totalAcUncompressedCount += encoder.numAcValuesEncoded(); |
2054 | 0 | *totalDcUncompressedCount += encoder.numDcValuesEncoded(); |
2055 | |
|
2056 | 0 | packedAcEnd += encoder.numAcValuesEncoded() * sizeof(unsigned short); |
2057 | 0 | packedDcEnd += encoder.numDcValuesEncoded() * sizeof(unsigned short); |
2058 | |
|
2059 | 0 | encodedChannels[_cscSets[csc].idx[0]] = true; |
2060 | 0 | encodedChannels[_cscSets[csc].idx[1]] = true; |
2061 | 0 | encodedChannels[_cscSets[csc].idx[2]] = true; |
2062 | 0 | } |
2063 | |
|
2064 | 0 | for (unsigned int chan = 0; chan < _channelData.size(); ++chan) |
2065 | 0 | { |
2066 | 0 | ChannelData *cd = &_channelData[chan]; |
2067 | |
|
2068 | 0 | if (encodedChannels[chan]) |
2069 | 0 | continue; |
2070 | | |
2071 | 0 | switch (cd->compression) |
2072 | 0 | { |
2073 | 0 | case LOSSY_DCT: |
2074 | | |
2075 | | // |
2076 | | // For LOSSY_DCT, treat this just like the CSC'd case, |
2077 | | // but only operate on one channel |
2078 | | // |
2079 | |
|
2080 | 0 | { |
2081 | 0 | const unsigned short *nonlinearLut = 0; |
2082 | |
|
2083 | 0 | if (!cd->pLinear) |
2084 | 0 | nonlinearLut = get_dwaCompressorToNonlinear(); |
2085 | |
|
2086 | 0 | LossyDctEncoder encoder |
2087 | 0 | (_dwaCompressionLevel / 100000.f, |
2088 | 0 | rowPtrs[chan], |
2089 | 0 | packedAcEnd, |
2090 | 0 | packedDcEnd, |
2091 | 0 | nonlinearLut, |
2092 | 0 | cd->width, |
2093 | 0 | cd->height, |
2094 | 0 | cd->type); |
2095 | |
|
2096 | 0 | encoder.execute(); |
2097 | |
|
2098 | 0 | *totalAcUncompressedCount += encoder.numAcValuesEncoded(); |
2099 | 0 | *totalDcUncompressedCount += encoder.numDcValuesEncoded(); |
2100 | |
|
2101 | 0 | packedAcEnd += |
2102 | 0 | encoder.numAcValuesEncoded() * sizeof (unsigned short); |
2103 | |
|
2104 | 0 | packedDcEnd += |
2105 | 0 | encoder.numDcValuesEncoded() * sizeof (unsigned short); |
2106 | 0 | } |
2107 | |
|
2108 | 0 | break; |
2109 | | |
2110 | 0 | case RLE: |
2111 | | |
2112 | | // |
2113 | | // For RLE, bash the bytes up so that the first bytes of each |
2114 | | // pixel are contingous, as are the second bytes, and so on. |
2115 | | // |
2116 | |
|
2117 | 0 | for (unsigned int y = 0; y < rowPtrs[chan].size(); ++y) |
2118 | 0 | { |
2119 | 0 | const char *row = rowPtrs[chan][y]; |
2120 | |
|
2121 | 0 | for (int x = 0; x < cd->width; ++x) |
2122 | 0 | { |
2123 | 0 | for (int byte = 0; |
2124 | 0 | byte < OPENEXR_IMF_NAMESPACE::pixelTypeSize (cd->type); |
2125 | 0 | ++byte) |
2126 | 0 | { |
2127 | | |
2128 | 0 | *cd->planarUncRleEnd[byte]++ = *row++; |
2129 | 0 | } |
2130 | 0 | } |
2131 | |
|
2132 | 0 | *rleRawSize += cd->width * OPENEXR_IMF_NAMESPACE::pixelTypeSize(cd->type); |
2133 | 0 | } |
2134 | |
|
2135 | 0 | break; |
2136 | | |
2137 | 0 | case UNKNOWN: |
2138 | | |
2139 | | // |
2140 | | // Otherwise, just copy data over verbatim |
2141 | | // |
2142 | |
|
2143 | 0 | { |
2144 | 0 | int scanlineSize = cd->width * OPENEXR_IMF_NAMESPACE::pixelTypeSize(cd->type); |
2145 | |
|
2146 | 0 | for (unsigned int y = 0; y < rowPtrs[chan].size(); ++y) |
2147 | 0 | { |
2148 | 0 | memcpy (cd->planarUncBufferEnd, |
2149 | 0 | rowPtrs[chan][y], |
2150 | 0 | scanlineSize); |
2151 | | |
2152 | 0 | cd->planarUncBufferEnd += scanlineSize; |
2153 | 0 | } |
2154 | |
|
2155 | 0 | *unknownUncompressedSize += cd->planarUncSize; |
2156 | 0 | } |
2157 | |
|
2158 | 0 | break; |
2159 | | |
2160 | 0 | default: |
2161 | |
|
2162 | 0 | assert (false); |
2163 | 0 | } |
2164 | | |
2165 | 0 | encodedChannels[chan] = true; |
2166 | 0 | } |
2167 | | |
2168 | | // |
2169 | | // Pack the Unknown data into the output buffer first. Instead of |
2170 | | // just copying it uncompressed, try zlib compression at least. |
2171 | | // |
2172 | | |
2173 | 0 | if (*unknownUncompressedSize > 0) |
2174 | 0 | { |
2175 | 0 | uLongf inSize = (uLongf)(*unknownUncompressedSize); |
2176 | 0 | uLongf outSize = compressBound (inSize); |
2177 | |
|
2178 | 0 | if (Z_OK != ::compress2 ((Bytef *)outDataPtr, |
2179 | 0 | &outSize, |
2180 | 0 | (const Bytef *)_planarUncBuffer[UNKNOWN], |
2181 | 0 | inSize, |
2182 | 0 | 9)) |
2183 | 0 | { |
2184 | 0 | throw IEX_NAMESPACE::BaseExc ("Data compression (zlib) failed."); |
2185 | 0 | } |
2186 | | |
2187 | 0 | outDataPtr += outSize; |
2188 | 0 | *unknownCompressedSize = outSize; |
2189 | 0 | } |
2190 | | |
2191 | | // |
2192 | | // Now, pack all the Lossy DCT coefficients into our output |
2193 | | // buffer, with Huffman encoding. |
2194 | | // |
2195 | | // Also, record the compressed size and the number of |
2196 | | // uncompressed componentns we have. |
2197 | | // |
2198 | | |
2199 | 0 | if (*totalAcUncompressedCount > 0) |
2200 | 0 | { |
2201 | 0 | switch (_acCompression) |
2202 | 0 | { |
2203 | 0 | case STATIC_HUFFMAN: |
2204 | |
|
2205 | 0 | *acCompressedSize = (int) |
2206 | 0 | hufCompress((unsigned short *)_packedAcBuffer, |
2207 | 0 | (int)*totalAcUncompressedCount, |
2208 | 0 | outDataPtr); |
2209 | 0 | break; |
2210 | | |
2211 | 0 | case DEFLATE: |
2212 | |
|
2213 | 0 | { |
2214 | 0 | uLongf destLen = compressBound ( |
2215 | 0 | (*totalAcUncompressedCount) * sizeof (unsigned short)); |
2216 | |
|
2217 | 0 | if (Z_OK != ::compress2 |
2218 | 0 | ((Bytef *)outDataPtr, |
2219 | 0 | &destLen, |
2220 | 0 | (Bytef *)_packedAcBuffer, |
2221 | 0 | (uLong)(*totalAcUncompressedCount |
2222 | 0 | * sizeof (unsigned short)), |
2223 | 0 | 9)) |
2224 | 0 | { |
2225 | 0 | throw IEX_NAMESPACE::InputExc ("Data compression (zlib) failed."); |
2226 | 0 | } |
2227 | | |
2228 | 0 | *acCompressedSize = destLen; |
2229 | 0 | } |
2230 | | |
2231 | 0 | break; |
2232 | | |
2233 | 0 | default: |
2234 | | |
2235 | 0 | assert (false); |
2236 | 0 | } |
2237 | | |
2238 | 0 | outDataPtr += *acCompressedSize; |
2239 | 0 | } |
2240 | | |
2241 | | // |
2242 | | // Handle the DC components separately |
2243 | | // |
2244 | | |
2245 | 0 | if (*totalDcUncompressedCount > 0) |
2246 | 0 | { |
2247 | 0 | *dcCompressedSize = _zip->compress |
2248 | 0 | (_packedDcBuffer, |
2249 | 0 | (int)(*totalDcUncompressedCount) * sizeof (unsigned short), |
2250 | 0 | outDataPtr); |
2251 | |
|
2252 | 0 | outDataPtr += *dcCompressedSize; |
2253 | 0 | } |
2254 | | |
2255 | | // |
2256 | | // If we have RLE data, first RLE encode it and set the uncompressed |
2257 | | // size. Then, deflate the results and set the compressed size. |
2258 | | // |
2259 | |
|
2260 | 0 | if (*rleRawSize > 0) |
2261 | 0 | { |
2262 | 0 | *rleUncompressedSize = rleCompress |
2263 | 0 | ((int)(*rleRawSize), |
2264 | 0 | _planarUncBuffer[RLE], |
2265 | 0 | (signed char *)_rleBuffer); |
2266 | |
|
2267 | 0 | uLongf dstLen = compressBound ((uLongf)*rleUncompressedSize); |
2268 | |
|
2269 | 0 | if (Z_OK != ::compress2 |
2270 | 0 | ((Bytef *)outDataPtr, |
2271 | 0 | &dstLen, |
2272 | 0 | (Bytef *)_rleBuffer, |
2273 | 0 | (uLong)(*rleUncompressedSize), |
2274 | 0 | 9)) |
2275 | 0 | { |
2276 | 0 | throw IEX_NAMESPACE::BaseExc ("Error compressing RLE'd data."); |
2277 | 0 | } |
2278 | | |
2279 | 0 | *rleCompressedSize = dstLen; |
2280 | 0 | outDataPtr += *rleCompressedSize; |
2281 | 0 | } |
2282 | | |
2283 | | // |
2284 | | // Flip the counters to XDR format |
2285 | | // |
2286 | | |
2287 | 0 | for (int i = 0; i < NUM_SIZES_SINGLE; ++i) |
2288 | 0 | { |
2289 | 0 | Int64 src = *(((Int64 *)_outBuffer) + i); |
2290 | 0 | char *dst = (char *)(((Int64 *)_outBuffer) + i); |
2291 | |
|
2292 | 0 | Xdr::write<CharPtrIO> (dst, src); |
2293 | 0 | } |
2294 | | |
2295 | | // |
2296 | | // We're done - compute the number of bytes we packed |
2297 | | // |
2298 | |
|
2299 | 0 | outPtr = _outBuffer; |
2300 | |
|
2301 | 0 | return static_cast<int>(outDataPtr - _outBuffer + 1); |
2302 | 0 | } |
2303 | | |
2304 | | |
2305 | | int |
2306 | | DwaCompressor::uncompress |
2307 | | (const char *inPtr, |
2308 | | int inSize, |
2309 | | int minY, |
2310 | | const char *&outPtr) |
2311 | 0 | { |
2312 | 0 | return uncompress (inPtr, |
2313 | 0 | inSize, |
2314 | 0 | IMATH_NAMESPACE::Box2i (IMATH_NAMESPACE::V2i (_min[0], minY), |
2315 | 0 | IMATH_NAMESPACE::V2i (_max[0], minY + numScanLines() - 1)), |
2316 | 0 | outPtr); |
2317 | 0 | } |
2318 | | |
2319 | | |
2320 | | int |
2321 | | DwaCompressor::uncompressTile |
2322 | | (const char *inPtr, |
2323 | | int inSize, |
2324 | | IMATH_NAMESPACE::Box2i range, |
2325 | | const char *&outPtr) |
2326 | 0 | { |
2327 | 0 | return uncompress (inPtr, inSize, range, outPtr); |
2328 | 0 | } |
2329 | | |
2330 | | |
2331 | | int |
2332 | | DwaCompressor::uncompress |
2333 | | (const char *inPtr, |
2334 | | int inSize, |
2335 | | IMATH_NAMESPACE::Box2i range, |
2336 | | const char *&outPtr) |
2337 | 0 | { |
2338 | 0 | int minX = range.min.x; |
2339 | 0 | int maxX = std::min (range.max.x, _max[0]); |
2340 | 0 | int minY = range.min.y; |
2341 | 0 | int maxY = std::min (range.max.y, _max[1]); |
2342 | |
|
2343 | 0 | int headerSize = NUM_SIZES_SINGLE*sizeof(Int64); |
2344 | 0 | if (inSize < headerSize) |
2345 | 0 | { |
2346 | 0 | throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data" |
2347 | 0 | "(truncated header)."); |
2348 | 0 | } |
2349 | | |
2350 | | // |
2351 | | // Flip the counters from XDR to NATIVE |
2352 | | // |
2353 | | |
2354 | 0 | for (int i = 0; i < NUM_SIZES_SINGLE; ++i) |
2355 | 0 | { |
2356 | 0 | Int64 *dst = (((Int64 *)inPtr) + i); |
2357 | 0 | const char *src = (char *)(((Int64 *)inPtr) + i); |
2358 | |
|
2359 | 0 | Xdr::read<CharPtrIO> (src, *dst); |
2360 | 0 | } |
2361 | | |
2362 | | // |
2363 | | // Unwind all the counter info |
2364 | | // |
2365 | |
|
2366 | 0 | const Int64 *inPtr64 = (const Int64*) inPtr; |
2367 | |
|
2368 | 0 | Int64 version = *(inPtr64 + VERSION); |
2369 | 0 | Int64 unknownUncompressedSize = *(inPtr64 + UNKNOWN_UNCOMPRESSED_SIZE); |
2370 | 0 | Int64 unknownCompressedSize = *(inPtr64 + UNKNOWN_COMPRESSED_SIZE); |
2371 | 0 | Int64 acCompressedSize = *(inPtr64 + AC_COMPRESSED_SIZE); |
2372 | 0 | Int64 dcCompressedSize = *(inPtr64 + DC_COMPRESSED_SIZE); |
2373 | 0 | Int64 rleCompressedSize = *(inPtr64 + RLE_COMPRESSED_SIZE); |
2374 | 0 | Int64 rleUncompressedSize = *(inPtr64 + RLE_UNCOMPRESSED_SIZE); |
2375 | 0 | Int64 rleRawSize = *(inPtr64 + RLE_RAW_SIZE); |
2376 | | |
2377 | 0 | Int64 totalAcUncompressedCount = *(inPtr64 + AC_UNCOMPRESSED_COUNT); |
2378 | 0 | Int64 totalDcUncompressedCount = *(inPtr64 + DC_UNCOMPRESSED_COUNT); |
2379 | |
|
2380 | 0 | Int64 acCompression = *(inPtr64 + AC_COMPRESSION); |
2381 | |
|
2382 | 0 | Int64 compressedSize = unknownCompressedSize + |
2383 | 0 | acCompressedSize + |
2384 | 0 | dcCompressedSize + |
2385 | 0 | rleCompressedSize; |
2386 | |
|
2387 | 0 | const char *dataPtr = inPtr + NUM_SIZES_SINGLE * sizeof(Int64); |
2388 | | |
2389 | | /* Both the sum and individual sizes are checked in case of overflow. */ |
2390 | 0 | if (inSize < (headerSize + compressedSize) || |
2391 | 0 | inSize < unknownCompressedSize || |
2392 | 0 | inSize < acCompressedSize || |
2393 | 0 | inSize < dcCompressedSize || |
2394 | 0 | inSize < rleCompressedSize) |
2395 | 0 | { |
2396 | 0 | throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data" |
2397 | 0 | "(truncated file)."); |
2398 | 0 | } |
2399 | | |
2400 | 0 | if ((SInt64)unknownUncompressedSize < 0 || |
2401 | 0 | (SInt64)unknownCompressedSize < 0 || |
2402 | 0 | (SInt64)acCompressedSize < 0 || |
2403 | 0 | (SInt64)dcCompressedSize < 0 || |
2404 | 0 | (SInt64)rleCompressedSize < 0 || |
2405 | 0 | (SInt64)rleUncompressedSize < 0 || |
2406 | 0 | (SInt64)rleRawSize < 0 || |
2407 | 0 | (SInt64)totalAcUncompressedCount < 0 || |
2408 | 0 | (SInt64)totalDcUncompressedCount < 0) |
2409 | 0 | { |
2410 | 0 | throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data" |
2411 | 0 | " (corrupt header)."); |
2412 | 0 | } |
2413 | | |
2414 | 0 | if (version < 2) |
2415 | 0 | initializeLegacyChannelRules(); |
2416 | 0 | else |
2417 | 0 | { |
2418 | 0 | unsigned short ruleSize = 0; |
2419 | 0 | Xdr::read<CharPtrIO>(dataPtr, ruleSize); |
2420 | |
|
2421 | 0 | if (ruleSize < 0) |
2422 | 0 | throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data" |
2423 | 0 | " (corrupt header file)."); |
2424 | | |
2425 | 0 | headerSize += ruleSize; |
2426 | 0 | if (inSize < headerSize + compressedSize) |
2427 | 0 | throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data" |
2428 | 0 | " (truncated file)."); |
2429 | | |
2430 | 0 | _channelRules.clear(); |
2431 | 0 | ruleSize -= Xdr::size<unsigned short> (); |
2432 | 0 | while (ruleSize > 0) |
2433 | 0 | { |
2434 | 0 | Classifier rule(dataPtr, ruleSize); |
2435 | | |
2436 | 0 | _channelRules.push_back(rule); |
2437 | 0 | ruleSize -= rule.size(); |
2438 | 0 | } |
2439 | 0 | } |
2440 | | |
2441 | | |
2442 | 0 | size_t outBufferSize = 0; |
2443 | 0 | initializeBuffers(outBufferSize); |
2444 | | |
2445 | | // |
2446 | | // Allocate _outBuffer, if we haven't done so already |
2447 | | // |
2448 | |
|
2449 | 0 | if (_maxScanLineSize * numScanLines() > _outBufferSize) |
2450 | 0 | { |
2451 | 0 | _outBufferSize = _maxScanLineSize * numScanLines(); |
2452 | 0 | if (_outBuffer != 0) |
2453 | 0 | delete[] _outBuffer; |
2454 | 0 | _outBuffer = new char[_maxScanLineSize * numScanLines()]; |
2455 | 0 | } |
2456 | | |
2457 | |
|
2458 | 0 | char *outBufferEnd = _outBuffer; |
2459 | | |
2460 | | |
2461 | | // |
2462 | | // Find the start of the RLE packed AC components and |
2463 | | // the DC components for each channel. This will be handy |
2464 | | // if you want to decode the channels in parallel later on. |
2465 | | // |
2466 | |
|
2467 | 0 | char *packedAcBufferEnd = 0; |
2468 | |
|
2469 | 0 | if (_packedAcBuffer) |
2470 | 0 | packedAcBufferEnd = _packedAcBuffer; |
2471 | |
|
2472 | 0 | char *packedDcBufferEnd = 0; |
2473 | |
|
2474 | 0 | if (_packedDcBuffer) |
2475 | 0 | packedDcBufferEnd = _packedDcBuffer; |
2476 | | |
2477 | | // |
2478 | | // UNKNOWN data is packed first, followed by the |
2479 | | // Huffman-compressed AC, then the DC values, |
2480 | | // and then the zlib compressed RLE data. |
2481 | | // |
2482 | | |
2483 | 0 | const char *compressedUnknownBuf = dataPtr; |
2484 | |
|
2485 | 0 | const char *compressedAcBuf = compressedUnknownBuf + |
2486 | 0 | static_cast<ptrdiff_t>(unknownCompressedSize); |
2487 | 0 | const char *compressedDcBuf = compressedAcBuf + |
2488 | 0 | static_cast<ptrdiff_t>(acCompressedSize); |
2489 | 0 | const char *compressedRleBuf = compressedDcBuf + |
2490 | 0 | static_cast<ptrdiff_t>(dcCompressedSize); |
2491 | | |
2492 | | // |
2493 | | // Sanity check that the version is something we expect. Right now, |
2494 | | // we can decode version 0, 1, and 2. v1 adds 'end of block' symbols |
2495 | | // to the AC RLE. v2 adds channel classification rules at the |
2496 | | // start of the data block. |
2497 | | // |
2498 | |
|
2499 | 0 | if (version > 2) |
2500 | 0 | throw IEX_NAMESPACE::InputExc ("Invalid version of compressed data block"); |
2501 | | |
2502 | 0 | setupChannelData(minX, minY, maxX, maxY); |
2503 | | |
2504 | | // |
2505 | | // Uncompress the UNKNOWN data into _planarUncBuffer[UNKNOWN] |
2506 | | // |
2507 | |
|
2508 | 0 | if (unknownCompressedSize > 0) |
2509 | 0 | { |
2510 | 0 | if (unknownUncompressedSize > _planarUncBufferSize[UNKNOWN]) |
2511 | 0 | { |
2512 | 0 | throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data" |
2513 | 0 | "(corrupt header)."); |
2514 | 0 | } |
2515 | | |
2516 | 0 | uLongf outSize = (uLongf)unknownUncompressedSize; |
2517 | |
|
2518 | 0 | if (Z_OK != ::uncompress |
2519 | 0 | ((Bytef *)_planarUncBuffer[UNKNOWN], |
2520 | 0 | &outSize, |
2521 | 0 | (Bytef *)compressedUnknownBuf, |
2522 | 0 | (uLong)unknownCompressedSize)) |
2523 | 0 | { |
2524 | 0 | throw IEX_NAMESPACE::BaseExc("Error uncompressing UNKNOWN data."); |
2525 | 0 | } |
2526 | 0 | } |
2527 | | |
2528 | | // |
2529 | | // Uncompress the AC data into _packedAcBuffer |
2530 | | // |
2531 | | |
2532 | 0 | if (acCompressedSize > 0) |
2533 | 0 | { |
2534 | 0 | if (totalAcUncompressedCount*sizeof(unsigned short) > _packedAcBufferSize) |
2535 | 0 | { |
2536 | 0 | throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data" |
2537 | 0 | "(corrupt header)."); |
2538 | 0 | } |
2539 | | |
2540 | | // |
2541 | | // Don't trust the user to get it right, look in the file. |
2542 | | // |
2543 | | |
2544 | 0 | switch (acCompression) |
2545 | 0 | { |
2546 | 0 | case STATIC_HUFFMAN: |
2547 | |
|
2548 | 0 | hufUncompress |
2549 | 0 | (compressedAcBuf, |
2550 | 0 | (int)acCompressedSize, |
2551 | 0 | (unsigned short *)_packedAcBuffer, |
2552 | 0 | (int)totalAcUncompressedCount); |
2553 | |
|
2554 | 0 | break; |
2555 | | |
2556 | 0 | case DEFLATE: |
2557 | 0 | { |
2558 | 0 | uLongf destLen = |
2559 | 0 | (int)(totalAcUncompressedCount) * sizeof (unsigned short); |
2560 | |
|
2561 | 0 | if (Z_OK != ::uncompress |
2562 | 0 | ((Bytef *)_packedAcBuffer, |
2563 | 0 | &destLen, |
2564 | 0 | (Bytef *)compressedAcBuf, |
2565 | 0 | (uLong)acCompressedSize)) |
2566 | 0 | { |
2567 | 0 | throw IEX_NAMESPACE::InputExc ("Data decompression (zlib) failed."); |
2568 | 0 | } |
2569 | | |
2570 | 0 | if (totalAcUncompressedCount * sizeof (unsigned short) != |
2571 | 0 | destLen) |
2572 | 0 | { |
2573 | 0 | throw IEX_NAMESPACE::InputExc ("AC data corrupt."); |
2574 | 0 | } |
2575 | 0 | } |
2576 | 0 | break; |
2577 | | |
2578 | 0 | default: |
2579 | |
|
2580 | 0 | throw IEX_NAMESPACE::NoImplExc ("Unknown AC Compression"); |
2581 | 0 | break; |
2582 | 0 | } |
2583 | 0 | } |
2584 | | |
2585 | | // |
2586 | | // Uncompress the DC data into _packedDcBuffer |
2587 | | // |
2588 | | |
2589 | 0 | if (dcCompressedSize > 0) |
2590 | 0 | { |
2591 | 0 | if (totalDcUncompressedCount*sizeof(unsigned short) > _packedDcBufferSize) |
2592 | 0 | { |
2593 | 0 | throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data" |
2594 | 0 | "(corrupt header)."); |
2595 | 0 | } |
2596 | | |
2597 | 0 | if (_zip->uncompress |
2598 | 0 | (compressedDcBuf, (int)dcCompressedSize, _packedDcBuffer) |
2599 | 0 | != (int)totalDcUncompressedCount * sizeof (unsigned short)) |
2600 | 0 | { |
2601 | 0 | throw IEX_NAMESPACE::BaseExc("DC data corrupt."); |
2602 | 0 | } |
2603 | 0 | } |
2604 | | |
2605 | | // |
2606 | | // Uncompress the RLE data into _rleBuffer, then unRLE the results |
2607 | | // into _planarUncBuffer[RLE] |
2608 | | // |
2609 | | |
2610 | 0 | if (rleRawSize > 0) |
2611 | 0 | { |
2612 | 0 | if (rleUncompressedSize > _rleBufferSize || |
2613 | 0 | rleRawSize > _planarUncBufferSize[RLE]) |
2614 | 0 | { |
2615 | 0 | throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data" |
2616 | 0 | "(corrupt header)."); |
2617 | 0 | } |
2618 | | |
2619 | 0 | uLongf dstLen = (uLongf)rleUncompressedSize; |
2620 | |
|
2621 | 0 | if (Z_OK != ::uncompress |
2622 | 0 | ((Bytef *)_rleBuffer, |
2623 | 0 | &dstLen, |
2624 | 0 | (Bytef *)compressedRleBuf, |
2625 | 0 | (uLong)rleCompressedSize)) |
2626 | 0 | { |
2627 | 0 | throw IEX_NAMESPACE::BaseExc("Error uncompressing RLE data."); |
2628 | 0 | } |
2629 | | |
2630 | 0 | if (dstLen != rleUncompressedSize) |
2631 | 0 | throw IEX_NAMESPACE::BaseExc("RLE data corrupted"); |
2632 | | |
2633 | 0 | if (rleUncompress |
2634 | 0 | ((int)rleUncompressedSize, |
2635 | 0 | (int)rleRawSize, |
2636 | 0 | (signed char *)_rleBuffer, |
2637 | 0 | _planarUncBuffer[RLE]) != rleRawSize) |
2638 | 0 | { |
2639 | 0 | throw IEX_NAMESPACE::BaseExc("RLE data corrupted"); |
2640 | 0 | } |
2641 | 0 | } |
2642 | | |
2643 | | // |
2644 | | // Determine the start of each row in the output buffer |
2645 | | // |
2646 | | |
2647 | 0 | std::vector<bool> decodedChannels (_channelData.size()); |
2648 | 0 | std::vector< std::vector<char *> > rowPtrs (_channelData.size()); |
2649 | |
|
2650 | 0 | for (unsigned int chan = 0; chan < _channelData.size(); ++chan) |
2651 | 0 | decodedChannels[chan] = false; |
2652 | |
|
2653 | 0 | outBufferEnd = _outBuffer; |
2654 | |
|
2655 | 0 | for (int y = minY; y <= maxY; ++y) |
2656 | 0 | { |
2657 | 0 | for (unsigned int chan = 0; chan < _channelData.size(); ++chan) |
2658 | 0 | { |
2659 | 0 | ChannelData *cd = &_channelData[chan]; |
2660 | |
|
2661 | 0 | if (IMATH_NAMESPACE::modp (y, cd->ySampling) != 0) |
2662 | 0 | continue; |
2663 | | |
2664 | 0 | rowPtrs[chan].push_back (outBufferEnd); |
2665 | 0 | outBufferEnd += cd->width * OPENEXR_IMF_NAMESPACE::pixelTypeSize (cd->type); |
2666 | 0 | } |
2667 | 0 | } |
2668 | | |
2669 | | // |
2670 | | // Setup to decode each block of 3 channels that need to |
2671 | | // be handled together |
2672 | | // |
2673 | |
|
2674 | 0 | for (unsigned int csc = 0; csc < _cscSets.size(); ++csc) |
2675 | 0 | { |
2676 | 0 | int rChan = _cscSets[csc].idx[0]; |
2677 | 0 | int gChan = _cscSets[csc].idx[1]; |
2678 | 0 | int bChan = _cscSets[csc].idx[2]; |
2679 | | |
2680 | |
|
2681 | 0 | LossyDctDecoderCsc decoder |
2682 | 0 | (rowPtrs[rChan], |
2683 | 0 | rowPtrs[gChan], |
2684 | 0 | rowPtrs[bChan], |
2685 | 0 | packedAcBufferEnd, |
2686 | 0 | packedDcBufferEnd, |
2687 | 0 | get_dwaCompressorToLinear(), |
2688 | 0 | _channelData[rChan].width, |
2689 | 0 | _channelData[rChan].height, |
2690 | 0 | _channelData[rChan].type, |
2691 | 0 | _channelData[gChan].type, |
2692 | 0 | _channelData[bChan].type); |
2693 | |
|
2694 | 0 | decoder.execute(); |
2695 | |
|
2696 | 0 | packedAcBufferEnd += |
2697 | 0 | decoder.numAcValuesEncoded() * sizeof (unsigned short); |
2698 | |
|
2699 | 0 | packedDcBufferEnd += |
2700 | 0 | decoder.numDcValuesEncoded() * sizeof (unsigned short); |
2701 | |
|
2702 | 0 | decodedChannels[rChan] = true; |
2703 | 0 | decodedChannels[gChan] = true; |
2704 | 0 | decodedChannels[bChan] = true; |
2705 | 0 | } |
2706 | | |
2707 | | // |
2708 | | // Setup to handle the remaining channels by themselves |
2709 | | // |
2710 | |
|
2711 | 0 | for (unsigned int chan = 0; chan < _channelData.size(); ++chan) |
2712 | 0 | { |
2713 | 0 | if (decodedChannels[chan]) |
2714 | 0 | continue; |
2715 | | |
2716 | 0 | ChannelData *cd = &_channelData[chan]; |
2717 | 0 | int pixelSize = OPENEXR_IMF_NAMESPACE::pixelTypeSize (cd->type); |
2718 | |
|
2719 | 0 | switch (cd->compression) |
2720 | 0 | { |
2721 | 0 | case LOSSY_DCT: |
2722 | | |
2723 | | // |
2724 | | // Setup a single-channel lossy DCT decoder pointing |
2725 | | // at the output buffer |
2726 | | // |
2727 | |
|
2728 | 0 | { |
2729 | 0 | const unsigned short *linearLut = 0; |
2730 | |
|
2731 | 0 | if (!cd->pLinear) |
2732 | 0 | linearLut = get_dwaCompressorToLinear(); |
2733 | |
|
2734 | 0 | LossyDctDecoder decoder |
2735 | 0 | (rowPtrs[chan], |
2736 | 0 | packedAcBufferEnd, |
2737 | 0 | packedDcBufferEnd, |
2738 | 0 | linearLut, |
2739 | 0 | cd->width, |
2740 | 0 | cd->height, |
2741 | 0 | cd->type); |
2742 | |
|
2743 | 0 | decoder.execute(); |
2744 | |
|
2745 | 0 | packedAcBufferEnd += |
2746 | 0 | decoder.numAcValuesEncoded() * sizeof (unsigned short); |
2747 | |
|
2748 | 0 | packedDcBufferEnd += |
2749 | 0 | decoder.numDcValuesEncoded() * sizeof (unsigned short); |
2750 | 0 | } |
2751 | |
|
2752 | 0 | break; |
2753 | | |
2754 | 0 | case RLE: |
2755 | | |
2756 | | // |
2757 | | // For the RLE case, the data has been un-RLE'd into |
2758 | | // planarUncRleEnd[], but is still split out by bytes. |
2759 | | // We need to rearrange the bytes back into the correct |
2760 | | // order in the output buffer; |
2761 | | // |
2762 | |
|
2763 | 0 | { |
2764 | 0 | int row = 0; |
2765 | |
|
2766 | 0 | for (int y = minY; y <= maxY; ++y) |
2767 | 0 | { |
2768 | 0 | if (IMATH_NAMESPACE::modp (y, cd->ySampling) != 0) |
2769 | 0 | continue; |
2770 | | |
2771 | 0 | char *dst = rowPtrs[chan][row]; |
2772 | |
|
2773 | 0 | if (pixelSize == 2) |
2774 | 0 | { |
2775 | 0 | interleaveByte2 (dst, |
2776 | 0 | cd->planarUncRleEnd[0], |
2777 | 0 | cd->planarUncRleEnd[1], |
2778 | 0 | cd->width); |
2779 | | |
2780 | 0 | cd->planarUncRleEnd[0] += cd->width; |
2781 | 0 | cd->planarUncRleEnd[1] += cd->width; |
2782 | 0 | } |
2783 | 0 | else |
2784 | 0 | { |
2785 | 0 | for (int x = 0; x < cd->width; ++x) |
2786 | 0 | { |
2787 | 0 | for (int byte = 0; byte < pixelSize; ++byte) |
2788 | 0 | { |
2789 | 0 | *dst++ = *cd->planarUncRleEnd[byte]++; |
2790 | 0 | } |
2791 | 0 | } |
2792 | 0 | } |
2793 | |
|
2794 | 0 | row++; |
2795 | 0 | } |
2796 | 0 | } |
2797 | |
|
2798 | 0 | break; |
2799 | | |
2800 | 0 | case UNKNOWN: |
2801 | | |
2802 | | // |
2803 | | // In the UNKNOWN case, data is already in planarUncBufferEnd |
2804 | | // and just needs to copied over to the output buffer |
2805 | | // |
2806 | |
|
2807 | 0 | { |
2808 | 0 | int row = 0; |
2809 | 0 | int dstScanlineSize = cd->width * OPENEXR_IMF_NAMESPACE::pixelTypeSize (cd->type); |
2810 | |
|
2811 | 0 | for (int y = minY; y <= maxY; ++y) |
2812 | 0 | { |
2813 | 0 | if (IMATH_NAMESPACE::modp (y, cd->ySampling) != 0) |
2814 | 0 | continue; |
2815 | | |
2816 | 0 | memcpy (rowPtrs[chan][row], |
2817 | 0 | cd->planarUncBufferEnd, |
2818 | 0 | dstScanlineSize); |
2819 | |
|
2820 | 0 | cd->planarUncBufferEnd += dstScanlineSize; |
2821 | 0 | row++; |
2822 | 0 | } |
2823 | 0 | } |
2824 | |
|
2825 | 0 | break; |
2826 | | |
2827 | 0 | default: |
2828 | |
|
2829 | 0 | throw IEX_NAMESPACE::NoImplExc ("Unhandled compression scheme case"); |
2830 | 0 | break; |
2831 | 0 | } |
2832 | | |
2833 | 0 | decodedChannels[chan] = true; |
2834 | 0 | } |
2835 | | |
2836 | | // |
2837 | | // Return a ptr to _outBuffer |
2838 | | // |
2839 | | |
2840 | 0 | outPtr = _outBuffer; |
2841 | 0 | return (int)(outBufferEnd - _outBuffer); |
2842 | 0 | } |
2843 | | |
2844 | | |
2845 | | // static |
2846 | | void |
2847 | | DwaCompressor::initializeFuncs() |
2848 | 0 | { |
2849 | 0 | convertFloatToHalf64 = convertFloatToHalf64_scalar; |
2850 | 0 | fromHalfZigZag = fromHalfZigZag_scalar; |
2851 | |
|
2852 | 0 | CpuId cpuId; |
2853 | | |
2854 | | // |
2855 | | // Setup HALF <-> FLOAT conversion implementations |
2856 | | // |
2857 | |
|
2858 | 0 | if (cpuId.avx && cpuId.f16c) |
2859 | 0 | { |
2860 | 0 | convertFloatToHalf64 = convertFloatToHalf64_f16c; |
2861 | 0 | fromHalfZigZag = fromHalfZigZag_f16c; |
2862 | 0 | } |
2863 | | |
2864 | | // |
2865 | | // Setup inverse DCT implementations |
2866 | | // |
2867 | |
|
2868 | 0 | dctInverse8x8_0 = dctInverse8x8_scalar<0>; |
2869 | 0 | dctInverse8x8_1 = dctInverse8x8_scalar<1>; |
2870 | 0 | dctInverse8x8_2 = dctInverse8x8_scalar<2>; |
2871 | 0 | dctInverse8x8_3 = dctInverse8x8_scalar<3>; |
2872 | 0 | dctInverse8x8_4 = dctInverse8x8_scalar<4>; |
2873 | 0 | dctInverse8x8_5 = dctInverse8x8_scalar<5>; |
2874 | 0 | dctInverse8x8_6 = dctInverse8x8_scalar<6>; |
2875 | 0 | dctInverse8x8_7 = dctInverse8x8_scalar<7>; |
2876 | |
|
2877 | 0 | if (cpuId.avx) |
2878 | 0 | { |
2879 | 0 | dctInverse8x8_0 = dctInverse8x8_avx<0>; |
2880 | 0 | dctInverse8x8_1 = dctInverse8x8_avx<1>; |
2881 | 0 | dctInverse8x8_2 = dctInverse8x8_avx<2>; |
2882 | 0 | dctInverse8x8_3 = dctInverse8x8_avx<3>; |
2883 | 0 | dctInverse8x8_4 = dctInverse8x8_avx<4>; |
2884 | 0 | dctInverse8x8_5 = dctInverse8x8_avx<5>; |
2885 | 0 | dctInverse8x8_6 = dctInverse8x8_avx<6>; |
2886 | 0 | dctInverse8x8_7 = dctInverse8x8_avx<7>; |
2887 | 0 | } |
2888 | 0 | else if (cpuId.sse2) |
2889 | 0 | { |
2890 | 0 | dctInverse8x8_0 = dctInverse8x8_sse2<0>; |
2891 | 0 | dctInverse8x8_1 = dctInverse8x8_sse2<1>; |
2892 | 0 | dctInverse8x8_2 = dctInverse8x8_sse2<2>; |
2893 | 0 | dctInverse8x8_3 = dctInverse8x8_sse2<3>; |
2894 | 0 | dctInverse8x8_4 = dctInverse8x8_sse2<4>; |
2895 | 0 | dctInverse8x8_5 = dctInverse8x8_sse2<5>; |
2896 | 0 | dctInverse8x8_6 = dctInverse8x8_sse2<6>; |
2897 | 0 | dctInverse8x8_7 = dctInverse8x8_sse2<7>; |
2898 | 0 | } |
2899 | 0 | } |
2900 | | |
2901 | | |
2902 | | // |
2903 | | // Handle channel classification and buffer allocation once we know |
2904 | | // how to classify channels |
2905 | | // |
2906 | | |
2907 | | void |
2908 | | DwaCompressor::initializeBuffers (size_t &outBufferSize) |
2909 | 0 | { |
2910 | 0 | classifyChannels (_channels, _channelData, _cscSets); |
2911 | | |
2912 | | // |
2913 | | // _outBuffer needs to be big enough to hold all our |
2914 | | // compressed data - which could vary depending on what sort |
2915 | | // of channels we have. |
2916 | | // |
2917 | |
|
2918 | 0 | int maxOutBufferSize = 0; |
2919 | 0 | int numLossyDctChans = 0; |
2920 | 0 | int unknownBufferSize = 0; |
2921 | 0 | int rleBufferSize = 0; |
2922 | |
|
2923 | 0 | int maxLossyDctAcSize = (int)ceil ((float)numScanLines() / 8.0f) * |
2924 | 0 | (int)ceil ((float)(_max[0] - _min[0] + 1) / 8.0f) * |
2925 | 0 | 63 * sizeof (unsigned short); |
2926 | |
|
2927 | 0 | int maxLossyDctDcSize = (int)ceil ((float)numScanLines() / 8.0f) * |
2928 | 0 | (int)ceil ((float)(_max[0] - _min[0] + 1) / 8.0f) * |
2929 | 0 | sizeof (unsigned short); |
2930 | |
|
2931 | 0 | for (unsigned int chan = 0; chan < _channelData.size(); ++chan) |
2932 | 0 | { |
2933 | 0 | switch (_channelData[chan].compression) |
2934 | 0 | { |
2935 | 0 | case LOSSY_DCT: |
2936 | | |
2937 | | // |
2938 | | // This is the size of the number of packed |
2939 | | // components, plus the requirements for |
2940 | | // maximum Huffman encoding size (for STATIC_HUFFMAN) |
2941 | | // or for zlib compression (for DEFLATE) |
2942 | | // |
2943 | |
|
2944 | 0 | maxOutBufferSize += std::max( |
2945 | 0 | (int)(2 * maxLossyDctAcSize + 65536), |
2946 | 0 | (int)compressBound (maxLossyDctAcSize) ); |
2947 | 0 | numLossyDctChans++; |
2948 | 0 | break; |
2949 | | |
2950 | 0 | case RLE: |
2951 | 0 | { |
2952 | | // |
2953 | | // RLE, if gone horribly wrong, could double the size |
2954 | | // of the source data. |
2955 | | // |
2956 | |
|
2957 | 0 | int rleAmount = 2 * numScanLines() * (_max[0] - _min[0] + 1) * |
2958 | 0 | OPENEXR_IMF_NAMESPACE::pixelTypeSize (_channelData[chan].type); |
2959 | |
|
2960 | 0 | rleBufferSize += rleAmount; |
2961 | 0 | } |
2962 | 0 | break; |
2963 | | |
2964 | | |
2965 | 0 | case UNKNOWN: |
2966 | |
|
2967 | 0 | unknownBufferSize += numScanLines() * (_max[0] - _min[0] + 1) * |
2968 | 0 | OPENEXR_IMF_NAMESPACE::pixelTypeSize (_channelData[chan].type); |
2969 | 0 | break; |
2970 | | |
2971 | 0 | default: |
2972 | |
|
2973 | 0 | throw IEX_NAMESPACE::NoImplExc ("Unhandled compression scheme case"); |
2974 | 0 | break; |
2975 | 0 | } |
2976 | 0 | } |
2977 | | |
2978 | | // |
2979 | | // Also, since the results of the RLE are packed into |
2980 | | // the output buffer, we need the extra room there. But |
2981 | | // we're going to zlib compress() the data we pack, |
2982 | | // which could take slightly more space |
2983 | | // |
2984 | | |
2985 | 0 | maxOutBufferSize += (int)compressBound ((uLongf)rleBufferSize); |
2986 | | |
2987 | | // |
2988 | | // And the same goes for the UNKNOWN data |
2989 | | // |
2990 | |
|
2991 | 0 | maxOutBufferSize += (int)compressBound ((uLongf)unknownBufferSize); |
2992 | | |
2993 | | // |
2994 | | // Allocate a zip/deflate compressor big enought to hold the DC data |
2995 | | // and include it's compressed results in the size requirements |
2996 | | // for our output buffer |
2997 | | // |
2998 | |
|
2999 | 0 | if (_zip == 0) |
3000 | 0 | _zip = new Zip (maxLossyDctDcSize * numLossyDctChans); |
3001 | 0 | else if (_zip->maxRawSize() < maxLossyDctDcSize * numLossyDctChans) |
3002 | 0 | { |
3003 | 0 | delete _zip; |
3004 | 0 | _zip = new Zip (maxLossyDctDcSize * numLossyDctChans); |
3005 | 0 | } |
3006 | | |
3007 | |
|
3008 | 0 | maxOutBufferSize += _zip->maxCompressedSize(); |
3009 | | |
3010 | | // |
3011 | | // We also need to reserve space at the head of the buffer to |
3012 | | // write out the size of our various packed and compressed data. |
3013 | | // |
3014 | |
|
3015 | 0 | maxOutBufferSize += NUM_SIZES_SINGLE * sizeof (Int64); |
3016 | | |
3017 | | |
3018 | | // |
3019 | | // Later, we're going to hijack outBuffer for the result of |
3020 | | // both encoding and decoding. So it needs to be big enough |
3021 | | // to hold either a buffers' worth of uncompressed or |
3022 | | // compressed data |
3023 | | // |
3024 | | // For encoding, we'll need _outBuffer to hold maxOutBufferSize bytes, |
3025 | | // but for decoding, we only need it to be maxScanLineSize*numScanLines. |
3026 | | // Cache the max size for now, and alloc the buffer when we either |
3027 | | // encode or decode. |
3028 | | // |
3029 | |
|
3030 | 0 | outBufferSize = maxOutBufferSize; |
3031 | | |
3032 | | |
3033 | | // |
3034 | | // _packedAcBuffer holds the quantized DCT coefficients prior |
3035 | | // to Huffman encoding |
3036 | | // |
3037 | |
|
3038 | 0 | if (maxLossyDctAcSize * numLossyDctChans > _packedAcBufferSize) |
3039 | 0 | { |
3040 | 0 | _packedAcBufferSize = maxLossyDctAcSize * numLossyDctChans; |
3041 | 0 | if (_packedAcBuffer != 0) |
3042 | 0 | delete[] _packedAcBuffer; |
3043 | 0 | _packedAcBuffer = new char[_packedAcBufferSize]; |
3044 | 0 | } |
3045 | | |
3046 | | // |
3047 | | // _packedDcBuffer holds one quantized DCT coef per 8x8 block |
3048 | | // |
3049 | |
|
3050 | 0 | if (maxLossyDctDcSize * numLossyDctChans > _packedDcBufferSize) |
3051 | 0 | { |
3052 | 0 | _packedDcBufferSize = maxLossyDctDcSize * numLossyDctChans; |
3053 | 0 | if (_packedDcBuffer != 0) |
3054 | 0 | delete[] _packedDcBuffer; |
3055 | 0 | _packedDcBuffer = new char[_packedDcBufferSize]; |
3056 | 0 | } |
3057 | |
|
3058 | 0 | if (rleBufferSize > _rleBufferSize) |
3059 | 0 | { |
3060 | 0 | _rleBufferSize = rleBufferSize; |
3061 | 0 | if (_rleBuffer != 0) |
3062 | 0 | delete[] _rleBuffer; |
3063 | 0 | _rleBuffer = new char[rleBufferSize]; |
3064 | 0 | } |
3065 | | |
3066 | | // |
3067 | | // The planar uncompressed buffer will hold float data for LOSSY_DCT |
3068 | | // compressed values, and whatever the native type is for other |
3069 | | // channels. We're going to use this to hold data in a planar |
3070 | | // format, as opposed to the native interleaved format we take |
3071 | | // into compress() and give back from uncompress(). |
3072 | | // |
3073 | | // This also makes it easier to compress the UNKNOWN and RLE data |
3074 | | // all in one swoop (for each compression scheme). |
3075 | | // |
3076 | |
|
3077 | 0 | int planarUncBufferSize[NUM_COMPRESSOR_SCHEMES]; |
3078 | 0 | for (int i=0; i<NUM_COMPRESSOR_SCHEMES; ++i) |
3079 | 0 | planarUncBufferSize[i] = 0; |
3080 | |
|
3081 | 0 | for (unsigned int chan = 0; chan < _channelData.size(); ++chan) |
3082 | 0 | { |
3083 | 0 | switch (_channelData[chan].compression) |
3084 | 0 | { |
3085 | 0 | case LOSSY_DCT: |
3086 | 0 | break; |
3087 | | |
3088 | 0 | case RLE: |
3089 | 0 | planarUncBufferSize[RLE] += |
3090 | 0 | numScanLines() * (_max[0] - _min[0] + 1) * |
3091 | 0 | OPENEXR_IMF_NAMESPACE::pixelTypeSize (_channelData[chan].type); |
3092 | 0 | break; |
3093 | | |
3094 | 0 | case UNKNOWN: |
3095 | 0 | planarUncBufferSize[UNKNOWN] += |
3096 | 0 | numScanLines() * (_max[0] - _min[0] + 1) * |
3097 | 0 | OPENEXR_IMF_NAMESPACE::pixelTypeSize (_channelData[chan].type); |
3098 | 0 | break; |
3099 | | |
3100 | 0 | default: |
3101 | 0 | throw IEX_NAMESPACE::NoImplExc ("Unhandled compression scheme case"); |
3102 | 0 | break; |
3103 | 0 | } |
3104 | 0 | } |
3105 | | |
3106 | | // |
3107 | | // UNKNOWN data is going to be zlib compressed, which needs |
3108 | | // a little extra headroom |
3109 | | // |
3110 | | |
3111 | 0 | if (planarUncBufferSize[UNKNOWN] > 0) |
3112 | 0 | { |
3113 | 0 | planarUncBufferSize[UNKNOWN] = |
3114 | 0 | compressBound ((uLongf)planarUncBufferSize[UNKNOWN]); |
3115 | 0 | } |
3116 | |
|
3117 | 0 | for (int i = 0; i < NUM_COMPRESSOR_SCHEMES; ++i) |
3118 | 0 | { |
3119 | 0 | if (planarUncBufferSize[i] > _planarUncBufferSize[i]) |
3120 | 0 | { |
3121 | 0 | _planarUncBufferSize[i] = planarUncBufferSize[i]; |
3122 | 0 | if (_planarUncBuffer[i] != 0) |
3123 | 0 | delete[] _planarUncBuffer[i]; |
3124 | 0 | _planarUncBuffer[i] = new char[planarUncBufferSize[i]]; |
3125 | 0 | } |
3126 | 0 | } |
3127 | 0 | } |
3128 | | |
3129 | | |
3130 | | // |
3131 | | // Setup channel classification rules to use when writing files |
3132 | | // |
3133 | | |
3134 | | void |
3135 | | DwaCompressor::initializeDefaultChannelRules () |
3136 | 0 | { |
3137 | 0 | _channelRules.clear(); |
3138 | |
|
3139 | 0 | _channelRules.push_back (Classifier ("R", LOSSY_DCT, HALF, 0, false)); |
3140 | 0 | _channelRules.push_back (Classifier ("R", LOSSY_DCT, FLOAT, 0, false)); |
3141 | 0 | _channelRules.push_back (Classifier ("G", LOSSY_DCT, HALF, 1, false)); |
3142 | 0 | _channelRules.push_back (Classifier ("G", LOSSY_DCT, FLOAT, 1, false)); |
3143 | 0 | _channelRules.push_back (Classifier ("B", LOSSY_DCT, HALF, 2, false)); |
3144 | 0 | _channelRules.push_back (Classifier ("B", LOSSY_DCT, FLOAT, 2, false)); |
3145 | |
|
3146 | 0 | _channelRules.push_back (Classifier ("Y", LOSSY_DCT, HALF, -1, false)); |
3147 | 0 | _channelRules.push_back (Classifier ("Y", LOSSY_DCT, FLOAT, -1, false)); |
3148 | 0 | _channelRules.push_back (Classifier ("BY", LOSSY_DCT, HALF, -1, false)); |
3149 | 0 | _channelRules.push_back (Classifier ("BY", LOSSY_DCT, FLOAT, -1, false)); |
3150 | 0 | _channelRules.push_back (Classifier ("RY", LOSSY_DCT, HALF, -1, false)); |
3151 | 0 | _channelRules.push_back (Classifier ("RY", LOSSY_DCT, FLOAT, -1, false)); |
3152 | |
|
3153 | 0 | _channelRules.push_back (Classifier ("A", RLE, UINT, -1, false)); |
3154 | 0 | _channelRules.push_back (Classifier ("A", RLE, HALF, -1, false)); |
3155 | 0 | _channelRules.push_back (Classifier ("A", RLE, FLOAT, -1, false)); |
3156 | 0 | } |
3157 | | |
3158 | | |
3159 | | // |
3160 | | // Setup channel classification rules when reading files with VERSION < 2 |
3161 | | // |
3162 | | |
3163 | | void |
3164 | | DwaCompressor::initializeLegacyChannelRules () |
3165 | 0 | { |
3166 | 0 | _channelRules.clear(); |
3167 | |
|
3168 | 0 | _channelRules.push_back (Classifier ("r", LOSSY_DCT, HALF, 0, true)); |
3169 | 0 | _channelRules.push_back (Classifier ("r", LOSSY_DCT, FLOAT, 0, true)); |
3170 | 0 | _channelRules.push_back (Classifier ("red", LOSSY_DCT, HALF, 0, true)); |
3171 | 0 | _channelRules.push_back (Classifier ("red", LOSSY_DCT, FLOAT, 0, true)); |
3172 | 0 | _channelRules.push_back (Classifier ("g", LOSSY_DCT, HALF, 1, true)); |
3173 | 0 | _channelRules.push_back (Classifier ("g", LOSSY_DCT, FLOAT, 1, true)); |
3174 | 0 | _channelRules.push_back (Classifier ("grn", LOSSY_DCT, HALF, 1, true)); |
3175 | 0 | _channelRules.push_back (Classifier ("grn", LOSSY_DCT, FLOAT, 1, true)); |
3176 | 0 | _channelRules.push_back (Classifier ("green", LOSSY_DCT, HALF, 1, true)); |
3177 | 0 | _channelRules.push_back (Classifier ("green", LOSSY_DCT, FLOAT, 1, true)); |
3178 | 0 | _channelRules.push_back (Classifier ("b", LOSSY_DCT, HALF, 2, true)); |
3179 | 0 | _channelRules.push_back (Classifier ("b", LOSSY_DCT, FLOAT, 2, true)); |
3180 | 0 | _channelRules.push_back (Classifier ("blu", LOSSY_DCT, HALF, 2, true)); |
3181 | 0 | _channelRules.push_back (Classifier ("blu", LOSSY_DCT, FLOAT, 2, true)); |
3182 | 0 | _channelRules.push_back (Classifier ("blue", LOSSY_DCT, HALF, 2, true)); |
3183 | 0 | _channelRules.push_back (Classifier ("blue", LOSSY_DCT, FLOAT, 2, true)); |
3184 | |
|
3185 | 0 | _channelRules.push_back (Classifier ("y", LOSSY_DCT, HALF, -1, true)); |
3186 | 0 | _channelRules.push_back (Classifier ("y", LOSSY_DCT, FLOAT, -1, true)); |
3187 | 0 | _channelRules.push_back (Classifier ("by", LOSSY_DCT, HALF, -1, true)); |
3188 | 0 | _channelRules.push_back (Classifier ("by", LOSSY_DCT, FLOAT, -1, true)); |
3189 | 0 | _channelRules.push_back (Classifier ("ry", LOSSY_DCT, HALF, -1, true)); |
3190 | 0 | _channelRules.push_back (Classifier ("ry", LOSSY_DCT, FLOAT, -1, true)); |
3191 | 0 | _channelRules.push_back (Classifier ("a", RLE, UINT, -1, true)); |
3192 | 0 | _channelRules.push_back (Classifier ("a", RLE, HALF, -1, true)); |
3193 | 0 | _channelRules.push_back (Classifier ("a", RLE, FLOAT, -1, true)); |
3194 | 0 | } |
3195 | | |
3196 | | |
3197 | | // |
3198 | | // Given a set of rules and ChannelData, figure out which rules apply |
3199 | | // |
3200 | | |
3201 | | void |
3202 | | DwaCompressor::relevantChannelRules (std::vector<Classifier> &rules) const |
3203 | 0 | { |
3204 | 0 | rules.clear(); |
3205 | |
|
3206 | 0 | std::vector<std::string> suffixes; |
3207 | | |
3208 | 0 | for (size_t cd = 0; cd < _channelData.size(); ++cd) |
3209 | 0 | { |
3210 | 0 | std::string suffix = _channelData[cd].name; |
3211 | 0 | size_t lastDot = suffix.find_last_of ('.'); |
3212 | |
|
3213 | 0 | if (lastDot != std::string::npos) |
3214 | 0 | suffix = suffix.substr (lastDot+1, std::string::npos); |
3215 | |
|
3216 | 0 | suffixes.push_back(suffix); |
3217 | 0 | } |
3218 | | |
3219 | | |
3220 | 0 | for (size_t i = 0; i < _channelRules.size(); ++i) |
3221 | 0 | { |
3222 | 0 | for (size_t cd = 0; cd < _channelData.size(); ++cd) |
3223 | 0 | { |
3224 | 0 | if (_channelRules[i].match (suffixes[cd], _channelData[cd].type )) |
3225 | 0 | { |
3226 | 0 | rules.push_back (_channelRules[i]); |
3227 | 0 | break; |
3228 | 0 | } |
3229 | 0 | } |
3230 | 0 | } |
3231 | 0 | } |
3232 | | |
3233 | | |
3234 | | // |
3235 | | // Take our initial list of channels, and cache the contents. |
3236 | | // |
3237 | | // Determine approprate compression schemes for each channel, |
3238 | | // and figure out which sets should potentially be CSC'ed |
3239 | | // prior to lossy compression. |
3240 | | // |
3241 | | |
3242 | | void |
3243 | | DwaCompressor::classifyChannels |
3244 | | (ChannelList channels, |
3245 | | std::vector<ChannelData> &chanData, |
3246 | | std::vector<CscChannelSet> &cscData) |
3247 | 0 | { |
3248 | | // |
3249 | | // prefixMap used to map channel name prefixes to |
3250 | | // potential CSC-able sets of channels. |
3251 | | // |
3252 | |
|
3253 | 0 | std::map<std::string, DwaCompressor::CscChannelSet> prefixMap; |
3254 | 0 | std::vector<DwaCompressor::CscChannelSet> tmpCscSet; |
3255 | |
|
3256 | 0 | unsigned int numChan = 0; |
3257 | |
|
3258 | 0 | for (ChannelList::Iterator c = channels.begin(); c != channels.end(); ++c) |
3259 | 0 | numChan++; |
3260 | | |
3261 | 0 | if (numChan) |
3262 | 0 | chanData.resize (numChan); |
3263 | | |
3264 | | // |
3265 | | // Cache the relevant data from the channel structs. |
3266 | | // |
3267 | |
|
3268 | 0 | unsigned int offset = 0; |
3269 | |
|
3270 | 0 | for (ChannelList::Iterator c = channels.begin(); c != channels.end(); ++c) |
3271 | 0 | { |
3272 | 0 | chanData[offset].name = std::string (c.name()); |
3273 | 0 | chanData[offset].compression = UNKNOWN; |
3274 | 0 | chanData[offset].xSampling = c.channel().xSampling; |
3275 | 0 | chanData[offset].ySampling = c.channel().ySampling; |
3276 | 0 | chanData[offset].type = c.channel().type; |
3277 | 0 | chanData[offset].pLinear = c.channel().pLinear; |
3278 | |
|
3279 | 0 | offset++; |
3280 | 0 | } |
3281 | | |
3282 | | // |
3283 | | // Try and figure out which channels should be |
3284 | | // compressed by which means. |
3285 | | // |
3286 | |
|
3287 | 0 | for (offset = 0; offset<numChan; ++offset) |
3288 | 0 | { |
3289 | 0 | std::string prefix = ""; |
3290 | 0 | std::string suffix = chanData[offset].name; |
3291 | 0 | size_t lastDot = suffix.find_last_of ('.'); |
3292 | |
|
3293 | 0 | if (lastDot != std::string::npos) |
3294 | 0 | { |
3295 | 0 | prefix = suffix.substr (0, lastDot); |
3296 | 0 | suffix = suffix.substr (lastDot+1, std::string::npos); |
3297 | 0 | } |
3298 | | |
3299 | | // |
3300 | | // Make sure we have an entry in our CSC set map |
3301 | | // |
3302 | |
|
3303 | 0 | std::map<std::string, DwaCompressor::CscChannelSet>::iterator |
3304 | 0 | theSet = prefixMap.find (prefix); |
3305 | |
|
3306 | 0 | if (theSet == prefixMap.end()) |
3307 | 0 | { |
3308 | 0 | DwaCompressor::CscChannelSet tmpSet; |
3309 | |
|
3310 | 0 | tmpSet.idx[0] = |
3311 | 0 | tmpSet.idx[1] = |
3312 | 0 | tmpSet.idx[2] = -1; |
3313 | |
|
3314 | 0 | prefixMap[prefix] = tmpSet; |
3315 | 0 | } |
3316 | | |
3317 | | // |
3318 | | // Check the suffix against the list of classifications |
3319 | | // we defined previously. If the _cscIdx is not negative, |
3320 | | // it indicates that we should be part of a CSC group. |
3321 | | // |
3322 | |
|
3323 | 0 | for (std::vector<Classifier>::iterator i = _channelRules.begin(); |
3324 | 0 | i != _channelRules.end(); |
3325 | 0 | ++i) |
3326 | 0 | { |
3327 | 0 | if ( i->match(suffix, chanData[offset].type) ) |
3328 | 0 | { |
3329 | 0 | chanData[offset].compression = i->_scheme; |
3330 | |
|
3331 | 0 | if ( i->_cscIdx >= 0) |
3332 | 0 | prefixMap[prefix].idx[i->_cscIdx] = offset; |
3333 | 0 | } |
3334 | 0 | } |
3335 | 0 | } |
3336 | | |
3337 | | // |
3338 | | // Finally, try and find RGB sets of channels which |
3339 | | // can be CSC'ed to a Y'CbCr space prior to loss, for |
3340 | | // better compression. |
3341 | | // |
3342 | | // Walk over our set of candidates, and see who has |
3343 | | // all three channels defined (and has common sampling |
3344 | | // patterns, etc). |
3345 | | // |
3346 | |
|
3347 | 0 | for (std::map<std::string, DwaCompressor::CscChannelSet>::iterator |
3348 | 0 | theItem = prefixMap.begin(); theItem != prefixMap.end(); |
3349 | 0 | ++theItem) |
3350 | 0 | { |
3351 | 0 | int red = (*theItem).second.idx[0]; |
3352 | 0 | int grn = (*theItem).second.idx[1]; |
3353 | 0 | int blu = (*theItem).second.idx[2]; |
3354 | |
|
3355 | 0 | if ((red < 0) || (grn < 0) || (blu < 0)) |
3356 | 0 | continue; |
3357 | | |
3358 | 0 | if ((chanData[red].xSampling != chanData[grn].xSampling) || |
3359 | 0 | (chanData[red].xSampling != chanData[blu].xSampling) || |
3360 | 0 | (chanData[grn].xSampling != chanData[blu].xSampling) || |
3361 | 0 | (chanData[red].ySampling != chanData[grn].ySampling) || |
3362 | 0 | (chanData[red].ySampling != chanData[blu].ySampling) || |
3363 | 0 | (chanData[grn].ySampling != chanData[blu].ySampling)) |
3364 | 0 | { |
3365 | 0 | continue; |
3366 | 0 | } |
3367 | | |
3368 | 0 | tmpCscSet.push_back ((*theItem).second); |
3369 | 0 | } |
3370 | | |
3371 | 0 | size_t numCsc = tmpCscSet.size(); |
3372 | |
|
3373 | 0 | if (numCsc) |
3374 | 0 | cscData.resize(numCsc); |
3375 | |
|
3376 | 0 | for (offset = 0; offset < numCsc; ++offset) |
3377 | 0 | cscData[offset] = tmpCscSet[offset]; |
3378 | 0 | } |
3379 | | |
3380 | | |
3381 | | |
3382 | | // |
3383 | | // Setup some buffer pointers, determine channel sizes, things |
3384 | | // like that. |
3385 | | // |
3386 | | |
3387 | | void |
3388 | | DwaCompressor::setupChannelData (int minX, int minY, int maxX, int maxY) |
3389 | 0 | { |
3390 | 0 | char *planarUncBuffer[NUM_COMPRESSOR_SCHEMES]; |
3391 | |
|
3392 | 0 | for (int i=0; i<NUM_COMPRESSOR_SCHEMES; ++i) |
3393 | 0 | { |
3394 | 0 | planarUncBuffer[i] = 0; |
3395 | |
|
3396 | 0 | if (_planarUncBuffer[i]) |
3397 | 0 | planarUncBuffer[i] = _planarUncBuffer[i]; |
3398 | 0 | } |
3399 | |
|
3400 | 0 | for (unsigned int chan = 0; chan < _channelData.size(); ++chan) |
3401 | 0 | { |
3402 | 0 | ChannelData *cd = &_channelData[chan]; |
3403 | |
|
3404 | 0 | cd->width = OPENEXR_IMF_NAMESPACE::numSamples (cd->xSampling, minX, maxX); |
3405 | 0 | cd->height = OPENEXR_IMF_NAMESPACE::numSamples (cd->ySampling, minY, maxY); |
3406 | | |
3407 | 0 | cd->planarUncSize = |
3408 | 0 | cd->width * cd->height * OPENEXR_IMF_NAMESPACE::pixelTypeSize (cd->type); |
3409 | | |
3410 | 0 | cd->planarUncBuffer = planarUncBuffer[cd->compression]; |
3411 | 0 | cd->planarUncBufferEnd = cd->planarUncBuffer; |
3412 | |
|
3413 | 0 | cd->planarUncRle[0] = cd->planarUncBuffer; |
3414 | 0 | cd->planarUncRleEnd[0] = cd->planarUncRle[0]; |
3415 | |
|
3416 | 0 | for (int byte = 1; byte < OPENEXR_IMF_NAMESPACE::pixelTypeSize(cd->type); ++byte) |
3417 | 0 | { |
3418 | 0 | cd->planarUncRle[byte] = |
3419 | 0 | cd->planarUncRle[byte-1] + cd->width * cd->height; |
3420 | |
|
3421 | 0 | cd->planarUncRleEnd[byte] = |
3422 | 0 | cd->planarUncRle[byte]; |
3423 | 0 | } |
3424 | |
|
3425 | 0 | cd->planarUncType = cd->type; |
3426 | |
|
3427 | 0 | if (cd->compression == LOSSY_DCT) |
3428 | 0 | { |
3429 | 0 | cd->planarUncType = FLOAT; |
3430 | 0 | } |
3431 | 0 | else |
3432 | 0 | { |
3433 | 0 | planarUncBuffer[cd->compression] += |
3434 | 0 | cd->width * cd->height * OPENEXR_IMF_NAMESPACE::pixelTypeSize (cd->planarUncType); |
3435 | 0 | } |
3436 | 0 | } |
3437 | 0 | } |
3438 | | |
3439 | | OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT |