Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(35)

Side by Side Diff: src/codec/SkJpegCodec.cpp

Issue 1260673002: SkScaledCodec class (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Stop DM from running large interlaced images on 32-bit Ubuntu GCE bots b/c they are running out of … Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/codec/SkJpegCodec.h ('k') | src/codec/SkScaledCodec.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2015 Google Inc. 2 * Copyright 2015 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkCodec.h" 8 #include "SkCodec.h"
9 #include "SkJpegCodec.h" 9 #include "SkJpegCodec.h"
10 #include "SkJpegDecoderMgr.h" 10 #include "SkJpegDecoderMgr.h"
11 #include "SkJpegUtility_codec.h" 11 #include "SkJpegUtility_codec.h"
12 #include "SkCodecPriv.h" 12 #include "SkCodecPriv.h"
13 #include "SkColorPriv.h" 13 #include "SkColorPriv.h"
14 #include "SkScaledCodec.h"
14 #include "SkScanlineDecoder.h" 15 #include "SkScanlineDecoder.h"
15 #include "SkStream.h" 16 #include "SkStream.h"
16 #include "SkTemplates.h" 17 #include "SkTemplates.h"
17 #include "SkTypes.h" 18 #include "SkTypes.h"
18 19
19 // stdio is needed for libjpeg-turbo 20 // stdio is needed for libjpeg-turbo
20 #include <stdio.h> 21 #include <stdio.h>
21 22
22 extern "C" { 23 extern "C" {
23 #include "jpeglibmangler.h" 24 #include "jpeglibmangler.h"
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
142 return NULL; 143 return NULL;
143 } 144 }
144 145
145 SkJpegCodec::SkJpegCodec(const SkImageInfo& srcInfo, SkStream* stream, 146 SkJpegCodec::SkJpegCodec(const SkImageInfo& srcInfo, SkStream* stream,
146 JpegDecoderMgr* decoderMgr) 147 JpegDecoderMgr* decoderMgr)
147 : INHERITED(srcInfo, stream) 148 : INHERITED(srcInfo, stream)
148 , fDecoderMgr(decoderMgr) 149 , fDecoderMgr(decoderMgr)
149 {} 150 {}
150 151
151 /* 152 /*
153 * Return the row bytes of a particular image type and width
154 */
155 static int get_row_bytes(const j_decompress_ptr dinfo) {
156 int colorBytes = (dinfo->out_color_space == JCS_RGB565) ? 2 : dinfo->out_col or_components;
157 return dinfo->output_width * colorBytes;
158
159 }
160 /*
152 * Return a valid set of output dimensions for this decoder, given an input scal e 161 * Return a valid set of output dimensions for this decoder, given an input scal e
153 */ 162 */
154 SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const { 163 SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const {
155 // 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 164 // 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
156 // support these as well 165 // support these as well
157 long num; 166 long num;
158 long denom = 8; 167 long denom = 8;
159 if (desiredScale > 0.875f) { 168 if (desiredScale > 0.875f) {
160 num = 8; 169 num = 8;
161 } else if (desiredScale > 0.75f) { 170 } else if (desiredScale > 0.75f) {
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
251 // much faster than decoding to color and then converting 260 // much faster than decoding to color and then converting
252 fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE; 261 fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE;
253 } 262 }
254 return true; 263 return true;
255 default: 264 default:
256 return false; 265 return false;
257 } 266 }
258 } 267 }
259 268
260 /* 269 /*
261 * Checks if we can scale to the requested dimensions and scales the dimensions 270 * Checks if we can natively scale to the requested dimensions and natively scal es the
262 * if possible 271 * dimensions if possible
263 */ 272 */
264 bool SkJpegCodec::scaleToDimensions(uint32_t dstWidth, uint32_t dstHeight) { 273 bool SkJpegCodec::nativelyScaleToDimensions(uint32_t dstWidth, uint32_t dstHeigh t) {
265 // libjpeg-turbo can scale to 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, and 1/1 274 // libjpeg-turbo can scale to 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, and 1/1
266 fDecoderMgr->dinfo()->scale_denom = 8; 275 fDecoderMgr->dinfo()->scale_denom = 8;
267 fDecoderMgr->dinfo()->scale_num = 8; 276 fDecoderMgr->dinfo()->scale_num = 8;
268 chromium_jpeg_calc_output_dimensions(fDecoderMgr->dinfo()); 277 chromium_jpeg_calc_output_dimensions(fDecoderMgr->dinfo());
269 while (fDecoderMgr->dinfo()->output_width != dstWidth || 278 while (fDecoderMgr->dinfo()->output_width != dstWidth ||
270 fDecoderMgr->dinfo()->output_height != dstHeight) { 279 fDecoderMgr->dinfo()->output_height != dstHeight) {
271 280
272 // Return a failure if we have tried all of the possible scales 281 // Return a failure if we have tried all of the possible scales
273 if (1 == fDecoderMgr->dinfo()->scale_num || 282 if (1 == fDecoderMgr->dinfo()->scale_num ||
274 dstWidth > fDecoderMgr->dinfo()->output_width || 283 dstWidth > fDecoderMgr->dinfo()->output_width ||
275 dstHeight > fDecoderMgr->dinfo()->output_height) { 284 dstHeight > fDecoderMgr->dinfo()->output_height) {
276 return fDecoderMgr->returnFalse("could not scale to requested dimens ions"); 285 // reset native scale settings on failure because this may be suppor ted by the swizzler
286 this->fDecoderMgr->dinfo()->scale_num = 8;
287 chromium_jpeg_calc_output_dimensions(this->fDecoderMgr->dinfo());
288 return false;
277 } 289 }
278 290
279 // Try the next scale 291 // Try the next scale
280 fDecoderMgr->dinfo()->scale_num -= 1; 292 fDecoderMgr->dinfo()->scale_num -= 1;
281 chromium_jpeg_calc_output_dimensions(fDecoderMgr->dinfo()); 293 chromium_jpeg_calc_output_dimensions(fDecoderMgr->dinfo());
282 } 294 }
283 return true; 295 return true;
284 } 296 }
285 297
286 /* 298 /*
(...skipping 19 matching lines...) Expand all
306 if (setjmp(fDecoderMgr->getJmpBuf())) { 318 if (setjmp(fDecoderMgr->getJmpBuf())) {
307 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); 319 return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
308 } 320 }
309 321
310 // Check if we can decode to the requested destination and set the output co lor space 322 // Check if we can decode to the requested destination and set the output co lor space
311 if (!this->setOutputColorSpace(dstInfo)) { 323 if (!this->setOutputColorSpace(dstInfo)) {
312 return fDecoderMgr->returnFailure("conversion_possible", kInvalidConvers ion); 324 return fDecoderMgr->returnFailure("conversion_possible", kInvalidConvers ion);
313 } 325 }
314 326
315 // Perform the necessary scaling 327 // Perform the necessary scaling
316 if (!this->scaleToDimensions(dstInfo.width(), dstInfo.height())) { 328 if (!this->nativelyScaleToDimensions(dstInfo.width(), dstInfo.height())) {
317 return fDecoderMgr->returnFailure("cannot scale to requested dims", kInv alidScale); 329 return fDecoderMgr->returnFailure("cannot scale to requested dims", kInv alidScale);
318 } 330 }
319 331
320 // Now, given valid output dimensions, we can start the decompress 332 // Now, given valid output dimensions, we can start the decompress
321 if (!chromium_jpeg_start_decompress(dinfo)) { 333 if (!chromium_jpeg_start_decompress(dinfo)) {
322 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); 334 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
323 } 335 }
324 336
325 // The recommended output buffer height should always be 1 in high quality m odes. 337 // The recommended output buffer height should always be 1 in high quality m odes.
326 // If it's not, we want to know because it means our strategy is not optimal . 338 // If it's not, we want to know because it means our strategy is not optimal .
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
374 * Enable scanline decoding for jpegs 386 * Enable scanline decoding for jpegs
375 */ 387 */
376 class SkJpegScanlineDecoder : public SkScanlineDecoder { 388 class SkJpegScanlineDecoder : public SkScanlineDecoder {
377 public: 389 public:
378 SkJpegScanlineDecoder(const SkImageInfo& srcInfo, SkJpegCodec* codec) 390 SkJpegScanlineDecoder(const SkImageInfo& srcInfo, SkJpegCodec* codec)
379 : INHERITED(srcInfo) 391 : INHERITED(srcInfo)
380 , fCodec(codec) 392 , fCodec(codec)
381 , fOpts() 393 , fOpts()
382 {} 394 {}
383 395
396 /*
397 * Return a valid set of output dimensions for this decoder, given an input s cale
398 */
399 SkISize onGetScaledDimensions(float desiredScale) override {
400 return fCodec->onGetScaledDimensions(desiredScale);
401 }
402
403 /*
404 * Create the swizzler based on the encoded format.
405 * The swizzler is only used for sampling in the x direction.
406 */
407
408 SkCodec::Result initializeSwizzler(const SkImageInfo& info, const SkCodec::O ptions& options) {
409 SkSwizzler::SrcConfig srcConfig;
410 switch (info.colorType()) {
411 case kGray_8_SkColorType:
412 srcConfig = SkSwizzler::kGray;
413 break;
414 case kRGBA_8888_SkColorType:
415 srcConfig = SkSwizzler::kRGBX;
416 break;
417 case kBGRA_8888_SkColorType:
418 srcConfig = SkSwizzler::kBGRX;
419 break;
420 case kRGB_565_SkColorType:
421 srcConfig = SkSwizzler::kRGB_565;
422 break;
423 default:
424 //would have exited before now if the colorType was supported by jpeg
425 SkASSERT(false);
426 }
427
428 fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, NULL, info, option s.fZeroInitialized,
429 this->getInfo()));
430 if (!fSwizzler) {
431 // FIXME: CreateSwizzler could fail for another reason.
432 return SkCodec::kUnimplemented;
433 }
434 return SkCodec::kSuccess;
435 }
436
384 SkCodec::Result onStart(const SkImageInfo& dstInfo, const SkCodec::Options& options, 437 SkCodec::Result onStart(const SkImageInfo& dstInfo, const SkCodec::Options& options,
385 SkPMColor ctable[], int* ctableCount) override { 438 SkPMColor ctable[], int* ctableCount) override {
386 439
387 // Rewind the stream if needed 440 // Rewind the stream if needed
388 if (!fCodec->rewindIfNeeded()) { 441 if (!fCodec->rewindIfNeeded()) {
389 return SkCodec::kCouldNotRewind; 442 return SkCodec::kCouldNotRewind;
390 } 443 }
391 444
392 // Set the jump location for libjpeg errors 445 // Set the jump location for libjpeg errors
393 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { 446 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) {
394 SkCodecPrintf("setjmp: Error from libjpeg\n"); 447 SkCodecPrintf("setjmp: Error from libjpeg\n");
395 return SkCodec::kInvalidInput; 448 return SkCodec::kInvalidInput;
396 } 449 }
397 450
398 // Check if we can decode to the requested destination and set the outpu t color space 451 // Check if we can decode to the requested destination and set the outpu t color space
399 if (!fCodec->setOutputColorSpace(dstInfo)) { 452 if (!fCodec->setOutputColorSpace(dstInfo)) {
400 return SkCodec::kInvalidConversion; 453 return SkCodec::kInvalidConversion;
401 } 454 }
402 455
403 // Perform the necessary scaling 456 // Perform the necessary scaling
404 if (!fCodec->scaleToDimensions(dstInfo.width(), dstInfo.height())) { 457 if (!fCodec->nativelyScaleToDimensions(dstInfo.width(), dstInfo.height() )) {
405 return SkCodec::kInvalidScale; 458 // full native scaling to dstInfo dimensions not supported
459
460 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) {
461 return SkCodec::kInvalidScale;
462 }
463 // create swizzler for sampling
464 SkCodec::Result result = this->initializeSwizzler(dstInfo, options);
465 if (SkCodec::kSuccess != result) {
466 SkCodecPrintf("failed to initialize the swizzler.\n");
467 return result;
468 }
469 fStorage.reset(get_row_bytes(fCodec->fDecoderMgr->dinfo()));
470 fSrcRow = static_cast<uint8_t*>(fStorage.get());
471 } else {
472 fSrcRow = NULL;
473 fSwizzler.reset(NULL);
406 } 474 }
407 475
408 // Now, given valid output dimensions, we can start the decompress 476 // Now, given valid output dimensions, we can start the decompress
409 if (!chromium_jpeg_start_decompress(fCodec->fDecoderMgr->dinfo())) { 477 if (!chromium_jpeg_start_decompress(fCodec->fDecoderMgr->dinfo())) {
410 SkCodecPrintf("start decompress failed\n"); 478 SkCodecPrintf("start decompress failed\n");
411 return SkCodec::kInvalidInput; 479 return SkCodec::kInvalidInput;
412 } 480 }
413 481
414 fOpts = options; 482 fOpts = options;
415 483
(...skipping 10 matching lines...) Expand all
426 // partial decode. 494 // partial decode.
427 fCodec->fDecoderMgr->dinfo()->output_scanline = fCodec->getInfo().height (); 495 fCodec->fDecoderMgr->dinfo()->output_scanline = fCodec->getInfo().height ();
428 chromium_jpeg_finish_decompress(fCodec->fDecoderMgr->dinfo()); 496 chromium_jpeg_finish_decompress(fCodec->fDecoderMgr->dinfo());
429 } 497 }
430 498
431 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri de { 499 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri de {
432 // Set the jump location for libjpeg errors 500 // Set the jump location for libjpeg errors
433 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { 501 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) {
434 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali dInput); 502 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali dInput);
435 } 503 }
504 // Read rows one at a time
505 JSAMPLE* dstRow;
506 if (fSwizzler) {
507 // write data to storage row, then sample using swizzler
508 dstRow = fSrcRow;
509 } else {
510 // write data directly to dst
511 dstRow = (JSAMPLE*) dst;
512 }
436 513
437 // Read rows one at a time
438 JSAMPLE* dstRow = (JSAMPLE*) dst;
439 for (int y = 0; y < count; y++) { 514 for (int y = 0; y < count; y++) {
440 // Read row of the image 515 // Read row of the image
441 uint32_t rowsDecoded = 516 uint32_t rowsDecoded =
442 chromium_jpeg_read_scanlines(fCodec->fDecoderMgr->dinfo(), & dstRow, 1); 517 chromium_jpeg_read_scanlines(fCodec->fDecoderMgr->dinfo(), & dstRow, 1);
443 if (rowsDecoded != 1) { 518 if (rowsDecoded != 1) {
444 if (SkCodec::kNo_ZeroInitialized == fOpts.fZeroInitialized || 519 if (SkCodec::kNo_ZeroInitialized == fOpts.fZeroInitialized ||
445 kN32_SkColorType == this->dstInfo().colorType()) { 520 kN32_SkColorType == this->dstInfo().colorType()) {
446 SkSwizzler::Fill(dstRow, this->dstInfo(), rowBytes, 521 SkSwizzler::Fill(dstRow, this->dstInfo(), rowBytes,
447 count - y, SK_ColorBLACK, NULL); 522 count - y, SK_ColorBLACK, NULL);
448 } 523 }
449 fCodec->fDecoderMgr->dinfo()->output_scanline = this->dstInfo(). height(); 524 fCodec->fDecoderMgr->dinfo()->output_scanline = this->dstInfo(). height();
450 return SkCodec::kIncompleteInput; 525 return SkCodec::kIncompleteInput;
451 } 526 }
452 527
453 // Convert to RGBA if necessary 528 // Convert to RGBA if necessary
454 if (JCS_CMYK == fCodec->fDecoderMgr->dinfo()->out_color_space) { 529 if (JCS_CMYK == fCodec->fDecoderMgr->dinfo()->out_color_space) {
455 convert_CMYK_to_RGBA(dstRow, this->dstInfo().width()); 530 convert_CMYK_to_RGBA(dstRow, fCodec->fDecoderMgr->dinfo()->outpu t_width);
456 } 531 }
457 532
458 // Move to the next row 533 if(fSwizzler) {
459 dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes); 534 // use swizzler to sample row
535 fSwizzler->swizzle(dst, dstRow);
536 dst = SkTAddOffset<JSAMPLE>(dst, rowBytes);
537 } else {
538 dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes);
539 }
460 } 540 }
461
462 return SkCodec::kSuccess; 541 return SkCodec::kSuccess;
463 } 542 }
464 543
465 #ifndef TURBO_HAS_SKIP 544 #ifndef TURBO_HAS_SKIP
466 // TODO (msarett): Make this a member function and avoid reallocating the 545 // TODO (msarett): Make this a member function and avoid reallocating the
467 // memory buffer on each call to skip. 546 // memory buffer on each call to skip.
468 #define chromium_jpeg_skip_scanlines(dinfo, count) \ 547 #define chromium_jpeg_skip_scanlines(dinfo, count) \
469 SkAutoMalloc storage(dinfo->output_width * dinfo->out_color_components); \ 548 SkAutoMalloc storage(get_row_bytes(dinfo)); \
470 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); \ 549 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); \
471 for (int y = 0; y < count; y++) { \ 550 for (int y = 0; y < count; y++) { \
472 chromium_jpeg_read_scanlines(dinfo, &storagePtr, 1); \ 551 chromium_jpeg_read_scanlines(dinfo, &storagePtr, 1); \
473 } 552 }
474 #endif 553 #endif
475 554
476 SkCodec::Result onSkipScanlines(int count) override { 555 SkCodec::Result onSkipScanlines(int count) override {
477 // Set the jump location for libjpeg errors 556 // Set the jump location for libjpeg errors
478 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { 557 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) {
479 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali dInput); 558 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali dInput);
480 } 559 }
481 560
482 chromium_jpeg_skip_scanlines(fCodec->fDecoderMgr->dinfo(), count); 561 chromium_jpeg_skip_scanlines(fCodec->fDecoderMgr->dinfo(), count);
483 562
484 return SkCodec::kSuccess; 563 return SkCodec::kSuccess;
485 } 564 }
486 565
487 #ifndef TURBO_HAS_SKIP 566 SkEncodedFormat onGetEncodedFormat() const override {
488 #undef chromium_jpeg_skip_scanlines 567 return kJPEG_SkEncodedFormat;
489 #endif 568 }
490 569
491 private: 570 private:
492 SkAutoTDelete<SkJpegCodec> fCodec; 571 SkAutoTDelete<SkJpegCodec> fCodec;
572 SkAutoMalloc fStorage; // Only used if sampling is needed
573 uint8_t* fSrcRow; // Only used if sampling is needed
493 SkCodec::Options fOpts; 574 SkCodec::Options fOpts;
575 SkAutoTDelete<SkSwizzler> fSwizzler;
494 576
495 typedef SkScanlineDecoder INHERITED; 577 typedef SkScanlineDecoder INHERITED;
496 }; 578 };
497 579
498 SkScanlineDecoder* SkJpegCodec::NewSDFromStream(SkStream* stream) { 580 SkScanlineDecoder* SkJpegCodec::NewSDFromStream(SkStream* stream) {
499 SkAutoTDelete<SkJpegCodec> codec(static_cast<SkJpegCodec*>(SkJpegCodec::NewF romStream(stream))); 581 SkAutoTDelete<SkJpegCodec> codec(static_cast<SkJpegCodec*>(SkJpegCodec::NewF romStream(stream)));
500 if (!codec) { 582 if (!codec) {
501 return NULL; 583 return NULL;
502 } 584 }
503 585
504 const SkImageInfo& srcInfo = codec->getInfo(); 586 const SkImageInfo& srcInfo = codec->getInfo();
587
505 // Return the new scanline decoder 588 // Return the new scanline decoder
506 return SkNEW_ARGS(SkJpegScanlineDecoder, (srcInfo, codec.detach())); 589 return SkNEW_ARGS(SkJpegScanlineDecoder, (srcInfo, codec.detach()));
507 } 590 }
OLDNEW
« no previous file with comments | « src/codec/SkJpegCodec.h ('k') | src/codec/SkScaledCodec.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698