blob: 2813c0e441695567f574890cc90916b4e25da08a [file] [log] [blame]
Leon Scroggins III04be2b52017-08-17 15:13:20 -04001/*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkTypes.h"
Leon Scroggins III04be2b52017-08-17 15:13:20 -04009
10#ifdef SK_HAS_HEIF_LIBRARY
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/codec/SkCodec.h"
12#include "include/core/SkStream.h"
13#include "include/private/SkColorData.h"
14#include "src/codec/SkCodecPriv.h"
15#include "src/codec/SkHeifCodec.h"
16#include "src/core/SkEndian.h"
Leon Scroggins III04be2b52017-08-17 15:13:20 -040017
18#define FOURCC(c1, c2, c3, c4) \
19 ((c1) << 24 | (c2) << 16 | (c3) << 8 | (c4))
20
Vignesh Venkatasubramanian28eb5922020-11-02 14:07:01 -080021std::optional<SkEncodedImageFormat> SkHeifCodec::IsSupported(const void* buffer, size_t bytesRead) {
22 // Parse the ftyp box up to bytesRead to determine if this is HEIF or AVIF.
Leon Scroggins III04be2b52017-08-17 15:13:20 -040023 // Any valid ftyp box should have at least 8 bytes.
24 if (bytesRead < 8) {
Vignesh Venkatasubramanian28eb5922020-11-02 14:07:01 -080025 return std::nullopt;
Leon Scroggins III04be2b52017-08-17 15:13:20 -040026 }
27
28 uint32_t* ptr = (uint32_t*)buffer;
29 uint64_t chunkSize = SkEndian_SwapBE32(ptr[0]);
30 uint32_t chunkType = SkEndian_SwapBE32(ptr[1]);
31
32 if (chunkType != FOURCC('f', 't', 'y', 'p')) {
Vignesh Venkatasubramanian28eb5922020-11-02 14:07:01 -080033 return std::nullopt;
Leon Scroggins III04be2b52017-08-17 15:13:20 -040034 }
35
Mike Klein329d5042017-10-20 13:48:55 -040036 int64_t offset = 8;
Leon Scroggins III04be2b52017-08-17 15:13:20 -040037 if (chunkSize == 1) {
38 // This indicates that the next 8 bytes represent the chunk size,
39 // and chunk data comes after that.
40 if (bytesRead < 16) {
Vignesh Venkatasubramanian28eb5922020-11-02 14:07:01 -080041 return std::nullopt;
Leon Scroggins III04be2b52017-08-17 15:13:20 -040042 }
43 auto* chunkSizePtr = SkTAddOffset<const uint64_t>(buffer, offset);
44 chunkSize = SkEndian_SwapBE64(*chunkSizePtr);
45 if (chunkSize < 16) {
46 // The smallest valid chunk is 16 bytes long in this case.
Vignesh Venkatasubramanian28eb5922020-11-02 14:07:01 -080047 return std::nullopt;
Leon Scroggins III04be2b52017-08-17 15:13:20 -040048 }
49 offset += 8;
50 } else if (chunkSize < 8) {
51 // The smallest valid chunk is 8 bytes long.
Vignesh Venkatasubramanian28eb5922020-11-02 14:07:01 -080052 return std::nullopt;
Leon Scroggins III04be2b52017-08-17 15:13:20 -040053 }
54
55 if (chunkSize > bytesRead) {
56 chunkSize = bytesRead;
57 }
Mike Klein329d5042017-10-20 13:48:55 -040058 int64_t chunkDataSize = chunkSize - offset;
Leon Scroggins III04be2b52017-08-17 15:13:20 -040059 // It should at least have major brand (4-byte) and minor version (4-bytes).
60 // The rest of the chunk (if any) is a list of (4-byte) compatible brands.
61 if (chunkDataSize < 8) {
Vignesh Venkatasubramanian28eb5922020-11-02 14:07:01 -080062 return std::nullopt;
Leon Scroggins III04be2b52017-08-17 15:13:20 -040063 }
64
65 uint32_t numCompatibleBrands = (chunkDataSize - 8) / 4;
Vignesh Venkatasubramanian28eb5922020-11-02 14:07:01 -080066 bool isHeif = false;
Leon Scroggins III04be2b52017-08-17 15:13:20 -040067 for (size_t i = 0; i < numCompatibleBrands + 2; ++i) {
68 if (i == 1) {
69 // Skip this index, it refers to the minorVersion,
70 // not a brand.
71 continue;
72 }
73 auto* brandPtr = SkTAddOffset<const uint32_t>(buffer, offset + 4 * i);
74 uint32_t brand = SkEndian_SwapBE32(*brandPtr);
Chong Zhang3c235932017-10-03 13:16:06 -070075 if (brand == FOURCC('m', 'i', 'f', '1') || brand == FOURCC('h', 'e', 'i', 'c')
Vignesh Venkatasubramanian28eb5922020-11-02 14:07:01 -080076 || brand == FOURCC('m', 's', 'f', '1') || brand == FOURCC('h', 'e', 'v', 'c')
77 || brand == FOURCC('a', 'v', 'i', 'f') || brand == FOURCC('a', 'v', 'i', 's')) {
78 // AVIF files could have "mif1" as the major brand. So we cannot
79 // distinguish whether the image is AVIF or HEIC just based on the
80 // "mif1" brand. So wait until we see a specific avif brand to
81 // determine whether it is AVIF or HEIC.
82 isHeif = true;
83 if (brand == FOURCC('a', 'v', 'i', 'f')
84 || brand == FOURCC('a', 'v', 'i', 's')) {
85 return SkEncodedImageFormat::kAVIF;
86 }
Leon Scroggins III04be2b52017-08-17 15:13:20 -040087 }
88 }
Vignesh Venkatasubramanian28eb5922020-11-02 14:07:01 -080089 if (isHeif) {
90 return SkEncodedImageFormat::kHEIF;
91 }
92 return std::nullopt;
Leon Scroggins III04be2b52017-08-17 15:13:20 -040093}
94
Mike Klein32a0a632017-10-19 08:33:12 -040095static SkEncodedOrigin get_orientation(const HeifFrameInfo& frameInfo) {
Leon Scroggins III04be2b52017-08-17 15:13:20 -040096 switch (frameInfo.mRotationAngle) {
Mike Klein32a0a632017-10-19 08:33:12 -040097 case 0: return kTopLeft_SkEncodedOrigin;
98 case 90: return kRightTop_SkEncodedOrigin;
99 case 180: return kBottomRight_SkEncodedOrigin;
100 case 270: return kLeftBottom_SkEncodedOrigin;
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400101 }
Mike Klein32a0a632017-10-19 08:33:12 -0400102 return kDefault_SkEncodedOrigin;
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400103}
104
105struct SkHeifStreamWrapper : public HeifStream {
106 SkHeifStreamWrapper(SkStream* stream) : fStream(stream) {}
107
108 ~SkHeifStreamWrapper() override {}
109
110 size_t read(void* buffer, size_t size) override {
111 return fStream->read(buffer, size);
112 }
113
114 bool rewind() override {
115 return fStream->rewind();
116 }
117
118 bool seek(size_t position) override {
119 return fStream->seek(position);
120 }
121
122 bool hasLength() const override {
123 return fStream->hasLength();
124 }
125
126 size_t getLength() const override {
127 return fStream->getLength();
128 }
129
130private:
131 std::unique_ptr<SkStream> fStream;
132};
133
Leon Scroggins III6154ac42019-08-14 11:29:29 -0400134static void releaseProc(const void* ptr, void* context) {
135 delete reinterpret_cast<std::vector<uint8_t>*>(context);
136}
Leon Scroggins III6154ac42019-08-14 11:29:29 -0400137
138std::unique_ptr<SkCodec> SkHeifCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
Vignesh Venkatasubramanian28eb5922020-11-02 14:07:01 -0800139 SkCodec::SelectionPolicy selectionPolicy, SkEncodedImageFormat format, Result* result) {
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400140 std::unique_ptr<HeifDecoder> heifDecoder(createHeifDecoder());
John Stilesa008b0f2020-08-16 08:48:02 -0400141 if (heifDecoder == nullptr) {
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400142 *result = kInternalError;
143 return nullptr;
144 }
145
Leon Scroggins III6154ac42019-08-14 11:29:29 -0400146 HeifFrameInfo heifInfo;
147 if (!heifDecoder->init(new SkHeifStreamWrapper(stream.release()), &heifInfo)) {
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400148 *result = kInvalidInput;
149 return nullptr;
150 }
151
Leon Scroggins III6154ac42019-08-14 11:29:29 -0400152 size_t frameCount = 1;
153 if (selectionPolicy == SkCodec::SelectionPolicy::kPreferAnimation) {
154 HeifFrameInfo sequenceInfo;
155 if (heifDecoder->getSequenceInfo(&sequenceInfo, &frameCount) &&
156 frameCount > 1) {
157 heifInfo = std::move(sequenceInfo);
158 }
159 }
Leon Scroggins III6154ac42019-08-14 11:29:29 -0400160
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400161 std::unique_ptr<SkEncodedInfo::ICCProfile> profile = nullptr;
Leon Scroggins III6154ac42019-08-14 11:29:29 -0400162 if (heifInfo.mIccData.size() > 0) {
163 auto iccData = new std::vector<uint8_t>(std::move(heifInfo.mIccData));
164 auto icc = SkData::MakeWithProc(iccData->data(), iccData->size(), releaseProc, iccData);
165 profile = SkEncodedInfo::ICCProfile::Make(std::move(icc));
166 }
Leon Scroggins III5dd47e42018-09-27 15:26:48 -0400167 if (profile && profile->profile()->data_color_space != skcms_Signature_RGB) {
168 // This will result in sRGB.
169 profile = nullptr;
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400170 }
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400171
Leon Scroggins III6154ac42019-08-14 11:29:29 -0400172 SkEncodedInfo info = SkEncodedInfo::Make(heifInfo.mWidth, heifInfo.mHeight,
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400173 SkEncodedInfo::kYUV_Color, SkEncodedInfo::kOpaque_Alpha, 8, std::move(profile));
Leon Scroggins III6154ac42019-08-14 11:29:29 -0400174 SkEncodedOrigin orientation = get_orientation(heifInfo);
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400175
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400176 *result = kSuccess;
Leon Scroggins III6154ac42019-08-14 11:29:29 -0400177 return std::unique_ptr<SkCodec>(new SkHeifCodec(
Vignesh Venkatasubramanian28eb5922020-11-02 14:07:01 -0800178 std::move(info), heifDecoder.release(), orientation, frameCount > 1, format));
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400179}
180
Leon Scroggins III6154ac42019-08-14 11:29:29 -0400181SkHeifCodec::SkHeifCodec(
182 SkEncodedInfo&& info,
183 HeifDecoder* heifDecoder,
Leon Scroggins III2b39cbe2019-08-22 11:35:18 -0400184 SkEncodedOrigin origin,
Vignesh Venkatasubramanian28eb5922020-11-02 14:07:01 -0800185 bool useAnimation,
186 SkEncodedImageFormat format)
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400187 : INHERITED(std::move(info), skcms_PixelFormat_RGBA_8888, nullptr, origin)
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400188 , fHeifDecoder(heifDecoder)
189 , fSwizzleSrcRow(nullptr)
190 , fColorXformSrcRow(nullptr)
Leon Scroggins III6154ac42019-08-14 11:29:29 -0400191 , fUseAnimation(useAnimation)
Vignesh Venkatasubramanian28eb5922020-11-02 14:07:01 -0800192 , fFormat(format)
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400193{}
194
Leon Scroggins III712476e2018-10-03 15:47:00 -0400195bool SkHeifCodec::conversionSupported(const SkImageInfo& dstInfo, bool srcIsOpaque,
196 bool needsColorXform) {
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400197 SkASSERT(srcIsOpaque);
198
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400199 if (kUnknown_SkAlphaType == dstInfo.alphaType()) {
200 return false;
201 }
202
203 if (kOpaque_SkAlphaType != dstInfo.alphaType()) {
204 SkCodecPrintf("Warning: an opaque image should be decoded as opaque "
205 "- it is being decoded as non-opaque, which will draw slower\n");
206 }
207
208 switch (dstInfo.colorType()) {
209 case kRGBA_8888_SkColorType:
210 return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888);
211
212 case kBGRA_8888_SkColorType:
213 return fHeifDecoder->setOutputColor(kHeifColorFormat_BGRA_8888);
214
215 case kRGB_565_SkColorType:
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400216 if (needsColorXform) {
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400217 return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888);
218 } else {
219 return fHeifDecoder->setOutputColor(kHeifColorFormat_RGB565);
220 }
221
222 case kRGBA_F16_SkColorType:
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400223 SkASSERT(needsColorXform);
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400224 return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888);
225
226 default:
227 return false;
228 }
229}
230
231int SkHeifCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count,
232 const Options& opts) {
233 // When fSwizzleSrcRow is non-null, it means that we need to swizzle. In this case,
234 // we will always decode into fSwizzlerSrcRow before swizzling into the next buffer.
235 // We can never swizzle "in place" because the swizzler may perform sampling and/or
236 // subsetting.
237 // When fColorXformSrcRow is non-null, it means that we need to color xform and that
238 // we cannot color xform "in place" (many times we can, but not when the dst is F16).
239 // In this case, we will color xform from fColorXformSrcRow into the dst.
240 uint8_t* decodeDst = (uint8_t*) dst;
241 uint32_t* swizzleDst = (uint32_t*) dst;
242 size_t decodeDstRowBytes = rowBytes;
243 size_t swizzleDstRowBytes = rowBytes;
244 int dstWidth = opts.fSubset ? opts.fSubset->width() : dstInfo.width();
245 if (fSwizzleSrcRow && fColorXformSrcRow) {
246 decodeDst = fSwizzleSrcRow;
247 swizzleDst = fColorXformSrcRow;
248 decodeDstRowBytes = 0;
249 swizzleDstRowBytes = 0;
250 dstWidth = fSwizzler->swizzleWidth();
251 } else if (fColorXformSrcRow) {
252 decodeDst = (uint8_t*) fColorXformSrcRow;
253 swizzleDst = fColorXformSrcRow;
254 decodeDstRowBytes = 0;
255 swizzleDstRowBytes = 0;
256 } else if (fSwizzleSrcRow) {
257 decodeDst = fSwizzleSrcRow;
258 decodeDstRowBytes = 0;
259 dstWidth = fSwizzler->swizzleWidth();
260 }
261
262 for (int y = 0; y < count; y++) {
263 if (!fHeifDecoder->getScanline(decodeDst)) {
264 return y;
265 }
266
267 if (fSwizzler) {
268 fSwizzler->swizzle(swizzleDst, decodeDst);
269 }
270
271 if (this->colorXform()) {
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400272 this->applyColorXform(dst, swizzleDst, dstWidth);
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400273 dst = SkTAddOffset<void>(dst, rowBytes);
274 }
275
276 decodeDst = SkTAddOffset<uint8_t>(decodeDst, decodeDstRowBytes);
277 swizzleDst = SkTAddOffset<uint32_t>(swizzleDst, swizzleDstRowBytes);
278 }
279
280 return count;
281}
282
Leon Scroggins III6154ac42019-08-14 11:29:29 -0400283int SkHeifCodec::onGetFrameCount() {
284 if (!fUseAnimation) {
285 return 1;
286 }
287
288 if (fFrameHolder.size() == 0) {
289 size_t frameCount;
290 HeifFrameInfo frameInfo;
291 if (!fHeifDecoder->getSequenceInfo(&frameInfo, &frameCount)
292 || frameCount <= 1) {
293 fUseAnimation = false;
294 return 1;
295 }
296 fFrameHolder.reserve(frameCount);
297 for (size_t i = 0; i < frameCount; i++) {
298 Frame* frame = fFrameHolder.appendNewFrame();
299 frame->setXYWH(0, 0, frameInfo.mWidth, frameInfo.mHeight);
300 frame->setDisposalMethod(SkCodecAnimation::DisposalMethod::kKeep);
Leon Scroggins III6154ac42019-08-14 11:29:29 -0400301 // Currently we don't know the duration until the frame is actually
302 // decoded (onGetFrameInfo is also called before frame is decoded).
303 // For now, fill it base on the value reported for the sequence.
304 frame->setDuration(frameInfo.mDurationUs / 1000);
305 frame->setRequiredFrame(SkCodec::kNoFrame);
306 frame->setHasAlpha(false);
307 }
308 }
309
310 return fFrameHolder.size();
311}
312
313const SkFrame* SkHeifCodec::FrameHolder::onGetFrame(int i) const {
314 return static_cast<const SkFrame*>(this->frame(i));
315}
316
317SkHeifCodec::Frame* SkHeifCodec::FrameHolder::appendNewFrame() {
318 const int i = this->size();
319 fFrames.emplace_back(i); // TODO: need to handle frame duration here
320 return &fFrames[i];
321}
322
323const SkHeifCodec::Frame* SkHeifCodec::FrameHolder::frame(int i) const {
324 SkASSERT(i >= 0 && i < this->size());
325 return &fFrames[i];
326}
327
Chong Zhangea68eac2019-08-26 11:28:38 -0700328SkHeifCodec::Frame* SkHeifCodec::FrameHolder::editFrameAt(int i) {
329 SkASSERT(i >= 0 && i < this->size());
330 return &fFrames[i];
331}
332
Leon Scroggins III6154ac42019-08-14 11:29:29 -0400333bool SkHeifCodec::onGetFrameInfo(int i, FrameInfo* frameInfo) const {
334 if (i >= fFrameHolder.size()) {
335 return false;
336 }
337
338 const Frame* frame = fFrameHolder.frame(i);
339 if (!frame) {
340 return false;
341 }
342
343 if (frameInfo) {
344 frameInfo->fRequiredFrame = SkCodec::kNoFrame;
345 frameInfo->fDuration = frame->getDuration();
346 frameInfo->fFullyReceived = true;
347 frameInfo->fAlphaType = kOpaque_SkAlphaType;
348 frameInfo->fDisposalMethod = SkCodecAnimation::DisposalMethod::kKeep;
349 }
350
351 return true;
352}
353
354int SkHeifCodec::onGetRepetitionCount() {
355 return kRepetitionCountInfinite;
356}
Leon Scroggins III6154ac42019-08-14 11:29:29 -0400357
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400358/*
359 * Performs the heif decode
360 */
361SkCodec::Result SkHeifCodec::onGetPixels(const SkImageInfo& dstInfo,
362 void* dst, size_t dstRowBytes,
363 const Options& options,
364 int* rowsDecoded) {
365 if (options.fSubset) {
366 // Not supporting subsets on this path for now.
367 // TODO: if the heif has tiles, we can support subset here, but
368 // need to retrieve tile config from metadata retriever first.
369 return kUnimplemented;
370 }
371
Leon Scroggins III6154ac42019-08-14 11:29:29 -0400372 bool success;
373 if (fUseAnimation) {
374 success = fHeifDecoder->decodeSequence(options.fFrameIndex, &fFrameInfo);
Chong Zhangea68eac2019-08-26 11:28:38 -0700375 fFrameHolder.editFrameAt(options.fFrameIndex)->setDuration(
376 fFrameInfo.mDurationUs / 1000);
Leon Scroggins III6154ac42019-08-14 11:29:29 -0400377 } else {
378 success = fHeifDecoder->decode(&fFrameInfo);
379 }
380
381 if (!success) {
382 return kInvalidInput;
383 }
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400384
Chong Zhang722b3a72017-08-23 11:17:36 -0700385 fSwizzler.reset(nullptr);
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400386 this->allocateStorage(dstInfo);
387
388 int rows = this->readRows(dstInfo, dst, dstRowBytes, dstInfo.height(), options);
389 if (rows < dstInfo.height()) {
390 *rowsDecoded = rows;
391 return kIncompleteInput;
392 }
393
394 return kSuccess;
395}
396
397void SkHeifCodec::allocateStorage(const SkImageInfo& dstInfo) {
398 int dstWidth = dstInfo.width();
399
400 size_t swizzleBytes = 0;
401 if (fSwizzler) {
402 swizzleBytes = fFrameInfo.mBytesPerPixel * fFrameInfo.mWidth;
403 dstWidth = fSwizzler->swizzleWidth();
404 SkASSERT(!this->colorXform() || SkIsAlign4(swizzleBytes));
405 }
406
407 size_t xformBytes = 0;
408 if (this->colorXform() && (kRGBA_F16_SkColorType == dstInfo.colorType() ||
409 kRGB_565_SkColorType == dstInfo.colorType())) {
410 xformBytes = dstWidth * sizeof(uint32_t);
411 }
412
413 size_t totalBytes = swizzleBytes + xformBytes;
414 fStorage.reset(totalBytes);
415 if (totalBytes > 0) {
416 fSwizzleSrcRow = (swizzleBytes > 0) ? fStorage.get() : nullptr;
417 fColorXformSrcRow = (xformBytes > 0) ?
418 SkTAddOffset<uint32_t>(fStorage.get(), swizzleBytes) : nullptr;
419 }
420}
421
422void SkHeifCodec::initializeSwizzler(
423 const SkImageInfo& dstInfo, const Options& options) {
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400424 SkImageInfo swizzlerDstInfo = dstInfo;
425 if (this->colorXform()) {
426 // The color xform will be expecting RGBA 8888 input.
427 swizzlerDstInfo = swizzlerDstInfo.makeColorType(kRGBA_8888_SkColorType);
428 }
429
Leon Scroggins III65f4aea2018-10-24 12:17:22 -0400430 int srcBPP = 4;
431 if (dstInfo.colorType() == kRGB_565_SkColorType && !this->colorXform()) {
432 srcBPP = 2;
433 }
434
435 fSwizzler = SkSwizzler::MakeSimple(srcBPP, swizzlerDstInfo, options);
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400436 SkASSERT(fSwizzler);
437}
438
439SkSampler* SkHeifCodec::getSampler(bool createIfNecessary) {
440 if (!createIfNecessary || fSwizzler) {
441 SkASSERT(!fSwizzler || (fSwizzleSrcRow && fStorage.get() == fSwizzleSrcRow));
442 return fSwizzler.get();
443 }
444
445 this->initializeSwizzler(this->dstInfo(), this->options());
446 this->allocateStorage(this->dstInfo());
447 return fSwizzler.get();
448}
449
Leon Scroggins IIIbcc75322019-04-15 10:34:53 -0400450bool SkHeifCodec::onRewind() {
451 fSwizzler.reset(nullptr);
452 fSwizzleSrcRow = nullptr;
453 fColorXformSrcRow = nullptr;
454 fStorage.reset();
455
456 return true;
457}
458
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400459SkCodec::Result SkHeifCodec::onStartScanlineDecode(
460 const SkImageInfo& dstInfo, const Options& options) {
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400461 // TODO: For now, just decode the whole thing even when there is a subset.
462 // If the heif image has tiles, we could potentially do this much faster,
463 // but the tile configuration needs to be retrieved from the metadata.
464 if (!fHeifDecoder->decode(&fFrameInfo)) {
465 return kInvalidInput;
466 }
467
Chong Zhang722b3a72017-08-23 11:17:36 -0700468 if (options.fSubset) {
469 this->initializeSwizzler(dstInfo, options);
470 } else {
471 fSwizzler.reset(nullptr);
472 }
473
Leon Scroggins III04be2b52017-08-17 15:13:20 -0400474 this->allocateStorage(dstInfo);
475
476 return kSuccess;
477}
478
479int SkHeifCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) {
480 return this->readRows(this->dstInfo(), dst, dstRowBytes, count, this->options());
481}
482
483bool SkHeifCodec::onSkipScanlines(int count) {
484 return count == (int) fHeifDecoder->skipScanlines(count);
485}
486
487#endif // SK_HAS_HEIF_LIBRARY