Reland "heif: Add AVIF type and AVIF sniffing"
This is a reland of 3ab5b73649554934a2ef23f3682c2a1e5487e1c3
Fix: Chromium does not use the heif decoder. So hide it behind
an ifdef.
Original change's description:
> heif: Add AVIF type and AVIF sniffing
>
> AVIF is the image format based on the AV1 video codec. The
> container for AVIF is very similar to that of HEIF. Add type
> definitions for AVIF and sniffing code for detecting AVIF images.
>
> The underlying android platform's HEIF decoder implementation will
> also support AVIF decoding.
>
> Bug: b/141654151
> Change-Id: I7e31f4cedf0bffb8920ddf880a26601e48d0e833
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/330059
> Reviewed-by: Leon Scroggins <scroggo@google.com>
> Reviewed-by: Derek Sollenberger <djsollen@google.com>
> Reviewed-by: Chong Zhang <chz@google.com>
> Commit-Queue: Leon Scroggins <scroggo@google.com>
Bug: b/141654151
Change-Id: Ie6840d6fc97789be619924fc60df8683cd58430f
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/331496
Reviewed-by: Derek Sollenberger <djsollen@google.com>
Reviewed-by: Leon Scroggins <scroggo@google.com>
Commit-Queue: Leon Scroggins <scroggo@google.com>
diff --git a/src/codec/SkHeifCodec.cpp b/src/codec/SkHeifCodec.cpp
index 3627a7b..2813c0e 100644
--- a/src/codec/SkHeifCodec.cpp
+++ b/src/codec/SkHeifCodec.cpp
@@ -18,11 +18,11 @@
#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.
+std::optional<SkEncodedImageFormat> SkHeifCodec::IsSupported(const void* buffer, size_t bytesRead) {
+ // Parse the ftyp box up to bytesRead to determine if this is HEIF or AVIF.
// Any valid ftyp box should have at least 8 bytes.
if (bytesRead < 8) {
- return false;
+ return std::nullopt;
}
uint32_t* ptr = (uint32_t*)buffer;
@@ -30,7 +30,7 @@
uint32_t chunkType = SkEndian_SwapBE32(ptr[1]);
if (chunkType != FOURCC('f', 't', 'y', 'p')) {
- return false;
+ return std::nullopt;
}
int64_t offset = 8;
@@ -38,18 +38,18 @@
// This indicates that the next 8 bytes represent the chunk size,
// and chunk data comes after that.
if (bytesRead < 16) {
- return false;
+ return std::nullopt;
}
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;
+ return std::nullopt;
}
offset += 8;
} else if (chunkSize < 8) {
// The smallest valid chunk is 8 bytes long.
- return false;
+ return std::nullopt;
}
if (chunkSize > bytesRead) {
@@ -59,10 +59,11 @@
// 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;
+ return std::nullopt;
}
uint32_t numCompatibleBrands = (chunkDataSize - 8) / 4;
+ bool isHeif = false;
for (size_t i = 0; i < numCompatibleBrands + 2; ++i) {
if (i == 1) {
// Skip this index, it refers to the minorVersion,
@@ -72,11 +73,23 @@
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')
- || brand == FOURCC('m', 's', 'f', '1') || brand == FOURCC('h', 'e', 'v', 'c')) {
- return true;
+ || brand == FOURCC('m', 's', 'f', '1') || brand == FOURCC('h', 'e', 'v', 'c')
+ || brand == FOURCC('a', 'v', 'i', 'f') || brand == FOURCC('a', 'v', 'i', 's')) {
+ // AVIF files could have "mif1" as the major brand. So we cannot
+ // distinguish whether the image is AVIF or HEIC just based on the
+ // "mif1" brand. So wait until we see a specific avif brand to
+ // determine whether it is AVIF or HEIC.
+ isHeif = true;
+ if (brand == FOURCC('a', 'v', 'i', 'f')
+ || brand == FOURCC('a', 'v', 'i', 's')) {
+ return SkEncodedImageFormat::kAVIF;
+ }
}
}
- return false;
+ if (isHeif) {
+ return SkEncodedImageFormat::kHEIF;
+ }
+ return std::nullopt;
}
static SkEncodedOrigin get_orientation(const HeifFrameInfo& frameInfo) {
@@ -123,7 +136,7 @@
}
std::unique_ptr<SkCodec> SkHeifCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
- SkCodec::SelectionPolicy selectionPolicy, Result* result) {
+ SkCodec::SelectionPolicy selectionPolicy, SkEncodedImageFormat format, Result* result) {
std::unique_ptr<HeifDecoder> heifDecoder(createHeifDecoder());
if (heifDecoder == nullptr) {
*result = kInternalError;
@@ -162,19 +175,21 @@
*result = kSuccess;
return std::unique_ptr<SkCodec>(new SkHeifCodec(
- std::move(info), heifDecoder.release(), orientation, frameCount > 1));
+ std::move(info), heifDecoder.release(), orientation, frameCount > 1, format));
}
SkHeifCodec::SkHeifCodec(
SkEncodedInfo&& info,
HeifDecoder* heifDecoder,
SkEncodedOrigin origin,
- bool useAnimation)
+ bool useAnimation,
+ SkEncodedImageFormat format)
: INHERITED(std::move(info), skcms_PixelFormat_RGBA_8888, nullptr, origin)
, fHeifDecoder(heifDecoder)
, fSwizzleSrcRow(nullptr)
, fColorXformSrcRow(nullptr)
, fUseAnimation(useAnimation)
+ , fFormat(format)
{}
bool SkHeifCodec::conversionSupported(const SkImageInfo& dstInfo, bool srcIsOpaque,