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 |