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 |