1 /*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkCodec.h"
9 #include "SkMSAN.h"
10 #include "SkJpegCodec.h"
11 #include "SkJpegDecoderMgr.h"
12 #include "SkJpegUtility_codec.h"
13 #include "SkCodecPriv.h"
14 #include "SkColorPriv.h"
15 #include "SkStream.h"
16 #include "SkTemplates.h"
17 #include "SkTypes.h"
18
19 // stdio is needed for libjpeg-turbo
20 #include <stdio.h>
21
22 extern "C" {
23 #include "jerror.h"
24 #include "jpeglib.h"
25 }
26
IsJpeg(const void * buffer,size_t bytesRead)27 bool SkJpegCodec::IsJpeg(const void* buffer, size_t bytesRead) {
28 static const uint8_t jpegSig[] = { 0xFF, 0xD8, 0xFF };
29 return bytesRead >= 3 && !memcmp(buffer, jpegSig, sizeof(jpegSig));
30 }
31
ReadHeader(SkStream * stream,SkCodec ** codecOut,JpegDecoderMgr ** decoderMgrOut)32 bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut,
33 JpegDecoderMgr** decoderMgrOut) {
34
35 // Create a JpegDecoderMgr to own all of the decompress information
36 SkAutoTDelete<JpegDecoderMgr> decoderMgr(new JpegDecoderMgr(stream));
37
38 // libjpeg errors will be caught and reported here
39 if (setjmp(decoderMgr->getJmpBuf())) {
40 return decoderMgr->returnFalse("setjmp");
41 }
42
43 // Initialize the decompress info and the source manager
44 decoderMgr->init();
45
46 // Read the jpeg header
47 if (JPEG_HEADER_OK != jpeg_read_header(decoderMgr->dinfo(), true)) {
48 return decoderMgr->returnFalse("read_header");
49 }
50
51 if (nullptr != codecOut) {
52 // Recommend the color type to decode to
53 const SkColorType colorType = decoderMgr->getColorType();
54
55 // Create image info object and the codec
56 const SkImageInfo& imageInfo = SkImageInfo::Make(decoderMgr->dinfo()->image_width,
57 decoderMgr->dinfo()->image_height, colorType, kOpaque_SkAlphaType);
58 *codecOut = new SkJpegCodec(imageInfo, stream, decoderMgr.detach());
59 } else {
60 SkASSERT(nullptr != decoderMgrOut);
61 *decoderMgrOut = decoderMgr.detach();
62 }
63 return true;
64 }
65
NewFromStream(SkStream * stream)66 SkCodec* SkJpegCodec::NewFromStream(SkStream* stream) {
67 SkAutoTDelete<SkStream> streamDeleter(stream);
68 SkCodec* codec = nullptr;
69 if (ReadHeader(stream, &codec, nullptr)) {
70 // Codec has taken ownership of the stream, we do not need to delete it
71 SkASSERT(codec);
72 streamDeleter.detach();
73 return codec;
74 }
75 return nullptr;
76 }
77
SkJpegCodec(const SkImageInfo & srcInfo,SkStream * stream,JpegDecoderMgr * decoderMgr)78 SkJpegCodec::SkJpegCodec(const SkImageInfo& srcInfo, SkStream* stream,
79 JpegDecoderMgr* decoderMgr)
80 : INHERITED(srcInfo, stream)
81 , fDecoderMgr(decoderMgr)
82 , fReadyState(decoderMgr->dinfo()->global_state)
83 , fSwizzlerSubset(SkIRect::MakeEmpty())
84 {}
85
86 /*
87 * Return the row bytes of a particular image type and width
88 */
get_row_bytes(const j_decompress_ptr dinfo)89 static size_t get_row_bytes(const j_decompress_ptr dinfo) {
90 #ifdef TURBO_HAS_565
91 const size_t colorBytes = (dinfo->out_color_space == JCS_RGB565) ? 2 :
92 dinfo->out_color_components;
93 #else
94 const size_t colorBytes = dinfo->out_color_components;
95 #endif
96 return dinfo->output_width * colorBytes;
97
98 }
99
100 /*
101 * Calculate output dimensions based on the provided factors.
102 *
103 * Not to be used on the actual jpeg_decompress_struct used for decoding, since it will
104 * incorrectly modify num_components.
105 */
calc_output_dimensions(jpeg_decompress_struct * dinfo,unsigned int num,unsigned int denom)106 void calc_output_dimensions(jpeg_decompress_struct* dinfo, unsigned int num, unsigned int denom) {
107 dinfo->num_components = 0;
108 dinfo->scale_num = num;
109 dinfo->scale_denom = denom;
110 jpeg_calc_output_dimensions(dinfo);
111 }
112
113 /*
114 * Return a valid set of output dimensions for this decoder, given an input scale
115 */
onGetScaledDimensions(float desiredScale) const116 SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const {
117 // libjpeg-turbo supports scaling by 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, and 1/1, so we will
118 // support these as well
119 unsigned int num;
120 unsigned int denom = 8;
121 if (desiredScale >= 0.9375) {
122 num = 8;
123 } else if (desiredScale >= 0.8125) {
124 num = 7;
125 } else if (desiredScale >= 0.6875f) {
126 num = 6;
127 } else if (desiredScale >= 0.5625f) {
128 num = 5;
129 } else if (desiredScale >= 0.4375f) {
130 num = 4;
131 } else if (desiredScale >= 0.3125f) {
132 num = 3;
133 } else if (desiredScale >= 0.1875f) {
134 num = 2;
135 } else {
136 num = 1;
137 }
138
139 // Set up a fake decompress struct in order to use libjpeg to calculate output dimensions
140 jpeg_decompress_struct dinfo;
141 sk_bzero(&dinfo, sizeof(dinfo));
142 dinfo.image_width = this->getInfo().width();
143 dinfo.image_height = this->getInfo().height();
144 dinfo.global_state = fReadyState;
145 calc_output_dimensions(&dinfo, num, denom);
146
147 // Return the calculated output dimensions for the given scale
148 return SkISize::Make(dinfo.output_width, dinfo.output_height);
149 }
150
onRewind()151 bool SkJpegCodec::onRewind() {
152 JpegDecoderMgr* decoderMgr = nullptr;
153 if (!ReadHeader(this->stream(), nullptr, &decoderMgr)) {
154 return fDecoderMgr->returnFalse("could not rewind");
155 }
156 SkASSERT(nullptr != decoderMgr);
157 fDecoderMgr.reset(decoderMgr);
158 return true;
159 }
160
161 /*
162 * Checks if the conversion between the input image and the requested output
163 * image has been implemented
164 * Sets the output color space
165 */
setOutputColorSpace(const SkImageInfo & dst)166 bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dst) {
167 const SkImageInfo& src = this->getInfo();
168
169 // Ensure that the profile type is unchanged
170 if (dst.profileType() != src.profileType()) {
171 return false;
172 }
173
174 if (kUnknown_SkAlphaType == dst.alphaType()) {
175 return false;
176 }
177
178 if (kOpaque_SkAlphaType != dst.alphaType()) {
179 SkCodecPrintf("Warning: an opaque image should be decoded as opaque "
180 "- it is being decoded as non-opaque, which will draw slower\n");
181 }
182
183 // Check if we will decode to CMYK because a conversion to RGBA is not supported
184 J_COLOR_SPACE colorSpace = fDecoderMgr->dinfo()->jpeg_color_space;
185 bool isCMYK = JCS_CMYK == colorSpace || JCS_YCCK == colorSpace;
186
187 // Check for valid color types and set the output color space
188 switch (dst.colorType()) {
189 case kN32_SkColorType:
190 if (isCMYK) {
191 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
192 } else {
193 #ifdef LIBJPEG_TURBO_VERSION
194 // Check the byte ordering of the RGBA color space for the
195 // current platform
196 #ifdef SK_PMCOLOR_IS_RGBA
197 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
198 #else
199 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_BGRA;
200 #endif
201 #else
202 fDecoderMgr->dinfo()->out_color_space = JCS_RGB;
203 #endif
204 }
205 return true;
206 case kRGB_565_SkColorType:
207 if (isCMYK) {
208 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
209 } else {
210 #ifdef TURBO_HAS_565
211 fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE;
212 fDecoderMgr->dinfo()->out_color_space = JCS_RGB565;
213 #else
214 fDecoderMgr->dinfo()->out_color_space = JCS_RGB;
215 #endif
216 }
217 return true;
218 case kGray_8_SkColorType:
219 if (isCMYK) {
220 return false;
221 } else {
222 // We will enable decodes to gray even if the image is color because this is
223 // much faster than decoding to color and then converting
224 fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE;
225 }
226 return true;
227 default:
228 return false;
229 }
230 }
231
232 /*
233 * Checks if we can natively scale to the requested dimensions and natively scales the
234 * dimensions if possible
235 */
onDimensionsSupported(const SkISize & size)236 bool SkJpegCodec::onDimensionsSupported(const SkISize& size) {
237 if (setjmp(fDecoderMgr->getJmpBuf())) {
238 return fDecoderMgr->returnFalse("onDimensionsSupported/setjmp");
239 }
240
241 const unsigned int dstWidth = size.width();
242 const unsigned int dstHeight = size.height();
243
244 // Set up a fake decompress struct in order to use libjpeg to calculate output dimensions
245 // FIXME: Why is this necessary?
246 jpeg_decompress_struct dinfo;
247 sk_bzero(&dinfo, sizeof(dinfo));
248 dinfo.image_width = this->getInfo().width();
249 dinfo.image_height = this->getInfo().height();
250 dinfo.global_state = fReadyState;
251
252 // libjpeg-turbo can scale to 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, and 1/1
253 unsigned int num = 8;
254 const unsigned int denom = 8;
255 calc_output_dimensions(&dinfo, num, denom);
256 while (dinfo.output_width != dstWidth || dinfo.output_height != dstHeight) {
257
258 // Return a failure if we have tried all of the possible scales
259 if (1 == num || dstWidth > dinfo.output_width || dstHeight > dinfo.output_height) {
260 return false;
261 }
262
263 // Try the next scale
264 num -= 1;
265 calc_output_dimensions(&dinfo, num, denom);
266 }
267
268 fDecoderMgr->dinfo()->scale_num = num;
269 fDecoderMgr->dinfo()->scale_denom = denom;
270 return true;
271 }
272
273 /*
274 * Performs the jpeg decode
275 */
onGetPixels(const SkImageInfo & dstInfo,void * dst,size_t dstRowBytes,const Options & options,SkPMColor *,int *,int * rowsDecoded)276 SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo,
277 void* dst, size_t dstRowBytes,
278 const Options& options, SkPMColor*, int*,
279 int* rowsDecoded) {
280 if (options.fSubset) {
281 // Subsets are not supported.
282 return kUnimplemented;
283 }
284
285 // Get a pointer to the decompress info since we will use it quite frequently
286 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
287
288 // Set the jump location for libjpeg errors
289 if (setjmp(fDecoderMgr->getJmpBuf())) {
290 return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
291 }
292
293 // Check if we can decode to the requested destination and set the output color space
294 if (!this->setOutputColorSpace(dstInfo)) {
295 return fDecoderMgr->returnFailure("conversion_possible", kInvalidConversion);
296 }
297
298 // Now, given valid output dimensions, we can start the decompress
299 if (!jpeg_start_decompress(dinfo)) {
300 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
301 }
302
303 // The recommended output buffer height should always be 1 in high quality modes.
304 // If it's not, we want to know because it means our strategy is not optimal.
305 SkASSERT(1 == dinfo->rec_outbuf_height);
306
307 J_COLOR_SPACE colorSpace = dinfo->out_color_space;
308 if (JCS_CMYK == colorSpace || JCS_RGB == colorSpace) {
309 this->initializeSwizzler(dstInfo, options);
310 }
311
312 // Perform the decode a single row at a time
313 uint32_t dstHeight = dstInfo.height();
314
315 JSAMPLE* dstRow;
316 if (fSwizzler) {
317 // write data to storage row, then sample using swizzler
318 dstRow = fSrcRow;
319 } else {
320 // write data directly to dst
321 dstRow = (JSAMPLE*) dst;
322 }
323
324 for (uint32_t y = 0; y < dstHeight; y++) {
325 // Read rows of the image
326 uint32_t lines = jpeg_read_scanlines(dinfo, &dstRow, 1);
327 sk_msan_mark_initialized(dstRow, dstRow + dstRowBytes, "skbug.com/4550");
328
329 // If we cannot read enough rows, assume the input is incomplete
330 if (lines != 1) {
331 *rowsDecoded = y;
332
333 return fDecoderMgr->returnFailure("Incomplete image data", kIncompleteInput);
334 }
335
336 if (fSwizzler) {
337 // use swizzler to sample row
338 fSwizzler->swizzle(dst, dstRow);
339 dst = SkTAddOffset<JSAMPLE>(dst, dstRowBytes);
340 } else {
341 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes);
342 }
343 }
344
345 return kSuccess;
346 }
347
initializeSwizzler(const SkImageInfo & dstInfo,const Options & options)348 void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) {
349 SkSwizzler::SrcConfig srcConfig = SkSwizzler::kUnknown;
350 if (JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) {
351 srcConfig = SkSwizzler::kCMYK;
352 } else {
353 // If the out_color_space is not CMYK, the only reason we would need a swizzler is
354 // for sampling and/or subsetting.
355 switch (dstInfo.colorType()) {
356 case kGray_8_SkColorType:
357 srcConfig = SkSwizzler::kNoOp8;
358 break;
359 case kN32_SkColorType:
360 srcConfig = SkSwizzler::kNoOp32;
361 break;
362 case kRGB_565_SkColorType:
363 srcConfig = SkSwizzler::kNoOp16;
364 break;
365 default:
366 // This function should only be called if the colorType is supported by jpeg
367 SkASSERT(false);
368 }
369 }
370
371 if (JCS_RGB == fDecoderMgr->dinfo()->out_color_space) {
372 srcConfig = SkSwizzler::kRGB;
373 }
374
375 Options swizzlerOptions = options;
376 if (options.fSubset) {
377 // Use fSwizzlerSubset if this is a subset decode. This is necessary in the case
378 // where libjpeg-turbo provides a subset and then we need to subset it further.
379 // Also, verify that fSwizzlerSubset is initialized and valid.
380 SkASSERT(!fSwizzlerSubset.isEmpty() && fSwizzlerSubset.x() <= options.fSubset->x() &&
381 fSwizzlerSubset.width() == options.fSubset->width());
382 swizzlerOptions.fSubset = &fSwizzlerSubset;
383 }
384 fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, dstInfo, swizzlerOptions));
385 SkASSERT(fSwizzler);
386 fStorage.reset(get_row_bytes(fDecoderMgr->dinfo()));
387 fSrcRow = fStorage.get();
388 }
389
getSampler(bool createIfNecessary)390 SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) {
391 if (!createIfNecessary || fSwizzler) {
392 SkASSERT(!fSwizzler || (fSrcRow && fStorage.get() == fSrcRow));
393 return fSwizzler;
394 }
395
396 this->initializeSwizzler(this->dstInfo(), this->options());
397 return fSwizzler;
398 }
399
onStartScanlineDecode(const SkImageInfo & dstInfo,const Options & options,SkPMColor ctable[],int * ctableCount)400 SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
401 const Options& options, SkPMColor ctable[], int* ctableCount) {
402 // Set the jump location for libjpeg errors
403 if (setjmp(fDecoderMgr->getJmpBuf())) {
404 SkCodecPrintf("setjmp: Error from libjpeg\n");
405 return kInvalidInput;
406 }
407
408 // Check if we can decode to the requested destination and set the output color space
409 if (!this->setOutputColorSpace(dstInfo)) {
410 return kInvalidConversion;
411 }
412
413 // Remove objects used for sampling.
414 fSwizzler.reset(nullptr);
415 fSrcRow = nullptr;
416 fStorage.free();
417
418 // Now, given valid output dimensions, we can start the decompress
419 if (!jpeg_start_decompress(fDecoderMgr->dinfo())) {
420 SkCodecPrintf("start decompress failed\n");
421 return kInvalidInput;
422 }
423
424 if (options.fSubset) {
425 fSwizzlerSubset = *options.fSubset;
426 }
427
428 #ifdef TURBO_HAS_CROP
429 if (options.fSubset) {
430 uint32_t startX = options.fSubset->x();
431 uint32_t width = options.fSubset->width();
432
433 // libjpeg-turbo may need to align startX to a multiple of the IDCT
434 // block size. If this is the case, it will decrease the value of
435 // startX to the appropriate alignment and also increase the value
436 // of width so that the right edge of the requested subset remains
437 // the same.
438 jpeg_crop_scanline(fDecoderMgr->dinfo(), &startX, &width);
439
440 SkASSERT(startX <= (uint32_t) options.fSubset->x());
441 SkASSERT(width >= (uint32_t) options.fSubset->width());
442 SkASSERT(startX + width >= (uint32_t) options.fSubset->right());
443
444 // Instruct the swizzler (if it is necessary) to further subset the
445 // output provided by libjpeg-turbo.
446 //
447 // We set this here (rather than in the if statement below), so that
448 // if (1) we don't need a swizzler for the subset, and (2) we need a
449 // swizzler for CMYK, the swizzler will still use the proper subset
450 // dimensions.
451 //
452 // Note that the swizzler will ignore the y and height parameters of
453 // the subset. Since the scanline decoder (and the swizzler) handle
454 // one row at a time, only the subsetting in the x-dimension matters.
455 fSwizzlerSubset.setXYWH(options.fSubset->x() - startX, 0,
456 options.fSubset->width(), options.fSubset->height());
457
458 // We will need a swizzler if libjpeg-turbo cannot provide the exact
459 // subset that we request.
460 if (startX != (uint32_t) options.fSubset->x() ||
461 width != (uint32_t) options.fSubset->width()) {
462 this->initializeSwizzler(dstInfo, options);
463 }
464 }
465
466 // Make sure we have a swizzler if we are converting from CMYK.
467 if (!fSwizzler && JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) {
468 this->initializeSwizzler(dstInfo, options);
469 }
470 #else
471 // We will need a swizzler if we are performing a subset decode or
472 // converting from CMYK.
473 J_COLOR_SPACE colorSpace = fDecoderMgr->dinfo()->out_color_space;
474 if (options.fSubset || JCS_CMYK == colorSpace || JCS_RGB == colorSpace) {
475 this->initializeSwizzler(dstInfo, options);
476 }
477 #endif
478
479 return kSuccess;
480 }
481
onGetScanlines(void * dst,int count,size_t dstRowBytes)482 int SkJpegCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) {
483 // Set the jump location for libjpeg errors
484 if (setjmp(fDecoderMgr->getJmpBuf())) {
485 return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
486 }
487 // Read rows one at a time
488 JSAMPLE* dstRow;
489 size_t srcRowBytes = get_row_bytes(fDecoderMgr->dinfo());
490 if (fSwizzler) {
491 // write data to storage row, then sample using swizzler
492 dstRow = fSrcRow;
493 } else {
494 // write data directly to dst
495 SkASSERT(count == 1 || dstRowBytes >= srcRowBytes);
496 dstRow = (JSAMPLE*) dst;
497 }
498
499 for (int y = 0; y < count; y++) {
500 // Read row of the image
501 uint32_t rowsDecoded = jpeg_read_scanlines(fDecoderMgr->dinfo(), &dstRow, 1);
502 sk_msan_mark_initialized(dstRow, dstRow + srcRowBytes, "skbug.com/4550");
503 if (rowsDecoded != 1) {
504 fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height();
505 return y;
506 }
507
508 if (fSwizzler) {
509 // use swizzler to sample row
510 fSwizzler->swizzle(dst, dstRow);
511 dst = SkTAddOffset<JSAMPLE>(dst, dstRowBytes);
512 } else {
513 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes);
514 }
515 }
516 return count;
517 }
518
onSkipScanlines(int count)519 bool SkJpegCodec::onSkipScanlines(int count) {
520 // Set the jump location for libjpeg errors
521 if (setjmp(fDecoderMgr->getJmpBuf())) {
522 return fDecoderMgr->returnFalse("setjmp");
523 }
524
525 #ifdef TURBO_HAS_SKIP
526 return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count);
527 #else
528 if (!fSrcRow) {
529 fStorage.reset(get_row_bytes(fDecoderMgr->dinfo()));
530 fSrcRow = fStorage.get();
531 }
532
533 for (int y = 0; y < count; y++) {
534 if (1 != jpeg_read_scanlines(fDecoderMgr->dinfo(), &fSrcRow, 1)) {
535 return false;
536 }
537 }
538 return true;
539 #endif
540 }
541
is_yuv_supported(jpeg_decompress_struct * dinfo)542 static bool is_yuv_supported(jpeg_decompress_struct* dinfo) {
543 // Scaling is not supported in raw data mode.
544 SkASSERT(dinfo->scale_num == dinfo->scale_denom);
545
546 // I can't imagine that this would ever change, but we do depend on it.
547 static_assert(8 == DCTSIZE, "DCTSIZE (defined in jpeg library) should always be 8.");
548
549 if (JCS_YCbCr != dinfo->jpeg_color_space) {
550 return false;
551 }
552
553 SkASSERT(3 == dinfo->num_components);
554 SkASSERT(dinfo->comp_info);
555
556 // It is possible to perform a YUV decode for any combination of
557 // horizontal and vertical sampling that is supported by
558 // libjpeg/libjpeg-turbo. However, we will start by supporting only the
559 // common cases (where U and V have samp_factors of one).
560 //
561 // The definition of samp_factor is kind of the opposite of what SkCodec
562 // thinks of as a sampling factor. samp_factor is essentially a
563 // multiplier, and the larger the samp_factor is, the more samples that
564 // there will be. Ex:
565 // U_plane_width = image_width * (U_h_samp_factor / max_h_samp_factor)
566 //
567 // Supporting cases where the samp_factors for U or V were larger than
568 // that of Y would be an extremely difficult change, given that clients
569 // allocate memory as if the size of the Y plane is always the size of the
570 // image. However, this case is very, very rare.
571 if (!(1 == dinfo->comp_info[1].h_samp_factor) &&
572 (1 == dinfo->comp_info[1].v_samp_factor) &&
573 (1 == dinfo->comp_info[2].h_samp_factor) &&
574 (1 == dinfo->comp_info[2].v_samp_factor)) {
575 return false;
576 }
577
578 // Support all common cases of Y samp_factors.
579 // TODO (msarett): As mentioned above, it would be possible to support
580 // more combinations of samp_factors. The issues are:
581 // (1) Are there actually any images that are not covered
582 // by these cases?
583 // (2) How much complexity would be added to the
584 // implementation in order to support these rare
585 // cases?
586 int hSampY = dinfo->comp_info[0].h_samp_factor;
587 int vSampY = dinfo->comp_info[0].v_samp_factor;
588 return (1 == hSampY && 1 == vSampY) ||
589 (2 == hSampY && 1 == vSampY) ||
590 (2 == hSampY && 2 == vSampY) ||
591 (1 == hSampY && 2 == vSampY) ||
592 (4 == hSampY && 1 == vSampY) ||
593 (4 == hSampY && 2 == vSampY);
594 }
595
onQueryYUV8(YUVSizeInfo * sizeInfo,SkYUVColorSpace * colorSpace) const596 bool SkJpegCodec::onQueryYUV8(YUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const {
597 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
598 if (!is_yuv_supported(dinfo)) {
599 return false;
600 }
601
602 sizeInfo->fYSize.set(dinfo->comp_info[0].downsampled_width,
603 dinfo->comp_info[0].downsampled_height);
604 sizeInfo->fUSize.set(dinfo->comp_info[1].downsampled_width,
605 dinfo->comp_info[1].downsampled_height);
606 sizeInfo->fVSize.set(dinfo->comp_info[2].downsampled_width,
607 dinfo->comp_info[2].downsampled_height);
608 sizeInfo->fYWidthBytes = dinfo->comp_info[0].width_in_blocks * DCTSIZE;
609 sizeInfo->fUWidthBytes = dinfo->comp_info[1].width_in_blocks * DCTSIZE;
610 sizeInfo->fVWidthBytes = dinfo->comp_info[2].width_in_blocks * DCTSIZE;
611
612 if (colorSpace) {
613 *colorSpace = kJPEG_SkYUVColorSpace;
614 }
615
616 return true;
617 }
618
onGetYUV8Planes(const YUVSizeInfo & sizeInfo,void * pixels[3])619 SkCodec::Result SkJpegCodec::onGetYUV8Planes(const YUVSizeInfo& sizeInfo, void* pixels[3]) {
620 YUVSizeInfo defaultInfo;
621
622 // This will check is_yuv_supported(), so we don't need to here.
623 bool supportsYUV = this->onQueryYUV8(&defaultInfo, nullptr);
624 if (!supportsYUV || sizeInfo.fYSize != defaultInfo.fYSize ||
625 sizeInfo.fUSize != defaultInfo.fUSize ||
626 sizeInfo.fVSize != defaultInfo.fVSize ||
627 sizeInfo.fYWidthBytes < defaultInfo.fYWidthBytes ||
628 sizeInfo.fUWidthBytes < defaultInfo.fUWidthBytes ||
629 sizeInfo.fVWidthBytes < defaultInfo.fVWidthBytes) {
630 return fDecoderMgr->returnFailure("onGetYUV8Planes", kInvalidInput);
631 }
632
633 // Set the jump location for libjpeg errors
634 if (setjmp(fDecoderMgr->getJmpBuf())) {
635 return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
636 }
637
638 // Get a pointer to the decompress info since we will use it quite frequently
639 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
640
641 dinfo->raw_data_out = TRUE;
642 if (!jpeg_start_decompress(dinfo)) {
643 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
644 }
645
646 // A previous implementation claims that the return value of is_yuv_supported()
647 // may change after calling jpeg_start_decompress(). It looks to me like this
648 // was caused by a bug in the old code, but we'll be safe and check here.
649 SkASSERT(is_yuv_supported(dinfo));
650
651 // Currently, we require that the Y plane dimensions match the image dimensions
652 // and that the U and V planes are the same dimensions.
653 SkASSERT(sizeInfo.fUSize == sizeInfo.fVSize);
654 SkASSERT((uint32_t) sizeInfo.fYSize.width() == dinfo->output_width &&
655 (uint32_t) sizeInfo.fYSize.height() == dinfo->output_height);
656
657 // Build a JSAMPIMAGE to handle output from libjpeg-turbo. A JSAMPIMAGE has
658 // a 2-D array of pixels for each of the components (Y, U, V) in the image.
659 // Cheat Sheet:
660 // JSAMPIMAGE == JSAMPLEARRAY* == JSAMPROW** == JSAMPLE***
661 JSAMPARRAY yuv[3];
662
663 // Set aside enough space for pointers to rows of Y, U, and V.
664 JSAMPROW rowptrs[2 * DCTSIZE + DCTSIZE + DCTSIZE];
665 yuv[0] = &rowptrs[0]; // Y rows (DCTSIZE or 2 * DCTSIZE)
666 yuv[1] = &rowptrs[2 * DCTSIZE]; // U rows (DCTSIZE)
667 yuv[2] = &rowptrs[3 * DCTSIZE]; // V rows (DCTSIZE)
668
669 // Initialize rowptrs.
670 int numYRowsPerBlock = DCTSIZE * dinfo->comp_info[0].v_samp_factor;
671 for (int i = 0; i < numYRowsPerBlock; i++) {
672 rowptrs[i] = SkTAddOffset<JSAMPLE>(pixels[0], i * sizeInfo.fYWidthBytes);
673 }
674 for (int i = 0; i < DCTSIZE; i++) {
675 rowptrs[i + 2 * DCTSIZE] = SkTAddOffset<JSAMPLE>(pixels[1], i * sizeInfo.fUWidthBytes);
676 rowptrs[i + 3 * DCTSIZE] = SkTAddOffset<JSAMPLE>(pixels[2], i * sizeInfo.fVWidthBytes);
677 }
678
679 // After each loop iteration, we will increment pointers to Y, U, and V.
680 size_t blockIncrementY = numYRowsPerBlock * sizeInfo.fYWidthBytes;
681 size_t blockIncrementU = DCTSIZE * sizeInfo.fUWidthBytes;
682 size_t blockIncrementV = DCTSIZE * sizeInfo.fVWidthBytes;
683
684 uint32_t numRowsPerBlock = numYRowsPerBlock;
685
686 // We intentionally round down here, as this first loop will only handle
687 // full block rows. As a special case at the end, we will handle any
688 // remaining rows that do not make up a full block.
689 const int numIters = dinfo->output_height / numRowsPerBlock;
690 for (int i = 0; i < numIters; i++) {
691 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock);
692 if (linesRead < numRowsPerBlock) {
693 // FIXME: Handle incomplete YUV decodes without signalling an error.
694 return kInvalidInput;
695 }
696
697 // Update rowptrs.
698 for (int i = 0; i < numYRowsPerBlock; i++) {
699 rowptrs[i] += blockIncrementY;
700 }
701 for (int i = 0; i < DCTSIZE; i++) {
702 rowptrs[i + 2 * DCTSIZE] += blockIncrementU;
703 rowptrs[i + 3 * DCTSIZE] += blockIncrementV;
704 }
705 }
706
707 uint32_t remainingRows = dinfo->output_height - dinfo->output_scanline;
708 SkASSERT(remainingRows == dinfo->output_height % numRowsPerBlock);
709 SkASSERT(dinfo->output_scanline == numIters * numRowsPerBlock);
710 if (remainingRows > 0) {
711 // libjpeg-turbo needs memory to be padded by the block sizes. We will fulfill
712 // this requirement using a dummy row buffer.
713 // FIXME: Should SkCodec have an extra memory buffer that can be shared among
714 // all of the implementations that use temporary/garbage memory?
715 SkAutoTMalloc<JSAMPLE> dummyRow(sizeInfo.fYWidthBytes);
716 for (int i = remainingRows; i < numYRowsPerBlock; i++) {
717 rowptrs[i] = dummyRow.get();
718 }
719 int remainingUVRows = dinfo->comp_info[1].downsampled_height - DCTSIZE * numIters;
720 for (int i = remainingUVRows; i < DCTSIZE; i++) {
721 rowptrs[i + 2 * DCTSIZE] = dummyRow.get();
722 rowptrs[i + 3 * DCTSIZE] = dummyRow.get();
723 }
724
725 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock);
726 if (linesRead < remainingRows) {
727 // FIXME: Handle incomplete YUV decodes without signalling an error.
728 return kInvalidInput;
729 }
730 }
731
732 return kSuccess;
733 }
734