/* * Copyright 2022 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "src/codec/SkAvifCodec.h" #include "include/codec/SkAvifDecoder.h" #include "include/codec/SkCodec.h" #include "include/codec/SkCodecAnimation.h" #include "include/core/SkColorType.h" #include "include/core/SkImageInfo.h" #include "include/core/SkSize.h" #include "include/core/SkStream.h" #include "include/core/SkTypes.h" #include "modules/skcms/skcms.h" #include "src/core/SkStreamPriv.h" #include #include #include #include "avif/avif.h" void AvifDecoderDeleter::operator()(avifDecoder* decoder) const { if (decoder != nullptr) { avifDecoderDestroy(decoder); } } bool SkAvifCodec::IsAvif(const void* buffer, size_t bytesRead) { avifROData avifData = {static_cast(buffer), bytesRead}; bool isAvif = avifPeekCompatibleFileType(&avifData) == AVIF_TRUE; if (isAvif) return true; // Peeking sometimes fails if the ftyp box is too large. Check the signature // just to be sure. const char* bytes = static_cast(buffer); isAvif = bytesRead >= 12 && !memcmp(&bytes[4], "ftyp", 4) && (!memcmp(&bytes[8], "avif", 4) || !memcmp(&bytes[8], "avis", 4)); return isAvif; } std::unique_ptr SkAvifCodec::MakeFromStream(std::unique_ptr stream, Result* result) { SkASSERT(result); if (!stream) { *result = SkCodec::kInvalidInput; return nullptr; } AvifDecoder avifDecoder(avifDecoderCreate()); if (avifDecoder == nullptr) { *result = SkCodec::kInternalError; return nullptr; } avifDecoder->ignoreXMP = AVIF_TRUE; avifDecoder->ignoreExif = AVIF_TRUE; avifDecoder->allowProgressive = AVIF_FALSE; avifDecoder->allowIncremental = AVIF_FALSE; avifDecoder->strictFlags = AVIF_STRICT_DISABLED; // TODO(vigneshv): Enable threading based on number of CPU cores available. avifDecoder->maxThreads = 1; // libavif needs a contiguous data buffer. sk_sp data = nullptr; if (stream->getMemoryBase()) { // It is safe to make without copy because we'll hold onto the stream. data = SkData::MakeWithoutCopy(stream->getMemoryBase(), stream->getLength()); } else { data = SkCopyStreamToData(stream.get()); // If we are forced to copy the stream to a data, we can go ahead and // delete the stream. stream.reset(nullptr); } avifResult res = avifDecoderSetIOMemory(avifDecoder.get(), data->bytes(), data->size()); if (res != AVIF_RESULT_OK) { *result = SkCodec::kInternalError; return nullptr; } res = avifDecoderParse(avifDecoder.get()); if (res != AVIF_RESULT_OK) { *result = SkCodec::kInvalidInput; return nullptr; } std::unique_ptr profile = nullptr; // TODO(vigneshv): Get ICC Profile from the avif decoder. const int bitsPerComponent = avifDecoder->image->depth > 8 ? 16 : 8; SkEncodedInfo::Color color; SkEncodedInfo::Alpha alpha; if (avifDecoder->alphaPresent) { color = SkEncodedInfo::kRGBA_Color; alpha = SkEncodedInfo::kUnpremul_Alpha; } else { color = SkEncodedInfo::kRGB_Color; alpha = SkEncodedInfo::kOpaque_Alpha; } SkEncodedInfo info = SkEncodedInfo::Make(avifDecoder->image->width, avifDecoder->image->height, color, alpha, bitsPerComponent, std::move(profile), avifDecoder->image->depth); bool animation = avifDecoder->imageCount > 1; *result = kSuccess; return std::unique_ptr(new SkAvifCodec(std::move(info), std::move(stream), std::move(data), std::move(avifDecoder), kDefault_SkEncodedOrigin, animation)); } SkAvifCodec::SkAvifCodec(SkEncodedInfo&& info, std::unique_ptr stream, sk_sp data, AvifDecoder avifDecoder, SkEncodedOrigin origin, bool useAnimation) : INHERITED(std::move(info), skcms_PixelFormat_RGBA_8888, std::move(stream), origin) , fData(std::move(data)) , fAvifDecoder(std::move(avifDecoder)) , fUseAnimation(useAnimation) {} int SkAvifCodec::onGetFrameCount() { if (!fUseAnimation) { return 1; } if (fFrameHolder.size() == 0) { if (fAvifDecoder->imageCount <= 1) { fUseAnimation = false; return 1; } fFrameHolder.reserve(fAvifDecoder->imageCount); for (int i = 0; i < fAvifDecoder->imageCount; i++) { Frame* frame = fFrameHolder.appendNewFrame(fAvifDecoder->alphaPresent == AVIF_TRUE); frame->setXYWH(0, 0, fAvifDecoder->image->width, fAvifDecoder->image->height); frame->setDisposalMethod(SkCodecAnimation::DisposalMethod::kKeep); avifImageTiming timing; avifDecoderNthImageTiming(fAvifDecoder.get(), i, &timing); frame->setDuration(timing.duration * 1000); frame->setRequiredFrame(SkCodec::kNoFrame); frame->setHasAlpha(fAvifDecoder->alphaPresent == AVIF_TRUE); } } return fFrameHolder.size(); } const SkFrame* SkAvifCodec::FrameHolder::onGetFrame(int i) const { return static_cast(this->frame(i)); } SkAvifCodec::Frame* SkAvifCodec::FrameHolder::appendNewFrame(bool hasAlpha) { const int i = this->size(); fFrames.emplace_back(i, hasAlpha ? SkEncodedInfo::kUnpremul_Alpha : SkEncodedInfo::kOpaque_Alpha); return &fFrames[i]; } const SkAvifCodec::Frame* SkAvifCodec::FrameHolder::frame(int i) const { SkASSERT(i >= 0 && i < this->size()); return &fFrames[i]; } bool SkAvifCodec::onGetFrameInfo(int i, FrameInfo* frameInfo) const { if (i >= fFrameHolder.size()) { return false; } const Frame* frame = fFrameHolder.frame(i); if (!frame) { return false; } if (frameInfo) { frame->fillIn(frameInfo, true); } return true; } int SkAvifCodec::onGetRepetitionCount() { return kRepetitionCountInfinite; } SkCodec::Result SkAvifCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& options, int* rowsDecoded) { if (options.fSubset) { return kUnimplemented; } const SkColorType dstColorType = dstInfo.colorType(); if (dstColorType != kRGBA_8888_SkColorType && dstColorType != kRGBA_F16_SkColorType) { // TODO(vigneshv): Check if more color types need to be supported. // Currently android supports at least RGB565 and BGRA8888 which is not // supported here. return kUnimplemented; } avifResult result = avifDecoderNthImage(fAvifDecoder.get(), options.fFrameIndex); if (result != AVIF_RESULT_OK) { return kInvalidInput; } if (this->dimensions() != dstInfo.dimensions()) { result = avifImageScale( fAvifDecoder->image, dstInfo.width(), dstInfo.height(), &fAvifDecoder->diag); if (result != AVIF_RESULT_OK) { return kInvalidInput; } } avifRGBImage rgbImage; avifRGBImageSetDefaults(&rgbImage, fAvifDecoder->image); if (dstColorType == kRGBA_8888_SkColorType) { rgbImage.depth = 8; } else if (dstColorType == kRGBA_F16_SkColorType) { rgbImage.depth = 16; rgbImage.isFloat = AVIF_TRUE; } rgbImage.pixels = static_cast(dst); rgbImage.rowBytes = dstRowBytes; rgbImage.chromaUpsampling = AVIF_CHROMA_UPSAMPLING_FASTEST; result = avifImageYUVToRGB(fAvifDecoder->image, &rgbImage); if (result != AVIF_RESULT_OK) { return kInvalidInput; } *rowsDecoded = fAvifDecoder->image->height; return kSuccess; } namespace SkAvifDecoder { namespace LibAvif { bool IsAvif(const void* data, size_t len) { return SkAvifCodec::IsAvif(data, len); } std::unique_ptr Decode(std::unique_ptr stream, SkCodec::Result* outResult, SkCodecs::DecodeContext) { SkCodec::Result resultStorage; if (!outResult) { outResult = &resultStorage; } return SkAvifCodec::MakeFromStream(std::move(stream), outResult); } std::unique_ptr Decode(sk_sp data, SkCodec::Result* outResult, SkCodecs::DecodeContext) { if (!data) { if (outResult) { *outResult = SkCodec::kInvalidInput; } return nullptr; } return Decode(SkMemoryStream::Make(std::move(data)), outResult, nullptr); } } // namespace LibAvif } // namespace SkAvifDecoder