| OLD | NEW |
| 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 "SkMSAN.h" | 9 #include "SkMSAN.h" |
| 10 #include "SkJpegCodec.h" | 10 #include "SkJpegCodec.h" |
| (...skipping 517 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 528 int hSampY = dinfo->comp_info[0].h_samp_factor; | 528 int hSampY = dinfo->comp_info[0].h_samp_factor; |
| 529 int vSampY = dinfo->comp_info[0].v_samp_factor; | 529 int vSampY = dinfo->comp_info[0].v_samp_factor; |
| 530 return (1 == hSampY && 1 == vSampY) || | 530 return (1 == hSampY && 1 == vSampY) || |
| 531 (2 == hSampY && 1 == vSampY) || | 531 (2 == hSampY && 1 == vSampY) || |
| 532 (2 == hSampY && 2 == vSampY) || | 532 (2 == hSampY && 2 == vSampY) || |
| 533 (1 == hSampY && 2 == vSampY) || | 533 (1 == hSampY && 2 == vSampY) || |
| 534 (4 == hSampY && 1 == vSampY) || | 534 (4 == hSampY && 1 == vSampY) || |
| 535 (4 == hSampY && 2 == vSampY); | 535 (4 == hSampY && 2 == vSampY); |
| 536 } | 536 } |
| 537 | 537 |
| 538 bool SkJpegCodec::onQueryYUV8(YUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace
) const { | 538 bool SkJpegCodec::onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpa
ce) const { |
| 539 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); | 539 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); |
| 540 if (!is_yuv_supported(dinfo)) { | 540 if (!is_yuv_supported(dinfo)) { |
| 541 return false; | 541 return false; |
| 542 } | 542 } |
| 543 | 543 |
| 544 sizeInfo->fYSize.set(dinfo->comp_info[0].downsampled_width, | 544 sizeInfo->fSizes[SkYUVSizeInfo::kY].set(dinfo->comp_info[0].downsampled_widt
h, |
| 545 dinfo->comp_info[0].downsampled_height); | 545 dinfo->comp_info[0].downsampled_heigh
t); |
| 546 sizeInfo->fUSize.set(dinfo->comp_info[1].downsampled_width, | 546 sizeInfo->fSizes[SkYUVSizeInfo::kU].set(dinfo->comp_info[1].downsampled_widt
h, |
| 547 dinfo->comp_info[1].downsampled_height); | 547 dinfo->comp_info[1].downsampled_heigh
t); |
| 548 sizeInfo->fVSize.set(dinfo->comp_info[2].downsampled_width, | 548 sizeInfo->fSizes[SkYUVSizeInfo::kV].set(dinfo->comp_info[2].downsampled_widt
h, |
| 549 dinfo->comp_info[2].downsampled_height); | 549 dinfo->comp_info[2].downsampled_heigh
t); |
| 550 sizeInfo->fYWidthBytes = dinfo->comp_info[0].width_in_blocks * DCTSIZE; | 550 sizeInfo->fWidthBytes[SkYUVSizeInfo::kY] = dinfo->comp_info[0].width_in_bloc
ks * DCTSIZE; |
| 551 sizeInfo->fUWidthBytes = dinfo->comp_info[1].width_in_blocks * DCTSIZE; | 551 sizeInfo->fWidthBytes[SkYUVSizeInfo::kU] = dinfo->comp_info[1].width_in_bloc
ks * DCTSIZE; |
| 552 sizeInfo->fVWidthBytes = dinfo->comp_info[2].width_in_blocks * DCTSIZE; | 552 sizeInfo->fWidthBytes[SkYUVSizeInfo::kV] = dinfo->comp_info[2].width_in_bloc
ks * DCTSIZE; |
| 553 | 553 |
| 554 if (colorSpace) { | 554 if (colorSpace) { |
| 555 *colorSpace = kJPEG_SkYUVColorSpace; | 555 *colorSpace = kJPEG_SkYUVColorSpace; |
| 556 } | 556 } |
| 557 | 557 |
| 558 return true; | 558 return true; |
| 559 } | 559 } |
| 560 | 560 |
| 561 SkCodec::Result SkJpegCodec::onGetYUV8Planes(const YUVSizeInfo& sizeInfo, void*
pixels[3]) { | 561 SkCodec::Result SkJpegCodec::onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, |
| 562 YUVSizeInfo defaultInfo; | 562 void* pixels[SkYUVSizeInfo::kPlaneCount]) { |
| 563 SkYUVSizeInfo defaultInfo; |
| 563 | 564 |
| 564 // This will check is_yuv_supported(), so we don't need to here. | 565 // This will check is_yuv_supported(), so we don't need to here. |
| 565 bool supportsYUV = this->onQueryYUV8(&defaultInfo, nullptr); | 566 bool supportsYUV = this->onQueryYUV8(&defaultInfo, nullptr); |
| 566 if (!supportsYUV || sizeInfo.fYSize != defaultInfo.fYSize || | 567 if (!supportsYUV || |
| 567 sizeInfo.fUSize != defaultInfo.fUSize || | 568 sizeInfo.fSizes[SkYUVSizeInfo::kY] != defaultInfo.fSizes[SkYUVSizeIn
fo::kY] || |
| 568 sizeInfo.fVSize != defaultInfo.fVSize || | 569 sizeInfo.fSizes[SkYUVSizeInfo::kU] != defaultInfo.fSizes[SkYUVSizeIn
fo::kU] || |
| 569 sizeInfo.fYWidthBytes < defaultInfo.fYWidthBytes || | 570 sizeInfo.fSizes[SkYUVSizeInfo::kV] != defaultInfo.fSizes[SkYUVSizeIn
fo::kV] || |
| 570 sizeInfo.fUWidthBytes < defaultInfo.fUWidthBytes || | 571 sizeInfo.fWidthBytes[SkYUVSizeInfo::kY] < defaultInfo.fWidthBytes[Sk
YUVSizeInfo::kY] || |
| 571 sizeInfo.fVWidthBytes < defaultInfo.fVWidthBytes) { | 572 sizeInfo.fWidthBytes[SkYUVSizeInfo::kU] < defaultInfo.fWidthBytes[Sk
YUVSizeInfo::kU] || |
| 573 sizeInfo.fWidthBytes[SkYUVSizeInfo::kV] < defaultInfo.fWidthBytes[Sk
YUVSizeInfo::kV]) { |
| 572 return fDecoderMgr->returnFailure("onGetYUV8Planes", kInvalidInput); | 574 return fDecoderMgr->returnFailure("onGetYUV8Planes", kInvalidInput); |
| 573 } | 575 } |
| 574 | 576 |
| 575 // Set the jump location for libjpeg errors | 577 // Set the jump location for libjpeg errors |
| 576 if (setjmp(fDecoderMgr->getJmpBuf())) { | 578 if (setjmp(fDecoderMgr->getJmpBuf())) { |
| 577 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); | 579 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); |
| 578 } | 580 } |
| 579 | 581 |
| 580 // Get a pointer to the decompress info since we will use it quite frequentl
y | 582 // Get a pointer to the decompress info since we will use it quite frequentl
y |
| 581 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); | 583 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); |
| 582 | 584 |
| 583 dinfo->raw_data_out = TRUE; | 585 dinfo->raw_data_out = TRUE; |
| 584 if (!jpeg_start_decompress(dinfo)) { | 586 if (!jpeg_start_decompress(dinfo)) { |
| 585 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); | 587 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); |
| 586 } | 588 } |
| 587 | 589 |
| 588 // A previous implementation claims that the return value of is_yuv_supporte
d() | 590 // A previous implementation claims that the return value of is_yuv_supporte
d() |
| 589 // may change after calling jpeg_start_decompress(). It looks to me like th
is | 591 // may change after calling jpeg_start_decompress(). It looks to me like th
is |
| 590 // was caused by a bug in the old code, but we'll be safe and check here. | 592 // was caused by a bug in the old code, but we'll be safe and check here. |
| 591 SkASSERT(is_yuv_supported(dinfo)); | 593 SkASSERT(is_yuv_supported(dinfo)); |
| 592 | 594 |
| 593 // Currently, we require that the Y plane dimensions match the image dimensi
ons | 595 // Currently, we require that the Y plane dimensions match the image dimensi
ons |
| 594 // and that the U and V planes are the same dimensions. | 596 // and that the U and V planes are the same dimensions. |
| 595 SkASSERT(sizeInfo.fUSize == sizeInfo.fVSize); | 597 SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kU] == sizeInfo.fSizes[SkYUVSizeInfo
::kV]); |
| 596 SkASSERT((uint32_t) sizeInfo.fYSize.width() == dinfo->output_width && | 598 SkASSERT((uint32_t) sizeInfo.fSizes[SkYUVSizeInfo::kY].width() == dinfo->out
put_width && |
| 597 (uint32_t) sizeInfo.fYSize.height() == dinfo->output_height); | 599 (uint32_t) sizeInfo.fSizes[SkYUVSizeInfo::kY].height() == dinfo->out
put_height); |
| 598 | 600 |
| 599 // Build a JSAMPIMAGE to handle output from libjpeg-turbo. A JSAMPIMAGE has | 601 // Build a JSAMPIMAGE to handle output from libjpeg-turbo. A JSAMPIMAGE has |
| 600 // a 2-D array of pixels for each of the components (Y, U, V) in the image. | 602 // a 2-D array of pixels for each of the components (Y, U, V) in the image. |
| 601 // Cheat Sheet: | 603 // Cheat Sheet: |
| 602 // JSAMPIMAGE == JSAMPLEARRAY* == JSAMPROW** == JSAMPLE*** | 604 // JSAMPIMAGE == JSAMPLEARRAY* == JSAMPROW** == JSAMPLE*** |
| 603 JSAMPARRAY yuv[3]; | 605 JSAMPARRAY yuv[3]; |
| 604 | 606 |
| 605 // Set aside enough space for pointers to rows of Y, U, and V. | 607 // Set aside enough space for pointers to rows of Y, U, and V. |
| 606 JSAMPROW rowptrs[2 * DCTSIZE + DCTSIZE + DCTSIZE]; | 608 JSAMPROW rowptrs[2 * DCTSIZE + DCTSIZE + DCTSIZE]; |
| 607 yuv[0] = &rowptrs[0]; // Y rows (DCTSIZE or 2 * DCTSIZE) | 609 yuv[0] = &rowptrs[0]; // Y rows (DCTSIZE or 2 * DCTSIZE) |
| 608 yuv[1] = &rowptrs[2 * DCTSIZE]; // U rows (DCTSIZE) | 610 yuv[1] = &rowptrs[2 * DCTSIZE]; // U rows (DCTSIZE) |
| 609 yuv[2] = &rowptrs[3 * DCTSIZE]; // V rows (DCTSIZE) | 611 yuv[2] = &rowptrs[3 * DCTSIZE]; // V rows (DCTSIZE) |
| 610 | 612 |
| 611 // Initialize rowptrs. | 613 // Initialize rowptrs. |
| 612 int numYRowsPerBlock = DCTSIZE * dinfo->comp_info[0].v_samp_factor; | 614 int numYRowsPerBlock = DCTSIZE * dinfo->comp_info[0].v_samp_factor; |
| 613 for (int i = 0; i < numYRowsPerBlock; i++) { | 615 for (int i = 0; i < numYRowsPerBlock; i++) { |
| 614 rowptrs[i] = SkTAddOffset<JSAMPLE>(pixels[0], i * sizeInfo.fYWidthBytes)
; | 616 rowptrs[i] = SkTAddOffset<JSAMPLE>(pixels[SkYUVSizeInfo::kY], |
| 617 i * sizeInfo.fWidthBytes[SkYUVSizeInfo::kY]); |
| 615 } | 618 } |
| 616 for (int i = 0; i < DCTSIZE; i++) { | 619 for (int i = 0; i < DCTSIZE; i++) { |
| 617 rowptrs[i + 2 * DCTSIZE] = SkTAddOffset<JSAMPLE>(pixels[1], i * sizeInfo
.fUWidthBytes); | 620 rowptrs[i + 2 * DCTSIZE] = SkTAddOffset<JSAMPLE>(pixels[SkYUVSizeInfo::k
U], |
| 618 rowptrs[i + 3 * DCTSIZE] = SkTAddOffset<JSAMPLE>(pixels[2], i * sizeInfo
.fVWidthBytes); | 621 i * sizeInfo.fWidthBytes[SkYUVSizeInfo::kU]); |
| 622 rowptrs[i + 3 * DCTSIZE] = SkTAddOffset<JSAMPLE>(pixels[SkYUVSizeInfo::k
V], |
| 623 i * sizeInfo.fWidthBytes[SkYUVSizeInfo::kV]); |
| 619 } | 624 } |
| 620 | 625 |
| 621 // After each loop iteration, we will increment pointers to Y, U, and V. | 626 // After each loop iteration, we will increment pointers to Y, U, and V. |
| 622 size_t blockIncrementY = numYRowsPerBlock * sizeInfo.fYWidthBytes; | 627 size_t blockIncrementY = numYRowsPerBlock * sizeInfo.fWidthBytes[SkYUVSizeIn
fo::kY]; |
| 623 size_t blockIncrementU = DCTSIZE * sizeInfo.fUWidthBytes; | 628 size_t blockIncrementU = DCTSIZE * sizeInfo.fWidthBytes[SkYUVSizeInfo::kU]; |
| 624 size_t blockIncrementV = DCTSIZE * sizeInfo.fVWidthBytes; | 629 size_t blockIncrementV = DCTSIZE * sizeInfo.fWidthBytes[SkYUVSizeInfo::kV]; |
| 625 | 630 |
| 626 uint32_t numRowsPerBlock = numYRowsPerBlock; | 631 uint32_t numRowsPerBlock = numYRowsPerBlock; |
| 627 | 632 |
| 628 // We intentionally round down here, as this first loop will only handle | 633 // We intentionally round down here, as this first loop will only handle |
| 629 // full block rows. As a special case at the end, we will handle any | 634 // full block rows. As a special case at the end, we will handle any |
| 630 // remaining rows that do not make up a full block. | 635 // remaining rows that do not make up a full block. |
| 631 const int numIters = dinfo->output_height / numRowsPerBlock; | 636 const int numIters = dinfo->output_height / numRowsPerBlock; |
| 632 for (int i = 0; i < numIters; i++) { | 637 for (int i = 0; i < numIters; i++) { |
| 633 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock); | 638 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock); |
| 634 if (linesRead < numRowsPerBlock) { | 639 if (linesRead < numRowsPerBlock) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 647 } | 652 } |
| 648 | 653 |
| 649 uint32_t remainingRows = dinfo->output_height - dinfo->output_scanline; | 654 uint32_t remainingRows = dinfo->output_height - dinfo->output_scanline; |
| 650 SkASSERT(remainingRows == dinfo->output_height % numRowsPerBlock); | 655 SkASSERT(remainingRows == dinfo->output_height % numRowsPerBlock); |
| 651 SkASSERT(dinfo->output_scanline == numIters * numRowsPerBlock); | 656 SkASSERT(dinfo->output_scanline == numIters * numRowsPerBlock); |
| 652 if (remainingRows > 0) { | 657 if (remainingRows > 0) { |
| 653 // libjpeg-turbo needs memory to be padded by the block sizes. We will
fulfill | 658 // libjpeg-turbo needs memory to be padded by the block sizes. We will
fulfill |
| 654 // this requirement using a dummy row buffer. | 659 // this requirement using a dummy row buffer. |
| 655 // FIXME: Should SkCodec have an extra memory buffer that can be shared
among | 660 // FIXME: Should SkCodec have an extra memory buffer that can be shared
among |
| 656 // all of the implementations that use temporary/garbage memory? | 661 // all of the implementations that use temporary/garbage memory? |
| 657 SkAutoTMalloc<JSAMPLE> dummyRow(sizeInfo.fYWidthBytes); | 662 SkAutoTMalloc<JSAMPLE> dummyRow(sizeInfo.fWidthBytes[SkYUVSizeInfo::kY])
; |
| 658 for (int i = remainingRows; i < numYRowsPerBlock; i++) { | 663 for (int i = remainingRows; i < numYRowsPerBlock; i++) { |
| 659 rowptrs[i] = dummyRow.get(); | 664 rowptrs[i] = dummyRow.get(); |
| 660 } | 665 } |
| 661 int remainingUVRows = dinfo->comp_info[1].downsampled_height - DCTSIZE *
numIters; | 666 int remainingUVRows = dinfo->comp_info[1].downsampled_height - DCTSIZE *
numIters; |
| 662 for (int i = remainingUVRows; i < DCTSIZE; i++) { | 667 for (int i = remainingUVRows; i < DCTSIZE; i++) { |
| 663 rowptrs[i + 2 * DCTSIZE] = dummyRow.get(); | 668 rowptrs[i + 2 * DCTSIZE] = dummyRow.get(); |
| 664 rowptrs[i + 3 * DCTSIZE] = dummyRow.get(); | 669 rowptrs[i + 3 * DCTSIZE] = dummyRow.get(); |
| 665 } | 670 } |
| 666 | 671 |
| 667 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock); | 672 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock); |
| 668 if (linesRead < remainingRows) { | 673 if (linesRead < remainingRows) { |
| 669 // FIXME: Handle incomplete YUV decodes without signalling an error. | 674 // FIXME: Handle incomplete YUV decodes without signalling an error. |
| 670 return kInvalidInput; | 675 return kInvalidInput; |
| 671 } | 676 } |
| 672 } | 677 } |
| 673 | 678 |
| 674 return kSuccess; | 679 return kSuccess; |
| 675 } | 680 } |
| OLD | NEW |