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