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 |