| 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 576 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 587 int hSampY = dinfo->comp_info[0].h_samp_factor; | 587 int hSampY = dinfo->comp_info[0].h_samp_factor; |
| 588 int vSampY = dinfo->comp_info[0].v_samp_factor; | 588 int vSampY = dinfo->comp_info[0].v_samp_factor; |
| 589 return (1 == hSampY && 1 == vSampY) || | 589 return (1 == hSampY && 1 == vSampY) || |
| 590 (2 == hSampY && 1 == vSampY) || | 590 (2 == hSampY && 1 == vSampY) || |
| 591 (2 == hSampY && 2 == vSampY) || | 591 (2 == hSampY && 2 == vSampY) || |
| 592 (1 == hSampY && 2 == vSampY) || | 592 (1 == hSampY && 2 == vSampY) || |
| 593 (4 == hSampY && 1 == vSampY) || | 593 (4 == hSampY && 1 == vSampY) || |
| 594 (4 == hSampY && 2 == vSampY); | 594 (4 == hSampY && 2 == vSampY); |
| 595 } | 595 } |
| 596 | 596 |
| 597 bool SkJpegCodec::onQueryYUV8(YUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace
) const { | 597 bool SkJpegCodec::onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpa
ce) const { |
| 598 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); | 598 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); |
| 599 if (!is_yuv_supported(dinfo)) { | 599 if (!is_yuv_supported(dinfo)) { |
| 600 return false; | 600 return false; |
| 601 } | 601 } |
| 602 | 602 |
| 603 sizeInfo->fYSize.set(dinfo->comp_info[0].downsampled_width, | 603 sizeInfo->fSizes[SkYUVSizeInfo::kY].set(dinfo->comp_info[0].downsampled_widt
h, |
| 604 dinfo->comp_info[0].downsampled_height); | 604 dinfo->comp_info[0].downsampled_heigh
t); |
| 605 sizeInfo->fUSize.set(dinfo->comp_info[1].downsampled_width, | 605 sizeInfo->fSizes[SkYUVSizeInfo::kU].set(dinfo->comp_info[1].downsampled_widt
h, |
| 606 dinfo->comp_info[1].downsampled_height); | 606 dinfo->comp_info[1].downsampled_heigh
t); |
| 607 sizeInfo->fVSize.set(dinfo->comp_info[2].downsampled_width, | 607 sizeInfo->fSizes[SkYUVSizeInfo::kV].set(dinfo->comp_info[2].downsampled_widt
h, |
| 608 dinfo->comp_info[2].downsampled_height); | 608 dinfo->comp_info[2].downsampled_heigh
t); |
| 609 sizeInfo->fYWidthBytes = dinfo->comp_info[0].width_in_blocks * DCTSIZE; | 609 sizeInfo->fWidthBytes[SkYUVSizeInfo::kY] = dinfo->comp_info[0].width_in_bloc
ks * DCTSIZE; |
| 610 sizeInfo->fUWidthBytes = dinfo->comp_info[1].width_in_blocks * DCTSIZE; | 610 sizeInfo->fWidthBytes[SkYUVSizeInfo::kU] = dinfo->comp_info[1].width_in_bloc
ks * DCTSIZE; |
| 611 sizeInfo->fVWidthBytes = dinfo->comp_info[2].width_in_blocks * DCTSIZE; | 611 sizeInfo->fWidthBytes[SkYUVSizeInfo::kV] = dinfo->comp_info[2].width_in_bloc
ks * DCTSIZE; |
| 612 | 612 |
| 613 if (colorSpace) { | 613 if (colorSpace) { |
| 614 *colorSpace = kJPEG_SkYUVColorSpace; | 614 *colorSpace = kJPEG_SkYUVColorSpace; |
| 615 } | 615 } |
| 616 | 616 |
| 617 return true; | 617 return true; |
| 618 } | 618 } |
| 619 | 619 |
| 620 SkCodec::Result SkJpegCodec::onGetYUV8Planes(const YUVSizeInfo& sizeInfo, void*
pixels[3]) { | 620 SkCodec::Result SkJpegCodec::onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void
* planes[3]) { |
| 621 YUVSizeInfo defaultInfo; | 621 SkYUVSizeInfo defaultInfo; |
| 622 | 622 |
| 623 // This will check is_yuv_supported(), so we don't need to here. | 623 // This will check is_yuv_supported(), so we don't need to here. |
| 624 bool supportsYUV = this->onQueryYUV8(&defaultInfo, nullptr); | 624 bool supportsYUV = this->onQueryYUV8(&defaultInfo, nullptr); |
| 625 if (!supportsYUV || sizeInfo.fYSize != defaultInfo.fYSize || | 625 if (!supportsYUV || |
| 626 sizeInfo.fUSize != defaultInfo.fUSize || | 626 sizeInfo.fSizes[SkYUVSizeInfo::kY] != defaultInfo.fSizes[SkYUVSizeIn
fo::kY] || |
| 627 sizeInfo.fVSize != defaultInfo.fVSize || | 627 sizeInfo.fSizes[SkYUVSizeInfo::kU] != defaultInfo.fSizes[SkYUVSizeIn
fo::kU] || |
| 628 sizeInfo.fYWidthBytes < defaultInfo.fYWidthBytes || | 628 sizeInfo.fSizes[SkYUVSizeInfo::kV] != defaultInfo.fSizes[SkYUVSizeIn
fo::kV] || |
| 629 sizeInfo.fUWidthBytes < defaultInfo.fUWidthBytes || | 629 sizeInfo.fWidthBytes[SkYUVSizeInfo::kY] < defaultInfo.fWidthBytes[Sk
YUVSizeInfo::kY] || |
| 630 sizeInfo.fVWidthBytes < defaultInfo.fVWidthBytes) { | 630 sizeInfo.fWidthBytes[SkYUVSizeInfo::kU] < defaultInfo.fWidthBytes[Sk
YUVSizeInfo::kU] || |
| 631 sizeInfo.fWidthBytes[SkYUVSizeInfo::kV] < defaultInfo.fWidthBytes[Sk
YUVSizeInfo::kV]) { |
| 631 return fDecoderMgr->returnFailure("onGetYUV8Planes", kInvalidInput); | 632 return fDecoderMgr->returnFailure("onGetYUV8Planes", kInvalidInput); |
| 632 } | 633 } |
| 633 | 634 |
| 634 // Set the jump location for libjpeg errors | 635 // Set the jump location for libjpeg errors |
| 635 if (setjmp(fDecoderMgr->getJmpBuf())) { | 636 if (setjmp(fDecoderMgr->getJmpBuf())) { |
| 636 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); | 637 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); |
| 637 } | 638 } |
| 638 | 639 |
| 639 // Get a pointer to the decompress info since we will use it quite frequentl
y | 640 // Get a pointer to the decompress info since we will use it quite frequentl
y |
| 640 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); | 641 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); |
| 641 | 642 |
| 642 dinfo->raw_data_out = TRUE; | 643 dinfo->raw_data_out = TRUE; |
| 643 if (!jpeg_start_decompress(dinfo)) { | 644 if (!jpeg_start_decompress(dinfo)) { |
| 644 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); | 645 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); |
| 645 } | 646 } |
| 646 | 647 |
| 647 // A previous implementation claims that the return value of is_yuv_supporte
d() | 648 // A previous implementation claims that the return value of is_yuv_supporte
d() |
| 648 // may change after calling jpeg_start_decompress(). It looks to me like th
is | 649 // may change after calling jpeg_start_decompress(). It looks to me like th
is |
| 649 // was caused by a bug in the old code, but we'll be safe and check here. | 650 // was caused by a bug in the old code, but we'll be safe and check here. |
| 650 SkASSERT(is_yuv_supported(dinfo)); | 651 SkASSERT(is_yuv_supported(dinfo)); |
| 651 | 652 |
| 652 // Currently, we require that the Y plane dimensions match the image dimensi
ons | 653 // Currently, we require that the Y plane dimensions match the image dimensi
ons |
| 653 // and that the U and V planes are the same dimensions. | 654 // and that the U and V planes are the same dimensions. |
| 654 SkASSERT(sizeInfo.fUSize == sizeInfo.fVSize); | 655 SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kU] == sizeInfo.fSizes[SkYUVSizeInfo
::kV]); |
| 655 SkASSERT((uint32_t) sizeInfo.fYSize.width() == dinfo->output_width && | 656 SkASSERT((uint32_t) sizeInfo.fSizes[SkYUVSizeInfo::kY].width() == dinfo->out
put_width && |
| 656 (uint32_t) sizeInfo.fYSize.height() == dinfo->output_height); | 657 (uint32_t) sizeInfo.fSizes[SkYUVSizeInfo::kY].height() == dinfo->out
put_height); |
| 657 | 658 |
| 658 // Build a JSAMPIMAGE to handle output from libjpeg-turbo. A JSAMPIMAGE has | 659 // Build a JSAMPIMAGE to handle output from libjpeg-turbo. A JSAMPIMAGE has |
| 659 // a 2-D array of pixels for each of the components (Y, U, V) in the image. | 660 // a 2-D array of pixels for each of the components (Y, U, V) in the image. |
| 660 // Cheat Sheet: | 661 // Cheat Sheet: |
| 661 // JSAMPIMAGE == JSAMPLEARRAY* == JSAMPROW** == JSAMPLE*** | 662 // JSAMPIMAGE == JSAMPLEARRAY* == JSAMPROW** == JSAMPLE*** |
| 662 JSAMPARRAY yuv[3]; | 663 JSAMPARRAY yuv[3]; |
| 663 | 664 |
| 664 // Set aside enough space for pointers to rows of Y, U, and V. | 665 // Set aside enough space for pointers to rows of Y, U, and V. |
| 665 JSAMPROW rowptrs[2 * DCTSIZE + DCTSIZE + DCTSIZE]; | 666 JSAMPROW rowptrs[2 * DCTSIZE + DCTSIZE + DCTSIZE]; |
| 666 yuv[0] = &rowptrs[0]; // Y rows (DCTSIZE or 2 * DCTSIZE) | 667 yuv[0] = &rowptrs[0]; // Y rows (DCTSIZE or 2 * DCTSIZE) |
| 667 yuv[1] = &rowptrs[2 * DCTSIZE]; // U rows (DCTSIZE) | 668 yuv[1] = &rowptrs[2 * DCTSIZE]; // U rows (DCTSIZE) |
| 668 yuv[2] = &rowptrs[3 * DCTSIZE]; // V rows (DCTSIZE) | 669 yuv[2] = &rowptrs[3 * DCTSIZE]; // V rows (DCTSIZE) |
| 669 | 670 |
| 670 // Initialize rowptrs. | 671 // Initialize rowptrs. |
| 671 int numYRowsPerBlock = DCTSIZE * dinfo->comp_info[0].v_samp_factor; | 672 int numYRowsPerBlock = DCTSIZE * dinfo->comp_info[0].v_samp_factor; |
| 672 for (int i = 0; i < numYRowsPerBlock; i++) { | 673 for (int i = 0; i < numYRowsPerBlock; i++) { |
| 673 rowptrs[i] = SkTAddOffset<JSAMPLE>(pixels[0], i * sizeInfo.fYWidthBytes)
; | 674 rowptrs[i] = SkTAddOffset<JSAMPLE>(planes[SkYUVSizeInfo::kY], |
| 675 i * sizeInfo.fWidthBytes[SkYUVSizeInfo::kY]); |
| 674 } | 676 } |
| 675 for (int i = 0; i < DCTSIZE; i++) { | 677 for (int i = 0; i < DCTSIZE; i++) { |
| 676 rowptrs[i + 2 * DCTSIZE] = SkTAddOffset<JSAMPLE>(pixels[1], i * sizeInfo
.fUWidthBytes); | 678 rowptrs[i + 2 * DCTSIZE] = SkTAddOffset<JSAMPLE>(planes[SkYUVSizeInfo::k
U], |
| 677 rowptrs[i + 3 * DCTSIZE] = SkTAddOffset<JSAMPLE>(pixels[2], i * sizeInfo
.fVWidthBytes); | 679 i * sizeInfo.fWidthBytes[SkYUVSizeInfo::kU]); |
| 680 rowptrs[i + 3 * DCTSIZE] = SkTAddOffset<JSAMPLE>(planes[SkYUVSizeInfo::k
V], |
| 681 i * sizeInfo.fWidthBytes[SkYUVSizeInfo::kV]); |
| 678 } | 682 } |
| 679 | 683 |
| 680 // After each loop iteration, we will increment pointers to Y, U, and V. | 684 // After each loop iteration, we will increment pointers to Y, U, and V. |
| 681 size_t blockIncrementY = numYRowsPerBlock * sizeInfo.fYWidthBytes; | 685 size_t blockIncrementY = numYRowsPerBlock * sizeInfo.fWidthBytes[SkYUVSizeIn
fo::kY]; |
| 682 size_t blockIncrementU = DCTSIZE * sizeInfo.fUWidthBytes; | 686 size_t blockIncrementU = DCTSIZE * sizeInfo.fWidthBytes[SkYUVSizeInfo::kU]; |
| 683 size_t blockIncrementV = DCTSIZE * sizeInfo.fVWidthBytes; | 687 size_t blockIncrementV = DCTSIZE * sizeInfo.fWidthBytes[SkYUVSizeInfo::kV]; |
| 684 | 688 |
| 685 uint32_t numRowsPerBlock = numYRowsPerBlock; | 689 uint32_t numRowsPerBlock = numYRowsPerBlock; |
| 686 | 690 |
| 687 // We intentionally round down here, as this first loop will only handle | 691 // We intentionally round down here, as this first loop will only handle |
| 688 // full block rows. As a special case at the end, we will handle any | 692 // full block rows. As a special case at the end, we will handle any |
| 689 // remaining rows that do not make up a full block. | 693 // remaining rows that do not make up a full block. |
| 690 const int numIters = dinfo->output_height / numRowsPerBlock; | 694 const int numIters = dinfo->output_height / numRowsPerBlock; |
| 691 for (int i = 0; i < numIters; i++) { | 695 for (int i = 0; i < numIters; i++) { |
| 692 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock); | 696 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock); |
| 693 if (linesRead < numRowsPerBlock) { | 697 if (linesRead < numRowsPerBlock) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 706 } | 710 } |
| 707 | 711 |
| 708 uint32_t remainingRows = dinfo->output_height - dinfo->output_scanline; | 712 uint32_t remainingRows = dinfo->output_height - dinfo->output_scanline; |
| 709 SkASSERT(remainingRows == dinfo->output_height % numRowsPerBlock); | 713 SkASSERT(remainingRows == dinfo->output_height % numRowsPerBlock); |
| 710 SkASSERT(dinfo->output_scanline == numIters * numRowsPerBlock); | 714 SkASSERT(dinfo->output_scanline == numIters * numRowsPerBlock); |
| 711 if (remainingRows > 0) { | 715 if (remainingRows > 0) { |
| 712 // libjpeg-turbo needs memory to be padded by the block sizes. We will
fulfill | 716 // libjpeg-turbo needs memory to be padded by the block sizes. We will
fulfill |
| 713 // this requirement using a dummy row buffer. | 717 // this requirement using a dummy row buffer. |
| 714 // FIXME: Should SkCodec have an extra memory buffer that can be shared
among | 718 // FIXME: Should SkCodec have an extra memory buffer that can be shared
among |
| 715 // all of the implementations that use temporary/garbage memory? | 719 // all of the implementations that use temporary/garbage memory? |
| 716 SkAutoTMalloc<JSAMPLE> dummyRow(sizeInfo.fYWidthBytes); | 720 SkAutoTMalloc<JSAMPLE> dummyRow(sizeInfo.fWidthBytes[SkYUVSizeInfo::kY])
; |
| 717 for (int i = remainingRows; i < numYRowsPerBlock; i++) { | 721 for (int i = remainingRows; i < numYRowsPerBlock; i++) { |
| 718 rowptrs[i] = dummyRow.get(); | 722 rowptrs[i] = dummyRow.get(); |
| 719 } | 723 } |
| 720 int remainingUVRows = dinfo->comp_info[1].downsampled_height - DCTSIZE *
numIters; | 724 int remainingUVRows = dinfo->comp_info[1].downsampled_height - DCTSIZE *
numIters; |
| 721 for (int i = remainingUVRows; i < DCTSIZE; i++) { | 725 for (int i = remainingUVRows; i < DCTSIZE; i++) { |
| 722 rowptrs[i + 2 * DCTSIZE] = dummyRow.get(); | 726 rowptrs[i + 2 * DCTSIZE] = dummyRow.get(); |
| 723 rowptrs[i + 3 * DCTSIZE] = dummyRow.get(); | 727 rowptrs[i + 3 * DCTSIZE] = dummyRow.get(); |
| 724 } | 728 } |
| 725 | 729 |
| 726 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock); | 730 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock); |
| 727 if (linesRead < remainingRows) { | 731 if (linesRead < remainingRows) { |
| 728 // FIXME: Handle incomplete YUV decodes without signalling an error. | 732 // FIXME: Handle incomplete YUV decodes without signalling an error. |
| 729 return kInvalidInput; | 733 return kInvalidInput; |
| 730 } | 734 } |
| 731 } | 735 } |
| 732 | 736 |
| 733 return kSuccess; | 737 return kSuccess; |
| 734 } | 738 } |
| OLD | NEW |