diff options
author | Mike Klein <mtklein@google.com> | 2017-08-17 13:33:56 +0000 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-08-17 13:34:07 +0000 |
commit | db68a426b6ba3a0fa1cace25ac306037eb7413a6 (patch) | |
tree | 6a928b31410abb8d866ed8c5289d7243e5020155 /src/codec | |
parent | be1b071753538584c34257ce6eb17dcb78ef7d35 (diff) |
Revert "skia: add heif decoding support"
This reverts commit c2a954290dc3888f877a047098b84c24363895fb.
Reason for revert: both Android and Google3 rolls cannot compile. Android cannot cast std::unique_ptr<T> to T*, Google3 cannot find HeifDecoderAPI.h.
Original change's description:
> skia: add heif decoding support
>
> Bug: b/64077740
> Change-Id: I11e0243bcc4c21c0aa5aa29a719dd0fcba7ae6f7
> Reviewed-on: https://skia-review.googlesource.com/35123
> Reviewed-by: Chong Zhang <chz@google.com>
> Reviewed-by: Leon Scroggins <scroggo@google.com>
> Commit-Queue: Chong Zhang <chz@google.com>
> Commit-Queue: Leon Scroggins <scroggo@google.com>
TBR=scroggo@google.com,chz@google.com
Change-Id: Id98f025e63daec50408186000453d1695170f7a8
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: b/64077740
Reviewed-on: https://skia-review.googlesource.com/35741
Reviewed-by: Mike Klein <mtklein@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
Diffstat (limited to 'src/codec')
-rw-r--r-- | src/codec/SkAndroidCodec.cpp | 3 | ||||
-rw-r--r-- | src/codec/SkCodec.cpp | 14 | ||||
-rw-r--r-- | src/codec/SkHeifCodec.cpp | 397 | ||||
-rw-r--r-- | src/codec/SkHeifCodec.h | 108 | ||||
-rw-r--r-- | src/codec/SkWebpCodec.h | 2 |
5 files changed, 10 insertions, 514 deletions
diff --git a/src/codec/SkAndroidCodec.cpp b/src/codec/SkAndroidCodec.cpp index 3bf69053ea..3a57352113 100644 --- a/src/codec/SkAndroidCodec.cpp +++ b/src/codec/SkAndroidCodec.cpp @@ -83,9 +83,6 @@ std::unique_ptr<SkAndroidCodec> SkAndroidCodec::MakeFromStream(std::unique_ptr<S case SkEncodedImageFormat::kGIF: case SkEncodedImageFormat::kBMP: case SkEncodedImageFormat::kWBMP: -#ifdef SK_HAS_HEIF_LIBRARY - case SkEncodedImageFormat::kHEIF: -#endif return skstd::make_unique<SkSampledCodec>(codec.release()); #ifdef SK_HAS_WEBP_LIBRARY case SkEncodedImageFormat::kWEBP: diff --git a/src/codec/SkCodec.cpp b/src/codec/SkCodec.cpp index 7dc10854d2..2b6108250c 100644 --- a/src/codec/SkCodec.cpp +++ b/src/codec/SkCodec.cpp @@ -23,7 +23,6 @@ #include "SkStream.h" #include "SkWbmpCodec.h" #include "SkWebpCodec.h" -#include "SkHeifCodec.h" struct DecoderProc { bool (*IsFormat)(const void*, size_t); @@ -42,12 +41,13 @@ static const DecoderProc gDecoderProcs[] = { { SkIcoCodec::IsIco, SkIcoCodec::MakeFromStream }, #endif { SkBmpCodec::IsBmp, SkBmpCodec::MakeFromStream }, - { SkWbmpCodec::IsWbmp, SkWbmpCodec::MakeFromStream }, -#ifdef SK_HAS_HEIF_LIBRARY - { SkHeifCodec::IsHeif, SkHeifCodec::MakeFromStream }, -#endif + { SkWbmpCodec::IsWbmp, SkWbmpCodec::MakeFromStream } }; +size_t SkCodec::MinBufferedBytesNeeded() { + return WEBP_VP8_HEADER_SIZE; +} + std::unique_ptr<SkCodec> SkCodec::MakeFromStream(std::unique_ptr<SkStream> stream, Result* outResult, SkPngChunkReader* chunkReader) { Result resultStorage; @@ -60,7 +60,9 @@ std::unique_ptr<SkCodec> SkCodec::MakeFromStream(std::unique_ptr<SkStream> strea return nullptr; } - constexpr size_t bytesToRead = MinBufferedBytesNeeded(); + // 14 is enough to read all of the supported types. + const size_t bytesToRead = 14; + SkASSERT(bytesToRead <= MinBufferedBytesNeeded()); char buffer[bytesToRead]; size_t bytesRead = stream->peek(buffer, bytesToRead); diff --git a/src/codec/SkHeifCodec.cpp b/src/codec/SkHeifCodec.cpp deleted file mode 100644 index aea3ef0745..0000000000 --- a/src/codec/SkHeifCodec.cpp +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Copyright 2017 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkCodec.h" -#include "SkCodecPriv.h" -#include "SkColorPriv.h" -#include "SkColorSpace_Base.h" -#include "SkStream.h" -#include "SkTypes.h" -#include "SkHeifCodec.h" -#include "SkEndian.h" -#include "HeifDecoderAPI.h" - -#define FOURCC(c1, c2, c3, c4) \ - ((c1) << 24 | (c2) << 16 | (c3) << 8 | (c4)) - -bool SkHeifCodec::IsHeif(const void* buffer, size_t bytesRead) { - // Parse the ftyp box up to bytesRead to determine if this is HEIF. - // Any valid ftyp box should have at least 8 bytes. - if (bytesRead < 8) { - return false; - } - - uint32_t* ptr = (uint32_t*)buffer; - uint64_t chunkSize = SkEndian_SwapBE32(ptr[0]); - uint32_t chunkType = SkEndian_SwapBE32(ptr[1]); - - if (chunkType != FOURCC('f', 't', 'y', 'p')) { - return false; - } - - off64_t offset = 8; - if (chunkSize == 1) { - // This indicates that the next 8 bytes represent the chunk size, - // and chunk data comes after that. - if (bytesRead < 16) { - return false; - } - auto* chunkSizePtr = SkTAddOffset<const uint64_t>(buffer, offset); - chunkSize = SkEndian_SwapBE64(*chunkSizePtr); - if (chunkSize < 16) { - // The smallest valid chunk is 16 bytes long in this case. - return false; - } - offset += 8; - } else if (chunkSize < 8) { - // The smallest valid chunk is 8 bytes long. - return false; - } - - if (chunkSize > bytesRead) { - chunkSize = bytesRead; - } - off64_t chunkDataSize = chunkSize - offset; - // It should at least have major brand (4-byte) and minor version (4-bytes). - // The rest of the chunk (if any) is a list of (4-byte) compatible brands. - if (chunkDataSize < 8) { - return false; - } - - uint32_t numCompatibleBrands = (chunkDataSize - 8) / 4; - for (size_t i = 0; i < numCompatibleBrands + 2; ++i) { - if (i == 1) { - // Skip this index, it refers to the minorVersion, - // not a brand. - continue; - } - auto* brandPtr = SkTAddOffset<const uint32_t>(buffer, offset + 4 * i); - uint32_t brand = SkEndian_SwapBE32(*brandPtr); - if (brand == FOURCC('m', 'i', 'f', '1') || brand == FOURCC('h', 'e', 'i', 'c')) { - return true; - } - } - return false; -} - -std::unique_ptr<SkCodec> SkHeifCodec::MakeFromStream( - std::unique_ptr<SkStream> stream, Result* result) { - SkCodec* codec = nullptr; - - *result = ReadHeader(stream, &codec); - if (kSuccess == *result) { - // Codec has taken ownership of the stream, we do not need to delete it - SkASSERT(codec); - stream.release(); - return codec; - } - return nullptr; -} - -static SkCodec::Origin get_orientation(const HeifFrameInfo& frameInfo) { - switch (frameInfo.mRotationAngle) { - case 0: return SkCodec::kTopLeft_Origin; - case 90: return SkCodec::kRightTop_Origin; - case 180: return SkCodec::kBottomRight_Origin; - case 270: return SkCodec::kLeftBottom_Origin; - } - return SkCodec::kDefault_Origin; -} - -struct SkHeifStreamWrapper : public HeifStream { - SkHeifStreamWrapper(SkStream* stream) : fStream(stream) {} - - ~SkHeifStreamWrapper() override {} - - size_t read(void* buffer, size_t size) override { - return fStream->read(buffer, size); - } - - bool rewind() override { - return fStream->rewind(); - } - - bool seek(size_t position) override { - return fStream->seek(position); - } - - bool hasLength() const override { - return fStream->hasLength(); - } - - size_t getLength() const override { - return fStream->getLength(); - } - -private: - std::unique_ptr<SkStream> fStream; -}; - -SkCodec::Result SkHeifCodec::ReadHeader(SkStream* stream, SkCodec** codecOut) { - std::unique_ptr<SkHeifStreamWrapper> streamWrapper( - new SkHeifStreamWrapper(stream)); - - SkASSERT(codecOut != nullptr); - - // Create a HeifDecoder to own all of the decode information - std::unique_ptr<HeifDecoder> heifDecoder(createHeifDecoder()); - if (heifDecoder.get() == nullptr) { - return kInternalError; - } - - // Initialize the decoder info and the source manager - HeifFrameInfo frameInfo; - if (!heifDecoder->init(streamWrapper.release(), &frameInfo)) { - return kInvalidInput; - } - - // Create image info object and the codec - SkEncodedInfo info = SkEncodedInfo::Make( - SkEncodedInfo::kYUV_Color, SkEncodedInfo::kOpaque_Alpha, 8); - - Origin orientation = get_orientation(frameInfo); - - sk_sp<SkColorSpace> colorSpace = nullptr; - if ((frameInfo.mIccSize > 0) && (frameInfo.mIccData != nullptr)) { - SkColorSpace_Base::ICCTypeFlag iccType = SkColorSpace_Base::kRGB_ICCTypeFlag; - colorSpace = SkColorSpace_Base::MakeICC( - frameInfo.mIccData.get(), frameInfo.mIccSize, iccType); - } - if (!colorSpace) { - colorSpace = SkColorSpace::MakeSRGB(); - } - - *codecOut = new SkHeifCodec(frameInfo.mWidth, frameInfo.mHeight, - info, heifDecoder.release(), std::move(colorSpace), orientation); - return kSuccess; -} - -SkHeifCodec::SkHeifCodec(int width, int height, const SkEncodedInfo& info, - HeifDecoder* heifDecoder, sk_sp<SkColorSpace> colorSpace, Origin origin) - : INHERITED(width, height, info, SkColorSpaceXform::kRGBA_8888_ColorFormat, - nullptr, std::move(colorSpace), origin) - , fHeifDecoder(heifDecoder) - , fFrameInfo(new HeifFrameInfo()) - , fSwizzleSrcRow(nullptr) - , fColorXformSrcRow(nullptr) - , fSwizzlerSubset(SkIRect::MakeEmpty()) -{} - -/* - * Checks if the conversion between the input image and the requested output - * image has been implemented - * Sets the output color format - */ -bool SkHeifCodec::setOutputColorFormat(const SkImageInfo& dstInfo) { - if (kUnknown_SkAlphaType == dstInfo.alphaType()) { - return false; - } - - if (kOpaque_SkAlphaType != dstInfo.alphaType()) { - SkCodecPrintf("Warning: an opaque image should be decoded as opaque " - "- it is being decoded as non-opaque, which will draw slower\n"); - } - - switch (dstInfo.colorType()) { - case kRGBA_8888_SkColorType: - return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888); - - case kBGRA_8888_SkColorType: - return fHeifDecoder->setOutputColor(kHeifColorFormat_BGRA_8888); - - case kRGB_565_SkColorType: - if (this->colorXform()) { - return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888); - } else { - return fHeifDecoder->setOutputColor(kHeifColorFormat_RGB565); - } - - case kRGBA_F16_SkColorType: - SkASSERT(this->colorXform()); - - if (!dstInfo.colorSpace()->gammaIsLinear()) { - return false; - } - return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888); - - default: - return false; - } -} - -int SkHeifCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count, - const Options& opts) { - // When fSwizzleSrcRow is non-null, it means that we need to swizzle. In this case, - // we will always decode into fSwizzlerSrcRow before swizzling into the next buffer. - // We can never swizzle "in place" because the swizzler may perform sampling and/or - // subsetting. - // When fColorXformSrcRow is non-null, it means that we need to color xform and that - // we cannot color xform "in place" (many times we can, but not when the dst is F16). - // In this case, we will color xform from fColorXformSrcRow into the dst. - uint8_t* decodeDst = (uint8_t*) dst; - uint32_t* swizzleDst = (uint32_t*) dst; - size_t decodeDstRowBytes = rowBytes; - size_t swizzleDstRowBytes = rowBytes; - int dstWidth = opts.fSubset ? opts.fSubset->width() : dstInfo.width(); - if (fSwizzleSrcRow && fColorXformSrcRow) { - decodeDst = fSwizzleSrcRow; - swizzleDst = fColorXformSrcRow; - decodeDstRowBytes = 0; - swizzleDstRowBytes = 0; - dstWidth = fSwizzler->swizzleWidth(); - } else if (fColorXformSrcRow) { - decodeDst = (uint8_t*) fColorXformSrcRow; - swizzleDst = fColorXformSrcRow; - decodeDstRowBytes = 0; - swizzleDstRowBytes = 0; - } else if (fSwizzleSrcRow) { - decodeDst = fSwizzleSrcRow; - decodeDstRowBytes = 0; - dstWidth = fSwizzler->swizzleWidth(); - } - - for (int y = 0; y < count; y++) { - if (!fHeifDecoder->getScanline(decodeDst)) { - return y; - } - - if (fSwizzler) { - fSwizzler->swizzle(swizzleDst, decodeDst); - } - - if (this->colorXform()) { - this->applyColorXform(dst, swizzleDst, dstWidth, kOpaque_SkAlphaType); - dst = SkTAddOffset<void>(dst, rowBytes); - } - - decodeDst = SkTAddOffset<uint8_t>(decodeDst, decodeDstRowBytes); - swizzleDst = SkTAddOffset<uint32_t>(swizzleDst, swizzleDstRowBytes); - } - - return count; -} - -/* - * Performs the heif decode - */ -SkCodec::Result SkHeifCodec::onGetPixels(const SkImageInfo& dstInfo, - void* dst, size_t dstRowBytes, - const Options& options, - int* rowsDecoded) { - if (options.fSubset) { - // Not supporting subsets on this path for now. - // TODO: if the heif has tiles, we can support subset here, but - // need to retrieve tile config from metadata retriever first. - return kUnimplemented; - } - - if (!this->initializeColorXform(dstInfo, options.fPremulBehavior)) { - return kInvalidConversion; - } - - // Check if we can decode to the requested destination and set the output color space - if (!this->setOutputColorFormat(dstInfo)) { - return kInvalidConversion; - } - - if (!fHeifDecoder->decode(fFrameInfo.get())) { - return kInvalidInput; - } - - this->allocateStorage(dstInfo); - - int rows = this->readRows(dstInfo, dst, dstRowBytes, dstInfo.height(), options); - if (rows < dstInfo.height()) { - *rowsDecoded = rows; - return kIncompleteInput; - } - - return kSuccess; -} - -void SkHeifCodec::allocateStorage(const SkImageInfo& dstInfo) { - int dstWidth = dstInfo.width(); - - size_t swizzleBytes = 0; - if (fSwizzler) { - swizzleBytes = fFrameInfo->mBytesPerPixel * fFrameInfo->mWidth; - dstWidth = fSwizzler->swizzleWidth(); - SkASSERT(!this->colorXform() || SkIsAlign4(swizzleBytes)); - } - - size_t xformBytes = 0; - if (this->colorXform() && (kRGBA_F16_SkColorType == dstInfo.colorType() || - kRGB_565_SkColorType == dstInfo.colorType())) { - xformBytes = dstWidth * sizeof(uint32_t); - } - - size_t totalBytes = swizzleBytes + xformBytes; - fStorage.reset(totalBytes); - if (totalBytes > 0) { - fSwizzleSrcRow = (swizzleBytes > 0) ? fStorage.get() : nullptr; - fColorXformSrcRow = (xformBytes > 0) ? - SkTAddOffset<uint32_t>(fStorage.get(), swizzleBytes) : nullptr; - } -} - -void SkHeifCodec::initializeSwizzler( - const SkImageInfo& dstInfo, const Options& options) { - SkEncodedInfo swizzlerInfo = this->getEncodedInfo(); - - SkImageInfo swizzlerDstInfo = dstInfo; - if (this->colorXform()) { - // The color xform will be expecting RGBA 8888 input. - swizzlerDstInfo = swizzlerDstInfo.makeColorType(kRGBA_8888_SkColorType); - } - - fSwizzler.reset(SkSwizzler::CreateSwizzler(swizzlerInfo, nullptr, - swizzlerDstInfo, options, nullptr, true)); - SkASSERT(fSwizzler); -} - -SkSampler* SkHeifCodec::getSampler(bool createIfNecessary) { - if (!createIfNecessary || fSwizzler) { - SkASSERT(!fSwizzler || (fSwizzleSrcRow && fStorage.get() == fSwizzleSrcRow)); - return fSwizzler.get(); - } - - this->initializeSwizzler(this->dstInfo(), this->options()); - this->allocateStorage(this->dstInfo()); - return fSwizzler.get(); -} - -SkCodec::Result SkHeifCodec::onStartScanlineDecode( - const SkImageInfo& dstInfo, const Options& options) { - if (!this->initializeColorXform(dstInfo, options.fPremulBehavior)) { - return kInvalidConversion; - } - - // Check if we can decode to the requested destination and set the output color space - if (!this->setOutputColorFormat(dstInfo)) { - return kInvalidConversion; - } - - // TODO: For now, just decode the whole thing even when there is a subset. - // If the heif image has tiles, we could potentially do this much faster, - // but the tile configuration needs to be retrieved from the metadata. - if (!fHeifDecoder->decode(fFrameInfo.get())) { - return kInvalidInput; - } - - this->allocateStorage(dstInfo); - - return kSuccess; -} - -int SkHeifCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) { - return this->readRows(this->dstInfo(), dst, dstRowBytes, count, this->options()); -} - -bool SkHeifCodec::onSkipScanlines(int count) { - return count == (int) fHeifDecoder->skipScanlines(count); -} - diff --git a/src/codec/SkHeifCodec.h b/src/codec/SkHeifCodec.h deleted file mode 100644 index dab1535b6b..0000000000 --- a/src/codec/SkHeifCodec.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2017 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkHeifCodec_DEFINED -#define SkHeifCodec_DEFINED - -#include "SkCodec.h" -#include "SkColorSpace.h" -#include "SkColorSpaceXform.h" -#include "SkImageInfo.h" -#include "SkSwizzler.h" -#include "SkStream.h" - -struct HeifFrameInfo; -struct HeifDecoder; - -/* - * - * This class implements the decoding for heif images. - * - */ -class SkHeifCodec : public SkCodec { -public: - static bool IsHeif(const void*, size_t); - - /* - * Assumes IsHeif was called and returned true. - * Creates a heif decoder and takes ownership of the stream. - */ - static std::unique_ptr<SkCodec> MakeFromStream(std::unique_ptr<SkStream>, Result*); - -protected: - - Result onGetPixels( - const SkImageInfo& dstInfo, - void* dst, size_t dstRowBytes, - const Options& options, - int* rowsDecoded) override; - - SkEncodedImageFormat onGetEncodedFormat() const override { - return SkEncodedImageFormat::kHEIF; - } - -private: - - /* - * Read enough of the stream to initialize the SkHeifCodec. - * Returns a bool representing success or failure. - * - * @param codecOut - * If this returns true, and codecOut was not nullptr, - * codecOut will be set to a new SkHeifCodec. - * - * @param stream - * Deleted on failure. - * codecOut will take ownership of it in the case where we created a codec. - */ - static Result ReadHeader(SkStream* stream, SkCodec** codecOut); - - /* - * Creates an instance of the decoder - * Called only by NewFromStream - */ - SkHeifCodec(int width, int height, const SkEncodedInfo&, - HeifDecoder*, sk_sp<SkColorSpace>, Origin); - - /* - * Checks if the conversion between the input image and the requested output - * image has been implemented. - * - * Sets the output color format. - */ - bool setOutputColorFormat(const SkImageInfo& dst); - - void initializeSwizzler(const SkImageInfo& dstInfo, const Options& options); - void allocateStorage(const SkImageInfo& dstInfo); - int readRows(const SkImageInfo& dstInfo, void* dst, - size_t rowBytes, int count, const Options&); - - /* - * Scanline decoding. - */ - SkSampler* getSampler(bool createIfNecessary) override; - Result onStartScanlineDecode(const SkImageInfo& dstInfo, - const Options& options) override; - int onGetScanlines(void* dst, int count, size_t rowBytes) override; - bool onSkipScanlines(int count) override; - - std::unique_ptr<HeifDecoder> fHeifDecoder; - std::unique_ptr<HeifFrameInfo> fFrameInfo; - SkAutoTMalloc<uint8_t> fStorage; - uint8_t* fSwizzleSrcRow; - uint32_t* fColorXformSrcRow; - - // In the case that heif decoder cannot take the exact the subset that - // we need, we will use the swizzler to further subset the output. - SkIRect fSwizzlerSubset; - - std::unique_ptr<SkSwizzler> fSwizzler; - - typedef SkCodec INHERITED; -}; - -#endif // SkHeifCodec_DEFINED diff --git a/src/codec/SkWebpCodec.h b/src/codec/SkWebpCodec.h index 134dafa3d5..60bff61220 100644 --- a/src/codec/SkWebpCodec.h +++ b/src/codec/SkWebpCodec.h @@ -23,6 +23,8 @@ extern "C" { void WebPDemuxDelete(WebPDemuxer* dmux); } +static const size_t WEBP_VP8_HEADER_SIZE = 30; + class SkWebpCodec final : public SkCodec { public: // Assumes IsWebp was called and returned true. |