1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2017 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/core/SkTypes.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#ifdef SK_HAS_HEIF_LIBRARY
11cb93a386Sopenharmony_ci#include "include/codec/SkCodec.h"
12cb93a386Sopenharmony_ci#include "include/core/SkStream.h"
13cb93a386Sopenharmony_ci#include "include/private/SkColorData.h"
14cb93a386Sopenharmony_ci#include "src/codec/SkCodecPriv.h"
15cb93a386Sopenharmony_ci#include "src/codec/SkHeifCodec.h"
16cb93a386Sopenharmony_ci#include "src/core/SkEndian.h"
17cb93a386Sopenharmony_ci
18cb93a386Sopenharmony_ci#if !defined(WIN32) && !defined(_WIN32) && !defined(__WIN32__)
19cb93a386Sopenharmony_ci#include <dlfcn.h>
20cb93a386Sopenharmony_ci#endif
21cb93a386Sopenharmony_ci
22cb93a386Sopenharmony_ci#define FOURCC(c1, c2, c3, c4) \
23cb93a386Sopenharmony_ci    ((c1) << 24 | (c2) << 16 | (c3) << 8 | (c4))
24cb93a386Sopenharmony_ci
25cb93a386Sopenharmony_ciconst static char *HEIF_IMPL_SO_NAME = "libheifimpl.z.so";
26cb93a386Sopenharmony_ci
27cb93a386Sopenharmony_cibool SkHeifCodec::IsSupported(const void* buffer, size_t bytesRead,
28cb93a386Sopenharmony_ci                              SkEncodedImageFormat* format) {
29cb93a386Sopenharmony_ci    // Parse the ftyp box up to bytesRead to determine if this is HEIF or AVIF.
30cb93a386Sopenharmony_ci    // Any valid ftyp box should have at least 8 bytes.
31cb93a386Sopenharmony_ci    if (bytesRead < 8) {
32cb93a386Sopenharmony_ci        return false;
33cb93a386Sopenharmony_ci    }
34cb93a386Sopenharmony_ci
35cb93a386Sopenharmony_ci    uint32_t* ptr = (uint32_t*)buffer;
36cb93a386Sopenharmony_ci    uint64_t chunkSize = SkEndian_SwapBE32(ptr[0]);
37cb93a386Sopenharmony_ci    uint32_t chunkType = SkEndian_SwapBE32(ptr[1]);
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_ci    if (chunkType != FOURCC('f', 't', 'y', 'p')) {
40cb93a386Sopenharmony_ci        return false;
41cb93a386Sopenharmony_ci    }
42cb93a386Sopenharmony_ci
43cb93a386Sopenharmony_ci    int64_t offset = 8;
44cb93a386Sopenharmony_ci    if (chunkSize == 1) {
45cb93a386Sopenharmony_ci        // This indicates that the next 8 bytes represent the chunk size,
46cb93a386Sopenharmony_ci        // and chunk data comes after that.
47cb93a386Sopenharmony_ci        if (bytesRead < 16) {
48cb93a386Sopenharmony_ci            return false;
49cb93a386Sopenharmony_ci        }
50cb93a386Sopenharmony_ci        auto* chunkSizePtr = SkTAddOffset<const uint64_t>(buffer, offset);
51cb93a386Sopenharmony_ci        chunkSize = SkEndian_SwapBE64(*chunkSizePtr);
52cb93a386Sopenharmony_ci        if (chunkSize < 16) {
53cb93a386Sopenharmony_ci            // The smallest valid chunk is 16 bytes long in this case.
54cb93a386Sopenharmony_ci            return false;
55cb93a386Sopenharmony_ci        }
56cb93a386Sopenharmony_ci        offset += 8;
57cb93a386Sopenharmony_ci    } else if (chunkSize < 8) {
58cb93a386Sopenharmony_ci        // The smallest valid chunk is 8 bytes long.
59cb93a386Sopenharmony_ci        return false;
60cb93a386Sopenharmony_ci    }
61cb93a386Sopenharmony_ci
62cb93a386Sopenharmony_ci    if (chunkSize > bytesRead) {
63cb93a386Sopenharmony_ci        chunkSize = bytesRead;
64cb93a386Sopenharmony_ci    }
65cb93a386Sopenharmony_ci    int64_t chunkDataSize = chunkSize - offset;
66cb93a386Sopenharmony_ci    // It should at least have major brand (4-byte) and minor version (4-bytes).
67cb93a386Sopenharmony_ci    // The rest of the chunk (if any) is a list of (4-byte) compatible brands.
68cb93a386Sopenharmony_ci    if (chunkDataSize < 8) {
69cb93a386Sopenharmony_ci        return false;
70cb93a386Sopenharmony_ci    }
71cb93a386Sopenharmony_ci
72cb93a386Sopenharmony_ci    uint32_t numCompatibleBrands = (chunkDataSize - 8) / 4;
73cb93a386Sopenharmony_ci    bool isHeif = false;
74cb93a386Sopenharmony_ci    for (size_t i = 0; i < numCompatibleBrands + 2; ++i) {
75cb93a386Sopenharmony_ci        if (i == 1) {
76cb93a386Sopenharmony_ci            // Skip this index, it refers to the minorVersion,
77cb93a386Sopenharmony_ci            // not a brand.
78cb93a386Sopenharmony_ci            continue;
79cb93a386Sopenharmony_ci        }
80cb93a386Sopenharmony_ci        auto* brandPtr = SkTAddOffset<const uint32_t>(buffer, offset + 4 * i);
81cb93a386Sopenharmony_ci        uint32_t brand = SkEndian_SwapBE32(*brandPtr);
82cb93a386Sopenharmony_ci        if (brand == FOURCC('m', 'i', 'f', '1') || brand == FOURCC('h', 'e', 'i', 'c')
83cb93a386Sopenharmony_ci         || brand == FOURCC('m', 's', 'f', '1') || brand == FOURCC('h', 'e', 'v', 'c')
84cb93a386Sopenharmony_ci         || brand == FOURCC('a', 'v', 'i', 'f') || brand == FOURCC('a', 'v', 'i', 's')) {
85cb93a386Sopenharmony_ci            // AVIF files could have "mif1" as the major brand. So we cannot
86cb93a386Sopenharmony_ci            // distinguish whether the image is AVIF or HEIC just based on the
87cb93a386Sopenharmony_ci            // "mif1" brand. So wait until we see a specific avif brand to
88cb93a386Sopenharmony_ci            // determine whether it is AVIF or HEIC.
89cb93a386Sopenharmony_ci            isHeif = true;
90cb93a386Sopenharmony_ci            if (brand == FOURCC('a', 'v', 'i', 'f')
91cb93a386Sopenharmony_ci              || brand == FOURCC('a', 'v', 'i', 's')) {
92cb93a386Sopenharmony_ci                if (format != nullptr) {
93cb93a386Sopenharmony_ci                    *format = SkEncodedImageFormat::kAVIF;
94cb93a386Sopenharmony_ci                }
95cb93a386Sopenharmony_ci                return true;
96cb93a386Sopenharmony_ci            }
97cb93a386Sopenharmony_ci        }
98cb93a386Sopenharmony_ci    }
99cb93a386Sopenharmony_ci    if (isHeif) {
100cb93a386Sopenharmony_ci        if (format != nullptr) {
101cb93a386Sopenharmony_ci            *format = SkEncodedImageFormat::kHEIF;
102cb93a386Sopenharmony_ci        }
103cb93a386Sopenharmony_ci        return true;
104cb93a386Sopenharmony_ci    }
105cb93a386Sopenharmony_ci    return false;
106cb93a386Sopenharmony_ci}
107cb93a386Sopenharmony_ci
108cb93a386Sopenharmony_cistatic SkEncodedOrigin get_orientation(const HeifFrameInfo& frameInfo) {
109cb93a386Sopenharmony_ci    switch (frameInfo.mRotationAngle) {
110cb93a386Sopenharmony_ci        case 0:   return kTopLeft_SkEncodedOrigin;
111cb93a386Sopenharmony_ci        case 90:  return kRightTop_SkEncodedOrigin;
112cb93a386Sopenharmony_ci        case 180: return kBottomRight_SkEncodedOrigin;
113cb93a386Sopenharmony_ci        case 270: return kLeftBottom_SkEncodedOrigin;
114cb93a386Sopenharmony_ci    }
115cb93a386Sopenharmony_ci    return kDefault_SkEncodedOrigin;
116cb93a386Sopenharmony_ci}
117cb93a386Sopenharmony_ci
118cb93a386Sopenharmony_cistruct SkHeifStreamWrapper : public HeifStream {
119cb93a386Sopenharmony_ci    SkHeifStreamWrapper(SkStream* stream) : fStream(stream) {}
120cb93a386Sopenharmony_ci
121cb93a386Sopenharmony_ci    ~SkHeifStreamWrapper() override {}
122cb93a386Sopenharmony_ci
123cb93a386Sopenharmony_ci    size_t read(void* buffer, size_t size) override {
124cb93a386Sopenharmony_ci        return fStream->read(buffer, size);
125cb93a386Sopenharmony_ci    }
126cb93a386Sopenharmony_ci
127cb93a386Sopenharmony_ci    bool rewind() override {
128cb93a386Sopenharmony_ci        return fStream->rewind();
129cb93a386Sopenharmony_ci    }
130cb93a386Sopenharmony_ci
131cb93a386Sopenharmony_ci    bool seek(size_t position) override {
132cb93a386Sopenharmony_ci        return fStream->seek(position);
133cb93a386Sopenharmony_ci    }
134cb93a386Sopenharmony_ci
135cb93a386Sopenharmony_ci    bool hasLength() const override {
136cb93a386Sopenharmony_ci        return fStream->hasLength();
137cb93a386Sopenharmony_ci    }
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_ci    size_t getLength() const override {
140cb93a386Sopenharmony_ci        return fStream->getLength();
141cb93a386Sopenharmony_ci    }
142cb93a386Sopenharmony_ci
143cb93a386Sopenharmony_ci    bool hasPosition() const override {
144cb93a386Sopenharmony_ci        return fStream->hasPosition();
145cb93a386Sopenharmony_ci    }
146cb93a386Sopenharmony_ci
147cb93a386Sopenharmony_ci    size_t getPosition() const override {
148cb93a386Sopenharmony_ci        return fStream->getPosition();
149cb93a386Sopenharmony_ci    }
150cb93a386Sopenharmony_ci
151cb93a386Sopenharmony_ciprivate:
152cb93a386Sopenharmony_ci    std::unique_ptr<SkStream> fStream;
153cb93a386Sopenharmony_ci};
154cb93a386Sopenharmony_ci
155cb93a386Sopenharmony_cistatic void releaseProc(const void* ptr, void* context) {
156cb93a386Sopenharmony_ci    delete reinterpret_cast<std::vector<uint8_t>*>(context);
157cb93a386Sopenharmony_ci}
158cb93a386Sopenharmony_ci
159cb93a386Sopenharmony_cistd::unique_ptr<SkCodec> SkHeifCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
160cb93a386Sopenharmony_ci        SkCodec::SelectionPolicy selectionPolicy, SkEncodedImageFormat format, Result* result) {
161cb93a386Sopenharmony_ci    std::unique_ptr<HeifDecoder> heifDecoder(createHeifDecoder());
162cb93a386Sopenharmony_ci    if (heifDecoder == nullptr) {
163cb93a386Sopenharmony_ci        *result = kInternalError;
164cb93a386Sopenharmony_ci        return nullptr;
165cb93a386Sopenharmony_ci    }
166cb93a386Sopenharmony_ci
167cb93a386Sopenharmony_ci    HeifFrameInfo heifInfo;
168cb93a386Sopenharmony_ci    if (!heifDecoder->init(new SkHeifStreamWrapper(stream.release()), &heifInfo)) {
169cb93a386Sopenharmony_ci        *result = kInvalidInput;
170cb93a386Sopenharmony_ci        return nullptr;
171cb93a386Sopenharmony_ci    }
172cb93a386Sopenharmony_ci
173cb93a386Sopenharmony_ci    size_t frameCount = 1;
174cb93a386Sopenharmony_ci    if (selectionPolicy == SkCodec::SelectionPolicy::kPreferAnimation) {
175cb93a386Sopenharmony_ci        HeifFrameInfo sequenceInfo;
176cb93a386Sopenharmony_ci        if (heifDecoder->getSequenceInfo(&sequenceInfo, &frameCount) &&
177cb93a386Sopenharmony_ci                frameCount > 1) {
178cb93a386Sopenharmony_ci            heifInfo = std::move(sequenceInfo);
179cb93a386Sopenharmony_ci        }
180cb93a386Sopenharmony_ci    }
181cb93a386Sopenharmony_ci
182cb93a386Sopenharmony_ci    std::unique_ptr<SkEncodedInfo::ICCProfile> profile = nullptr;
183cb93a386Sopenharmony_ci    if (heifInfo.mIccData.size() > 0) {
184cb93a386Sopenharmony_ci        auto iccData = new std::vector<uint8_t>(std::move(heifInfo.mIccData));
185cb93a386Sopenharmony_ci        auto icc = SkData::MakeWithProc(iccData->data(), iccData->size(), releaseProc, iccData);
186cb93a386Sopenharmony_ci        profile = SkEncodedInfo::ICCProfile::Make(std::move(icc));
187cb93a386Sopenharmony_ci    }
188cb93a386Sopenharmony_ci    if (profile && profile->profile()->data_color_space != skcms_Signature_RGB) {
189cb93a386Sopenharmony_ci        // This will result in sRGB.
190cb93a386Sopenharmony_ci        profile = nullptr;
191cb93a386Sopenharmony_ci    }
192cb93a386Sopenharmony_ci
193cb93a386Sopenharmony_ci    SkEncodedInfo info = SkEncodedInfo::Make(heifInfo.mWidth, heifInfo.mHeight,
194cb93a386Sopenharmony_ci            SkEncodedInfo::kYUV_Color, SkEncodedInfo::kOpaque_Alpha, 8, std::move(profile));
195cb93a386Sopenharmony_ci    SkEncodedOrigin orientation = get_orientation(heifInfo);
196cb93a386Sopenharmony_ci
197cb93a386Sopenharmony_ci    *result = kSuccess;
198cb93a386Sopenharmony_ci    return std::unique_ptr<SkCodec>(new SkHeifCodec(
199cb93a386Sopenharmony_ci            std::move(info), heifDecoder.release(), orientation, frameCount > 1, format));
200cb93a386Sopenharmony_ci}
201cb93a386Sopenharmony_ci
202cb93a386Sopenharmony_ciSkHeifCodec::SkHeifCodec(
203cb93a386Sopenharmony_ci        SkEncodedInfo&& info,
204cb93a386Sopenharmony_ci        HeifDecoder* heifDecoder,
205cb93a386Sopenharmony_ci        SkEncodedOrigin origin,
206cb93a386Sopenharmony_ci        bool useAnimation,
207cb93a386Sopenharmony_ci        SkEncodedImageFormat format)
208cb93a386Sopenharmony_ci    : INHERITED(std::move(info), skcms_PixelFormat_RGBA_8888, nullptr, origin)
209cb93a386Sopenharmony_ci    , fHeifDecoder(heifDecoder)
210cb93a386Sopenharmony_ci    , fSwizzleSrcRow(nullptr)
211cb93a386Sopenharmony_ci    , fColorXformSrcRow(nullptr)
212cb93a386Sopenharmony_ci    , fUseAnimation(useAnimation)
213cb93a386Sopenharmony_ci    , fFormat(format)
214cb93a386Sopenharmony_ci{}
215cb93a386Sopenharmony_ci
216cb93a386Sopenharmony_cibool SkHeifCodec::conversionSupported(const SkImageInfo& dstInfo, bool srcIsOpaque,
217cb93a386Sopenharmony_ci                                      bool needsColorXform) {
218cb93a386Sopenharmony_ci    SkASSERT(srcIsOpaque);
219cb93a386Sopenharmony_ci
220cb93a386Sopenharmony_ci    if (kUnknown_SkAlphaType == dstInfo.alphaType()) {
221cb93a386Sopenharmony_ci        return false;
222cb93a386Sopenharmony_ci    }
223cb93a386Sopenharmony_ci
224cb93a386Sopenharmony_ci    if (kOpaque_SkAlphaType != dstInfo.alphaType()) {
225cb93a386Sopenharmony_ci        SkCodecPrintf("Warning: an opaque image should be decoded as opaque "
226cb93a386Sopenharmony_ci                "- it is being decoded as non-opaque, which will draw slower\n");
227cb93a386Sopenharmony_ci    }
228cb93a386Sopenharmony_ci
229cb93a386Sopenharmony_ci    switch (dstInfo.colorType()) {
230cb93a386Sopenharmony_ci        case kRGBA_8888_SkColorType:
231cb93a386Sopenharmony_ci            return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888);
232cb93a386Sopenharmony_ci
233cb93a386Sopenharmony_ci        case kBGRA_8888_SkColorType:
234cb93a386Sopenharmony_ci            return fHeifDecoder->setOutputColor(kHeifColorFormat_BGRA_8888);
235cb93a386Sopenharmony_ci
236cb93a386Sopenharmony_ci        case kRGB_565_SkColorType:
237cb93a386Sopenharmony_ci            if (needsColorXform) {
238cb93a386Sopenharmony_ci                return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888);
239cb93a386Sopenharmony_ci            } else {
240cb93a386Sopenharmony_ci                return fHeifDecoder->setOutputColor(kHeifColorFormat_RGB565);
241cb93a386Sopenharmony_ci            }
242cb93a386Sopenharmony_ci
243cb93a386Sopenharmony_ci        case kRGBA_F16_SkColorType:
244cb93a386Sopenharmony_ci            SkASSERT(needsColorXform);
245cb93a386Sopenharmony_ci            return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888);
246cb93a386Sopenharmony_ci
247cb93a386Sopenharmony_ci        default:
248cb93a386Sopenharmony_ci            return false;
249cb93a386Sopenharmony_ci    }
250cb93a386Sopenharmony_ci}
251cb93a386Sopenharmony_ci
252cb93a386Sopenharmony_ciint SkHeifCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count,
253cb93a386Sopenharmony_ci                          const Options& opts) {
254cb93a386Sopenharmony_ci    // When fSwizzleSrcRow is non-null, it means that we need to swizzle.  In this case,
255cb93a386Sopenharmony_ci    // we will always decode into fSwizzlerSrcRow before swizzling into the next buffer.
256cb93a386Sopenharmony_ci    // We can never swizzle "in place" because the swizzler may perform sampling and/or
257cb93a386Sopenharmony_ci    // subsetting.
258cb93a386Sopenharmony_ci    // When fColorXformSrcRow is non-null, it means that we need to color xform and that
259cb93a386Sopenharmony_ci    // we cannot color xform "in place" (many times we can, but not when the dst is F16).
260cb93a386Sopenharmony_ci    // In this case, we will color xform from fColorXformSrcRow into the dst.
261cb93a386Sopenharmony_ci    uint8_t* decodeDst = (uint8_t*) dst;
262cb93a386Sopenharmony_ci    uint32_t* swizzleDst = (uint32_t*) dst;
263cb93a386Sopenharmony_ci    size_t decodeDstRowBytes = rowBytes;
264cb93a386Sopenharmony_ci    size_t swizzleDstRowBytes = rowBytes;
265cb93a386Sopenharmony_ci    int dstWidth = opts.fSubset ? opts.fSubset->width() : dstInfo.width();
266cb93a386Sopenharmony_ci    if (fSwizzleSrcRow && fColorXformSrcRow) {
267cb93a386Sopenharmony_ci        decodeDst = fSwizzleSrcRow;
268cb93a386Sopenharmony_ci        swizzleDst = fColorXformSrcRow;
269cb93a386Sopenharmony_ci        decodeDstRowBytes = 0;
270cb93a386Sopenharmony_ci        swizzleDstRowBytes = 0;
271cb93a386Sopenharmony_ci        dstWidth = fSwizzler->swizzleWidth();
272cb93a386Sopenharmony_ci    } else if (fColorXformSrcRow) {
273cb93a386Sopenharmony_ci        decodeDst = (uint8_t*) fColorXformSrcRow;
274cb93a386Sopenharmony_ci        swizzleDst = fColorXformSrcRow;
275cb93a386Sopenharmony_ci        decodeDstRowBytes = 0;
276cb93a386Sopenharmony_ci        swizzleDstRowBytes = 0;
277cb93a386Sopenharmony_ci    } else if (fSwizzleSrcRow) {
278cb93a386Sopenharmony_ci        decodeDst = fSwizzleSrcRow;
279cb93a386Sopenharmony_ci        decodeDstRowBytes = 0;
280cb93a386Sopenharmony_ci        dstWidth = fSwizzler->swizzleWidth();
281cb93a386Sopenharmony_ci    }
282cb93a386Sopenharmony_ci
283cb93a386Sopenharmony_ci    for (int y = 0; y < count; y++) {
284cb93a386Sopenharmony_ci        if (!fHeifDecoder->getScanline(decodeDst)) {
285cb93a386Sopenharmony_ci            return y;
286cb93a386Sopenharmony_ci        }
287cb93a386Sopenharmony_ci
288cb93a386Sopenharmony_ci        if (fSwizzler) {
289cb93a386Sopenharmony_ci            fSwizzler->swizzle(swizzleDst, decodeDst);
290cb93a386Sopenharmony_ci        }
291cb93a386Sopenharmony_ci
292cb93a386Sopenharmony_ci        if (this->colorXform()) {
293cb93a386Sopenharmony_ci            this->applyColorXform(dst, swizzleDst, dstWidth);
294cb93a386Sopenharmony_ci            dst = SkTAddOffset<void>(dst, rowBytes);
295cb93a386Sopenharmony_ci        }
296cb93a386Sopenharmony_ci
297cb93a386Sopenharmony_ci        decodeDst = SkTAddOffset<uint8_t>(decodeDst, decodeDstRowBytes);
298cb93a386Sopenharmony_ci        swizzleDst = SkTAddOffset<uint32_t>(swizzleDst, swizzleDstRowBytes);
299cb93a386Sopenharmony_ci    }
300cb93a386Sopenharmony_ci
301cb93a386Sopenharmony_ci    return count;
302cb93a386Sopenharmony_ci}
303cb93a386Sopenharmony_ci
304cb93a386Sopenharmony_ciint SkHeifCodec::onGetFrameCount() {
305cb93a386Sopenharmony_ci    if (!fUseAnimation) {
306cb93a386Sopenharmony_ci        return 1;
307cb93a386Sopenharmony_ci    }
308cb93a386Sopenharmony_ci
309cb93a386Sopenharmony_ci    if (fFrameHolder.size() == 0) {
310cb93a386Sopenharmony_ci        size_t frameCount;
311cb93a386Sopenharmony_ci        HeifFrameInfo frameInfo;
312cb93a386Sopenharmony_ci        if (!fHeifDecoder->getSequenceInfo(&frameInfo, &frameCount)
313cb93a386Sopenharmony_ci                || frameCount <= 1) {
314cb93a386Sopenharmony_ci            fUseAnimation = false;
315cb93a386Sopenharmony_ci            return 1;
316cb93a386Sopenharmony_ci        }
317cb93a386Sopenharmony_ci        fFrameHolder.reserve(frameCount);
318cb93a386Sopenharmony_ci        for (size_t i = 0; i < frameCount; i++) {
319cb93a386Sopenharmony_ci            Frame* frame = fFrameHolder.appendNewFrame();
320cb93a386Sopenharmony_ci            frame->setXYWH(0, 0, frameInfo.mWidth, frameInfo.mHeight);
321cb93a386Sopenharmony_ci            frame->setDisposalMethod(SkCodecAnimation::DisposalMethod::kKeep);
322cb93a386Sopenharmony_ci            // Currently we don't know the duration until the frame is actually
323cb93a386Sopenharmony_ci            // decoded (onGetFrameInfo is also called before frame is decoded).
324cb93a386Sopenharmony_ci            // For now, fill it base on the value reported for the sequence.
325cb93a386Sopenharmony_ci            frame->setDuration(frameInfo.mDurationUs / 1000);
326cb93a386Sopenharmony_ci            frame->setRequiredFrame(SkCodec::kNoFrame);
327cb93a386Sopenharmony_ci            frame->setHasAlpha(false);
328cb93a386Sopenharmony_ci        }
329cb93a386Sopenharmony_ci    }
330cb93a386Sopenharmony_ci
331cb93a386Sopenharmony_ci    return fFrameHolder.size();
332cb93a386Sopenharmony_ci}
333cb93a386Sopenharmony_ci
334cb93a386Sopenharmony_ciconst SkFrame* SkHeifCodec::FrameHolder::onGetFrame(int i) const {
335cb93a386Sopenharmony_ci    return static_cast<const SkFrame*>(this->frame(i));
336cb93a386Sopenharmony_ci}
337cb93a386Sopenharmony_ci
338cb93a386Sopenharmony_ciSkHeifCodec::Frame* SkHeifCodec::FrameHolder::appendNewFrame() {
339cb93a386Sopenharmony_ci    const int i = this->size();
340cb93a386Sopenharmony_ci    fFrames.emplace_back(i); // TODO: need to handle frame duration here
341cb93a386Sopenharmony_ci    return &fFrames[i];
342cb93a386Sopenharmony_ci}
343cb93a386Sopenharmony_ci
344cb93a386Sopenharmony_ciconst SkHeifCodec::Frame* SkHeifCodec::FrameHolder::frame(int i) const {
345cb93a386Sopenharmony_ci    SkASSERT(i >= 0 && i < this->size());
346cb93a386Sopenharmony_ci    return &fFrames[i];
347cb93a386Sopenharmony_ci}
348cb93a386Sopenharmony_ci
349cb93a386Sopenharmony_ciSkHeifCodec::Frame* SkHeifCodec::FrameHolder::editFrameAt(int i) {
350cb93a386Sopenharmony_ci    SkASSERT(i >= 0 && i < this->size());
351cb93a386Sopenharmony_ci    return &fFrames[i];
352cb93a386Sopenharmony_ci}
353cb93a386Sopenharmony_ci
354cb93a386Sopenharmony_cibool SkHeifCodec::onGetFrameInfo(int i, FrameInfo* frameInfo) const {
355cb93a386Sopenharmony_ci    if (i >= fFrameHolder.size()) {
356cb93a386Sopenharmony_ci        return false;
357cb93a386Sopenharmony_ci    }
358cb93a386Sopenharmony_ci
359cb93a386Sopenharmony_ci    const Frame* frame = fFrameHolder.frame(i);
360cb93a386Sopenharmony_ci    if (!frame) {
361cb93a386Sopenharmony_ci        return false;
362cb93a386Sopenharmony_ci    }
363cb93a386Sopenharmony_ci
364cb93a386Sopenharmony_ci    if (frameInfo) {
365cb93a386Sopenharmony_ci        frame->fillIn(frameInfo, true);
366cb93a386Sopenharmony_ci    }
367cb93a386Sopenharmony_ci
368cb93a386Sopenharmony_ci    return true;
369cb93a386Sopenharmony_ci}
370cb93a386Sopenharmony_ci
371cb93a386Sopenharmony_ciint SkHeifCodec::onGetRepetitionCount() {
372cb93a386Sopenharmony_ci    return kRepetitionCountInfinite;
373cb93a386Sopenharmony_ci}
374cb93a386Sopenharmony_ci
375cb93a386Sopenharmony_ci/*
376cb93a386Sopenharmony_ci * Performs the heif decode
377cb93a386Sopenharmony_ci */
378cb93a386Sopenharmony_ciSkCodec::Result SkHeifCodec::onGetPixels(const SkImageInfo& dstInfo,
379cb93a386Sopenharmony_ci                                         void* dst, size_t dstRowBytes,
380cb93a386Sopenharmony_ci                                         const Options& options,
381cb93a386Sopenharmony_ci                                         int* rowsDecoded) {
382cb93a386Sopenharmony_ci    if (options.fSubset) {
383cb93a386Sopenharmony_ci        // Not supporting subsets on this path for now.
384cb93a386Sopenharmony_ci        // TODO: if the heif has tiles, we can support subset here, but
385cb93a386Sopenharmony_ci        // need to retrieve tile config from metadata retriever first.
386cb93a386Sopenharmony_ci        return kUnimplemented;
387cb93a386Sopenharmony_ci    }
388cb93a386Sopenharmony_ci
389cb93a386Sopenharmony_ci    bool success;
390cb93a386Sopenharmony_ci    if (fUseAnimation) {
391cb93a386Sopenharmony_ci        success = fHeifDecoder->decodeSequence(options.fFrameIndex, &fFrameInfo);
392cb93a386Sopenharmony_ci        fFrameHolder.editFrameAt(options.fFrameIndex)->setDuration(
393cb93a386Sopenharmony_ci                fFrameInfo.mDurationUs / 1000);
394cb93a386Sopenharmony_ci    } else {
395cb93a386Sopenharmony_ci        fHeifDecoder->setDstBuffer((uint8_t *)dst, dstRowBytes, nullptr);
396cb93a386Sopenharmony_ci        success = fHeifDecoder->decode(&fFrameInfo);
397cb93a386Sopenharmony_ci    }
398cb93a386Sopenharmony_ci
399cb93a386Sopenharmony_ci    if (!success) {
400cb93a386Sopenharmony_ci        return kInvalidInput;
401cb93a386Sopenharmony_ci    }
402cb93a386Sopenharmony_ci
403cb93a386Sopenharmony_ci    fSwizzler.reset(nullptr);
404cb93a386Sopenharmony_ci    this->allocateStorage(dstInfo);
405cb93a386Sopenharmony_ci
406cb93a386Sopenharmony_ci    int rows = this->readRows(dstInfo, dst, dstRowBytes, dstInfo.height(), options);
407cb93a386Sopenharmony_ci    if (rows < dstInfo.height()) {
408cb93a386Sopenharmony_ci        *rowsDecoded = rows;
409cb93a386Sopenharmony_ci        return kIncompleteInput;
410cb93a386Sopenharmony_ci    }
411cb93a386Sopenharmony_ci
412cb93a386Sopenharmony_ci    return kSuccess;
413cb93a386Sopenharmony_ci}
414cb93a386Sopenharmony_ci
415cb93a386Sopenharmony_civoid SkHeifCodec::allocateStorage(const SkImageInfo& dstInfo) {
416cb93a386Sopenharmony_ci    int dstWidth = dstInfo.width();
417cb93a386Sopenharmony_ci
418cb93a386Sopenharmony_ci    size_t swizzleBytes = 0;
419cb93a386Sopenharmony_ci    if (fSwizzler) {
420cb93a386Sopenharmony_ci        swizzleBytes = fFrameInfo.mBytesPerPixel * fFrameInfo.mWidth;
421cb93a386Sopenharmony_ci        dstWidth = fSwizzler->swizzleWidth();
422cb93a386Sopenharmony_ci        SkASSERT(!this->colorXform() || SkIsAlign4(swizzleBytes));
423cb93a386Sopenharmony_ci    }
424cb93a386Sopenharmony_ci
425cb93a386Sopenharmony_ci    size_t xformBytes = 0;
426cb93a386Sopenharmony_ci    if (this->colorXform() && (kRGBA_F16_SkColorType == dstInfo.colorType() ||
427cb93a386Sopenharmony_ci                               kRGB_565_SkColorType == dstInfo.colorType())) {
428cb93a386Sopenharmony_ci        xformBytes = dstWidth * sizeof(uint32_t);
429cb93a386Sopenharmony_ci    }
430cb93a386Sopenharmony_ci
431cb93a386Sopenharmony_ci    size_t totalBytes = swizzleBytes + xformBytes;
432cb93a386Sopenharmony_ci    fStorage.reset(totalBytes);
433cb93a386Sopenharmony_ci    if (totalBytes > 0) {
434cb93a386Sopenharmony_ci        fSwizzleSrcRow = (swizzleBytes > 0) ? fStorage.get() : nullptr;
435cb93a386Sopenharmony_ci        fColorXformSrcRow = (xformBytes > 0) ?
436cb93a386Sopenharmony_ci                SkTAddOffset<uint32_t>(fStorage.get(), swizzleBytes) : nullptr;
437cb93a386Sopenharmony_ci    }
438cb93a386Sopenharmony_ci}
439cb93a386Sopenharmony_ci
440cb93a386Sopenharmony_civoid SkHeifCodec::initializeSwizzler(
441cb93a386Sopenharmony_ci        const SkImageInfo& dstInfo, const Options& options) {
442cb93a386Sopenharmony_ci    SkImageInfo swizzlerDstInfo = dstInfo;
443cb93a386Sopenharmony_ci    if (this->colorXform()) {
444cb93a386Sopenharmony_ci        // The color xform will be expecting RGBA 8888 input.
445cb93a386Sopenharmony_ci        swizzlerDstInfo = swizzlerDstInfo.makeColorType(kRGBA_8888_SkColorType);
446cb93a386Sopenharmony_ci    }
447cb93a386Sopenharmony_ci
448cb93a386Sopenharmony_ci    int srcBPP = 4;
449cb93a386Sopenharmony_ci    if (dstInfo.colorType() == kRGB_565_SkColorType && !this->colorXform()) {
450cb93a386Sopenharmony_ci        srcBPP = 2;
451cb93a386Sopenharmony_ci    }
452cb93a386Sopenharmony_ci
453cb93a386Sopenharmony_ci    fSwizzler = SkSwizzler::MakeSimple(srcBPP, swizzlerDstInfo, options);
454cb93a386Sopenharmony_ci    SkASSERT(fSwizzler);
455cb93a386Sopenharmony_ci}
456cb93a386Sopenharmony_ci
457cb93a386Sopenharmony_ciSkSampler* SkHeifCodec::getSampler(bool createIfNecessary) {
458cb93a386Sopenharmony_ci    if (!createIfNecessary || fSwizzler) {
459cb93a386Sopenharmony_ci        SkASSERT(!fSwizzler || (fSwizzleSrcRow && fStorage.get() == fSwizzleSrcRow));
460cb93a386Sopenharmony_ci        return fSwizzler.get();
461cb93a386Sopenharmony_ci    }
462cb93a386Sopenharmony_ci
463cb93a386Sopenharmony_ci    this->initializeSwizzler(this->dstInfo(), this->options());
464cb93a386Sopenharmony_ci    this->allocateStorage(this->dstInfo());
465cb93a386Sopenharmony_ci    return fSwizzler.get();
466cb93a386Sopenharmony_ci}
467cb93a386Sopenharmony_ci
468cb93a386Sopenharmony_cibool SkHeifCodec::onRewind() {
469cb93a386Sopenharmony_ci    fSwizzler.reset(nullptr);
470cb93a386Sopenharmony_ci    fSwizzleSrcRow = nullptr;
471cb93a386Sopenharmony_ci    fColorXformSrcRow = nullptr;
472cb93a386Sopenharmony_ci    fStorage.reset();
473cb93a386Sopenharmony_ci
474cb93a386Sopenharmony_ci    return true;
475cb93a386Sopenharmony_ci}
476cb93a386Sopenharmony_ci
477cb93a386Sopenharmony_ciSkCodec::Result SkHeifCodec::onStartScanlineDecode(
478cb93a386Sopenharmony_ci        const SkImageInfo& dstInfo, const Options& options) {
479cb93a386Sopenharmony_ci    // TODO: For now, just decode the whole thing even when there is a subset.
480cb93a386Sopenharmony_ci    // If the heif image has tiles, we could potentially do this much faster,
481cb93a386Sopenharmony_ci    // but the tile configuration needs to be retrieved from the metadata.
482cb93a386Sopenharmony_ci    if (!fHeifDecoder->decode(&fFrameInfo)) {
483cb93a386Sopenharmony_ci        return kInvalidInput;
484cb93a386Sopenharmony_ci    }
485cb93a386Sopenharmony_ci
486cb93a386Sopenharmony_ci    if (options.fSubset) {
487cb93a386Sopenharmony_ci        this->initializeSwizzler(dstInfo, options);
488cb93a386Sopenharmony_ci    } else {
489cb93a386Sopenharmony_ci        fSwizzler.reset(nullptr);
490cb93a386Sopenharmony_ci    }
491cb93a386Sopenharmony_ci
492cb93a386Sopenharmony_ci    this->allocateStorage(dstInfo);
493cb93a386Sopenharmony_ci
494cb93a386Sopenharmony_ci    return kSuccess;
495cb93a386Sopenharmony_ci}
496cb93a386Sopenharmony_ci
497cb93a386Sopenharmony_ciint SkHeifCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) {
498cb93a386Sopenharmony_ci    return this->readRows(this->dstInfo(), dst, dstRowBytes, count, this->options());
499cb93a386Sopenharmony_ci}
500cb93a386Sopenharmony_ci
501cb93a386Sopenharmony_cibool SkHeifCodec::onSkipScanlines(int count) {
502cb93a386Sopenharmony_ci    return count == (int) fHeifDecoder->skipScanlines(count);
503cb93a386Sopenharmony_ci}
504cb93a386Sopenharmony_ci
505cb93a386Sopenharmony_civoid *SkHeifCodec::heifImplHandle = nullptr;
506cb93a386Sopenharmony_ciHeifDecoder* SkHeifCodec::createHeifDecoder() {
507cb93a386Sopenharmony_ci#if !defined(WIN32) && !defined(_WIN32) && !defined(__WIN32__)
508cb93a386Sopenharmony_ci    if (!heifImplHandle) {
509cb93a386Sopenharmony_ci        heifImplHandle = dlopen(HEIF_IMPL_SO_NAME, RTLD_LAZY);
510cb93a386Sopenharmony_ci    }
511cb93a386Sopenharmony_ci    if (!heifImplHandle) {
512cb93a386Sopenharmony_ci        return new StubHeifDecoder();
513cb93a386Sopenharmony_ci    }
514cb93a386Sopenharmony_ci    typedef HeifDecoder* (*CreateHeifDecoderImplT)();
515cb93a386Sopenharmony_ci    HeifDecoder* decoder = nullptr;
516cb93a386Sopenharmony_ci    CreateHeifDecoderImplT func = (CreateHeifDecoderImplT)dlsym(heifImplHandle, "CreateHeifDecoderImpl");
517cb93a386Sopenharmony_ci    if (func) {
518cb93a386Sopenharmony_ci        decoder = func();
519cb93a386Sopenharmony_ci    }
520cb93a386Sopenharmony_ci    return decoder != nullptr ? decoder : new StubHeifDecoder();
521cb93a386Sopenharmony_ci#else
522cb93a386Sopenharmony_ci    return new StubHeifDecoder();
523cb93a386Sopenharmony_ci#endif
524cb93a386Sopenharmony_ci}
525cb93a386Sopenharmony_ci
526cb93a386Sopenharmony_ci#endif // SK_HAS_HEIF_LIBRARY
527